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