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