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