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