1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkDataTable.h" 9 #include "SkDWrite.h" 10 #include "SkDWriteFontFileStream.h" 11 #include "SkHRESULT.h" 12 #include "SkRemotableFontMgr.h" 13 #include "SkStream.h" 14 #include "SkString.h" 15 #include "SkTArray.h" 16 #include "SkThread.h" 17 #include "SkTScopedComPtr.h" 18 #include "SkTypeface_win.h" 19 #include "SkTypes.h" 20 #include "SkUtils.h" 21 22 #include <dwrite.h> 23 24 struct DWriteStyle { 25 explicit DWriteStyle(const SkFontStyle& pattern) { 26 switch (pattern.slant()) { 27 case SkFontStyle::kUpright_Slant: 28 fSlant = DWRITE_FONT_STYLE_NORMAL; 29 break; 30 case SkFontStyle::kItalic_Slant: 31 fSlant = DWRITE_FONT_STYLE_ITALIC; 32 break; 33 default: 34 SkASSERT(false); 35 } 36 37 fWeight = (DWRITE_FONT_WEIGHT)pattern.weight(); 38 fWidth = (DWRITE_FONT_STRETCH)pattern.width(); 39 } 40 DWRITE_FONT_STYLE fSlant; 41 DWRITE_FONT_WEIGHT fWeight; 42 DWRITE_FONT_STRETCH fWidth; 43 }; 44 45 class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr { 46 private: 47 struct DataId { 48 IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity. 49 void* fKey; 50 UINT32 fKeySize; 51 52 DataId() { } 53 54 // This is actually a move!!! 55 explicit DataId(DataId& that) 56 : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize) 57 { 58 that.fLoader = NULL; 59 that.fKey = NULL; 60 SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;) 61 } 62 63 ~DataId() { 64 if (fLoader) { 65 fLoader->Release(); 66 } 67 sk_free(fKey); 68 } 69 }; 70 71 mutable SkTArray<DataId> fDataIdCache; 72 mutable SkMutex fDataIdCacheMutex; 73 74 int FindOrAdd(IDWriteFontFileLoader* fontFileLoader, 75 const void* refKey, UINT32 refKeySize) const 76 { 77 SkTScopedComPtr<IUnknown> fontFileLoaderId; 78 HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId), 79 "Failed to re-convert to IDWriteFontFileLoader.", 80 SkFontIdentity::kInvalidDataId); 81 82 SkAutoMutexAcquire ama(fDataIdCacheMutex); 83 int count = fDataIdCache.count(); 84 int i; 85 for (i = 0; i < count; ++i) { 86 const DataId& current = fDataIdCache[i]; 87 if (fontFileLoaderId.get() == current.fLoader && 88 refKeySize == current.fKeySize && 89 0 == memcmp(refKey, current.fKey, refKeySize)) 90 { 91 return i; 92 } 93 } 94 DataId& added = fDataIdCache.push_back(); 95 added.fLoader = fontFileLoaderId.release(); // Ref is passed. 96 added.fKey = sk_malloc_throw(refKeySize); 97 memcpy(added.fKey, refKey, refKeySize); 98 added.fKeySize = refKeySize; 99 100 return i; 101 } 102 103 public: 104 SK_DECLARE_INST_COUNT(SkRemotableFontMgr_DirectWrite) 105 106 /** localeNameLength must include the null terminator. */ 107 SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection, 108 WCHAR* localeName, int localeNameLength) 109 : fFontCollection(SkRefComPtr(fontCollection)) 110 , fLocaleName(localeNameLength) 111 { 112 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR)); 113 } 114 115 virtual SkDataTable* getFamilyNames() const SK_OVERRIDE { 116 int count = fFontCollection->GetFontFamilyCount(); 117 118 SkDataTableBuilder names(1024); 119 for (int index = 0; index < count; ++index) { 120 SkTScopedComPtr<IDWriteFontFamily> fontFamily; 121 HRNM(fFontCollection->GetFontFamily(index, &fontFamily), 122 "Could not get requested family."); 123 124 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; 125 HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); 126 127 SkString familyName; 128 sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName); 129 130 names.appendString(familyName); 131 } 132 return names.detachDataTable(); 133 } 134 135 HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const { 136 SkTScopedComPtr<IDWriteFontFace> fontFace; 137 HRM(font->CreateFontFace(&fontFace), "Could not create font face."); 138 139 UINT32 numFiles; 140 HR(fontFace->GetFiles(&numFiles, NULL)); 141 if (numFiles > 1) { 142 return E_FAIL; 143 } 144 145 // data id 146 SkTScopedComPtr<IDWriteFontFile> fontFile; 147 HR(fontFace->GetFiles(&numFiles, &fontFile)); 148 149 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader; 150 HR(fontFile->GetLoader(&fontFileLoader)); 151 152 const void* refKey; 153 UINT32 refKeySize; 154 HR(fontFile->GetReferenceKey(&refKey, &refKeySize)); 155 156 fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize); 157 158 // index 159 fontId->fTtcIndex = fontFace->GetIndex(); 160 161 // style 162 SkFontStyle::Slant slant; 163 switch (font->GetStyle()) { 164 case DWRITE_FONT_STYLE_NORMAL: 165 slant = SkFontStyle::kUpright_Slant; 166 break; 167 case DWRITE_FONT_STYLE_OBLIQUE: 168 case DWRITE_FONT_STYLE_ITALIC: 169 slant = SkFontStyle::kItalic_Slant; 170 break; 171 default: 172 SkASSERT(false); 173 } 174 175 int weight = font->GetWeight(); 176 int width = font->GetStretch(); 177 178 fontId->fFontStyle = SkFontStyle(weight, width, slant); 179 return S_OK; 180 } 181 182 virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const SK_OVERRIDE { 183 SkTScopedComPtr<IDWriteFontFamily> fontFamily; 184 HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily), 185 "Could not get requested family."); 186 187 int count = fontFamily->GetFontCount(); 188 SkFontIdentity* fontIds; 189 SkAutoTUnref<SkRemotableFontIdentitySet> fontIdSet( 190 new SkRemotableFontIdentitySet(count, &fontIds)); 191 for (int fontIndex = 0; fontIndex < count; ++fontIndex) { 192 SkTScopedComPtr<IDWriteFont> font; 193 HRNM(fontFamily->GetFont(fontIndex, &font), "Could not get font."); 194 195 HRN(FontToIdentity(font.get(), &fontIds[fontIndex])); 196 } 197 return fontIdSet.detach(); 198 } 199 200 virtual SkFontIdentity matchIndexStyle(int familyIndex, 201 const SkFontStyle& pattern) const SK_OVERRIDE 202 { 203 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; 204 205 SkTScopedComPtr<IDWriteFontFamily> fontFamily; 206 HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily), 207 "Could not get requested family.", 208 identity); 209 210 const DWriteStyle dwStyle(pattern); 211 SkTScopedComPtr<IDWriteFont> font; 212 HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, 213 dwStyle.fSlant, &font), 214 "Could not match font in family.", 215 identity); 216 217 HR_GENERAL(FontToIdentity(font.get(), &identity), NULL, identity); 218 219 return identity; 220 } 221 222 static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) { 223 NONCLIENTMETRICSW metrics; 224 metrics.cbSize = sizeof(metrics); 225 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 226 sizeof(metrics), 227 &metrics, 228 0)) { 229 return E_UNEXPECTED; 230 } 231 232 size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1; 233 if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) { 234 return E_UNEXPECTED; 235 } 236 237 return S_OK; 238 } 239 240 virtual SkRemotableFontIdentitySet* matchName(const char familyName[]) const SK_OVERRIDE { 241 SkSMallocWCHAR dwFamilyName; 242 if (NULL == familyName) { 243 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), 244 NULL, SkRemotableFontIdentitySet::NewEmpty()); 245 } else { 246 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), 247 NULL, SkRemotableFontIdentitySet::NewEmpty()); 248 } 249 250 UINT32 index; 251 BOOL exists; 252 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), 253 "Failed while finding family by name.", 254 SkRemotableFontIdentitySet::NewEmpty()); 255 if (!exists) { 256 return SkRemotableFontIdentitySet::NewEmpty(); 257 } 258 259 return this->getIndex(index); 260 } 261 262 virtual SkFontIdentity matchNameStyle(const char familyName[], 263 const SkFontStyle& style) const SK_OVERRIDE 264 { 265 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; 266 267 SkSMallocWCHAR dwFamilyName; 268 if (NULL == familyName) { 269 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity); 270 } else { 271 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity); 272 } 273 274 UINT32 index; 275 BOOL exists; 276 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists), 277 "Failed while finding family by name.", 278 identity); 279 if (!exists) { 280 return identity; 281 } 282 283 return this->matchIndexStyle(index, style); 284 } 285 286 class FontFallbackRenderer : public IDWriteTextRenderer { 287 public: 288 FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character) 289 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) { 290 fIdentity.fDataId = SkFontIdentity::kInvalidDataId; 291 } 292 293 virtual ~FontFallbackRenderer() { } 294 295 // IDWriteTextRenderer methods 296 virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun( 297 void* clientDrawingContext, 298 FLOAT baselineOriginX, 299 FLOAT baselineOriginY, 300 DWRITE_MEASURING_MODE measuringMode, 301 DWRITE_GLYPH_RUN const* glyphRun, 302 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 303 IUnknown* clientDrawingEffect) SK_OVERRIDE 304 { 305 SkTScopedComPtr<IDWriteFont> font; 306 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font), 307 "Could not get font from font face."); 308 309 // It is possible that the font passed does not actually have the requested character, 310 // due to no font being found and getting the fallback font. 311 // Check that the font actually contains the requested character. 312 BOOL exists; 313 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character."); 314 315 if (exists) { 316 HR(fOuter->FontToIdentity(font.get(), &fIdentity)); 317 } 318 319 return S_OK; 320 } 321 322 virtual HRESULT STDMETHODCALLTYPE DrawUnderline( 323 void* clientDrawingContext, 324 FLOAT baselineOriginX, 325 FLOAT baselineOriginY, 326 DWRITE_UNDERLINE const* underline, 327 IUnknown* clientDrawingEffect) SK_OVERRIDE 328 { return E_NOTIMPL; } 329 330 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough( 331 void* clientDrawingContext, 332 FLOAT baselineOriginX, 333 FLOAT baselineOriginY, 334 DWRITE_STRIKETHROUGH const* strikethrough, 335 IUnknown* clientDrawingEffect) SK_OVERRIDE 336 { return E_NOTIMPL; } 337 338 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject( 339 void* clientDrawingContext, 340 FLOAT originX, 341 FLOAT originY, 342 IDWriteInlineObject* inlineObject, 343 BOOL isSideways, 344 BOOL isRightToLeft, 345 IUnknown* clientDrawingEffect) SK_OVERRIDE 346 { return E_NOTIMPL; } 347 348 // IDWritePixelSnapping methods 349 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled( 350 void* clientDrawingContext, 351 BOOL* isDisabled) SK_OVERRIDE 352 { 353 *isDisabled = FALSE; 354 return S_OK; 355 } 356 357 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform( 358 void* clientDrawingContext, 359 DWRITE_MATRIX* transform) SK_OVERRIDE 360 { 361 const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; 362 *transform = ident; 363 return S_OK; 364 } 365 366 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip( 367 void* clientDrawingContext, 368 FLOAT* pixelsPerDip) SK_OVERRIDE 369 { 370 *pixelsPerDip = 1.0f; 371 return S_OK; 372 } 373 374 // IUnknown methods 375 virtual ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE { 376 return InterlockedIncrement(&fRefCount); 377 } 378 379 virtual ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE { 380 ULONG newCount = InterlockedDecrement(&fRefCount); 381 if (0 == newCount) { 382 delete this; 383 } 384 return newCount; 385 } 386 387 virtual HRESULT STDMETHODCALLTYPE QueryInterface( 388 IID const& riid, void** ppvObject) SK_OVERRIDE 389 { 390 if (__uuidof(IUnknown) == riid || 391 __uuidof(IDWritePixelSnapping) == riid || 392 __uuidof(IDWriteTextRenderer) == riid) 393 { 394 *ppvObject = this; 395 this->AddRef(); 396 return S_OK; 397 } 398 *ppvObject = NULL; 399 return E_FAIL; 400 } 401 402 const SkFontIdentity FallbackIdentity() { return fIdentity; } 403 404 protected: 405 ULONG fRefCount; 406 SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter; 407 UINT32 fCharacter; 408 SkFontIdentity fIdentity; 409 }; 410 411 virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], 412 const SkFontStyle& pattern, 413 const char bpc47[], 414 SkUnichar character) const SK_OVERRIDE 415 { 416 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; 417 418 IDWriteFactory* dwFactory = sk_get_dwrite_factory(); 419 if (NULL == dwFactory) { 420 return identity; 421 } 422 423 // TODO: use IDWriteFactory2::GetSystemFontFallback when available. 424 425 const DWriteStyle dwStyle(pattern); 426 427 SkSMallocWCHAR dwFamilyName; 428 if (NULL == familyName) { 429 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity); 430 } else { 431 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity); 432 } 433 434 const SkSMallocWCHAR* dwBpc47; 435 SkSMallocWCHAR dwBpc47Local; 436 if (NULL == bpc47) { 437 dwBpc47 = &fLocaleName; 438 } else { 439 HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity); 440 dwBpc47 = &dwBpc47Local; 441 } 442 443 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat; 444 HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName, 445 fFontCollection.get(), 446 dwStyle.fWeight, 447 dwStyle.fSlant, 448 dwStyle.fWidth, 449 72.0f, 450 *dwBpc47, 451 &fallbackFormat), 452 "Could not create text format.", 453 identity); 454 455 WCHAR str[16]; 456 UINT32 strLen = static_cast<UINT32>( 457 SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str))); 458 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout; 459 HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(), 460 200.0f, 200.0f, 461 &fallbackLayout), 462 "Could not create text layout.", 463 identity); 464 465 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer( 466 new FontFallbackRenderer(this, character)); 467 468 HR_GENERAL(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f), 469 "Could not draw layout with renderer.", 470 identity); 471 472 return fontFallbackRenderer->FallbackIdentity(); 473 } 474 475 virtual SkStreamAsset* getData(int dataId) const SK_OVERRIDE { 476 SkAutoMutexAcquire ama(fDataIdCacheMutex); 477 if (dataId >= fDataIdCache.count()) { 478 return NULL; 479 } 480 const DataId& id = fDataIdCache[dataId]; 481 482 SkTScopedComPtr<IDWriteFontFileLoader> loader; 483 HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed"); 484 485 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream; 486 HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream), 487 "Could not create font file stream."); 488 489 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get())); 490 } 491 492 private: 493 SkTScopedComPtr<IDWriteFontCollection> fFontCollection; 494 SkSMallocWCHAR fLocaleName; 495 496 typedef SkRemotableFontMgr INHERITED; 497 }; 498 499 SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() { 500 IDWriteFactory* factory = sk_get_dwrite_factory(); 501 if (NULL == factory) { 502 return NULL; 503 } 504 505 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; 506 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE), 507 "Could not get system font collection."); 508 509 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; 510 WCHAR* localeName = NULL; 511 int localeNameLen = 0; 512 513 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. 514 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; 515 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); 516 if (NULL == getUserDefaultLocaleNameProc) { 517 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); 518 } else { 519 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); 520 if (localeNameLen) { 521 localeName = localeNameStorage; 522 }; 523 } 524 525 return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(), 526 localeName, localeNameLen)); 527 } 528