OLD | NEW |
(Empty) | |
| 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(), &familyNa
me); |
| 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_OVERR
IDE { |
| 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.fWi
dth, |
| 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.lfFaceNa
me, _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_OVE
RRIDE |
| 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, ide
ntity); |
| 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 // IDWriteTextRenderer methods |
| 294 virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun( |
| 295 void* clientDrawingContext, |
| 296 FLOAT baselineOriginX, |
| 297 FLOAT baselineOriginY, |
| 298 DWRITE_MEASURING_MODE measuringMode, |
| 299 DWRITE_GLYPH_RUN const* glyphRun, |
| 300 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, |
| 301 IUnknown* clientDrawingEffect) SK_OVERRIDE |
| 302 { |
| 303 SkTScopedComPtr<IDWriteFont> font; |
| 304 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace,
&font), |
| 305 "Could not get font from font face."); |
| 306 |
| 307 // It is possible that the font passed does not actually have the re
quested character, |
| 308 // due to no font being found and getting the fallback font. |
| 309 // Check that the font actually contains the requested character. |
| 310 BOOL exists; |
| 311 HRM(font->HasCharacter(fCharacter, &exists), "Could not find charact
er."); |
| 312 |
| 313 if (exists) { |
| 314 HR(fOuter->FontToIdentity(font.get(), &fIdentity)); |
| 315 } |
| 316 |
| 317 return S_OK; |
| 318 } |
| 319 |
| 320 virtual HRESULT STDMETHODCALLTYPE DrawUnderline( |
| 321 void* clientDrawingContext, |
| 322 FLOAT baselineOriginX, |
| 323 FLOAT baselineOriginY, |
| 324 DWRITE_UNDERLINE const* underline, |
| 325 IUnknown* clientDrawingEffect) SK_OVERRIDE |
| 326 { return E_NOTIMPL; } |
| 327 |
| 328 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough( |
| 329 void* clientDrawingContext, |
| 330 FLOAT baselineOriginX, |
| 331 FLOAT baselineOriginY, |
| 332 DWRITE_STRIKETHROUGH const* strikethrough, |
| 333 IUnknown* clientDrawingEffect) SK_OVERRIDE |
| 334 { return E_NOTIMPL; } |
| 335 |
| 336 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject( |
| 337 void* clientDrawingContext, |
| 338 FLOAT originX, |
| 339 FLOAT originY, |
| 340 IDWriteInlineObject* inlineObject, |
| 341 BOOL isSideways, |
| 342 BOOL isRightToLeft, |
| 343 IUnknown* clientDrawingEffect) SK_OVERRIDE |
| 344 { return E_NOTIMPL; } |
| 345 |
| 346 // IDWritePixelSnapping methods |
| 347 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled( |
| 348 void* clientDrawingContext, |
| 349 BOOL* isDisabled) SK_OVERRIDE |
| 350 { |
| 351 *isDisabled = FALSE; |
| 352 return S_OK; |
| 353 } |
| 354 |
| 355 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform( |
| 356 void* clientDrawingContext, |
| 357 DWRITE_MATRIX* transform) SK_OVERRIDE |
| 358 { |
| 359 const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; |
| 360 *transform = ident; |
| 361 return S_OK; |
| 362 } |
| 363 |
| 364 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip( |
| 365 void* clientDrawingContext, |
| 366 FLOAT* pixelsPerDip) SK_OVERRIDE |
| 367 { |
| 368 *pixelsPerDip = 1.0f; |
| 369 return S_OK; |
| 370 } |
| 371 |
| 372 // IUnknown methods |
| 373 virtual ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE { |
| 374 return InterlockedIncrement(&fRefCount); |
| 375 } |
| 376 |
| 377 virtual ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE { |
| 378 ULONG newCount = InterlockedDecrement(&fRefCount); |
| 379 if (0 == newCount) { |
| 380 delete this; |
| 381 } |
| 382 return newCount; |
| 383 } |
| 384 |
| 385 virtual HRESULT STDMETHODCALLTYPE QueryInterface( |
| 386 IID const& riid, void** ppvObject) SK_OVERRIDE |
| 387 { |
| 388 if (__uuidof(IUnknown) == riid || |
| 389 __uuidof(IDWritePixelSnapping) == riid || |
| 390 __uuidof(IDWriteTextRenderer) == riid) |
| 391 { |
| 392 *ppvObject = this; |
| 393 this->AddRef(); |
| 394 return S_OK; |
| 395 } |
| 396 *ppvObject = NULL; |
| 397 return E_FAIL; |
| 398 } |
| 399 |
| 400 const SkFontIdentity FallbackIdentity() { return fIdentity; } |
| 401 |
| 402 protected: |
| 403 ULONG fRefCount; |
| 404 SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter; |
| 405 UINT32 fCharacter; |
| 406 SkFontIdentity fIdentity; |
| 407 }; |
| 408 |
| 409 virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], |
| 410 const SkFontStyle& pattern, |
| 411 const char bpc47[], |
| 412 SkUnichar character) const S
K_OVERRIDE |
| 413 { |
| 414 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId }; |
| 415 |
| 416 IDWriteFactory* dwFactory = sk_get_dwrite_factory(); |
| 417 if (NULL == dwFactory) { |
| 418 return identity; |
| 419 } |
| 420 |
| 421 // TODO: use IDWriteFactory2::GetSystemFontFallback when available. |
| 422 |
| 423 const DWriteStyle dwStyle(pattern); |
| 424 |
| 425 SkSMallocWCHAR dwFamilyName; |
| 426 if (NULL == familyName) { |
| 427 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity); |
| 428 } else { |
| 429 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, ide
ntity); |
| 430 } |
| 431 |
| 432 const SkSMallocWCHAR* dwBpc47; |
| 433 SkSMallocWCHAR dwBpc47Local; |
| 434 if (NULL == bpc47) { |
| 435 dwBpc47 = &fLocaleName; |
| 436 } else { |
| 437 HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity
); |
| 438 dwBpc47 = &dwBpc47Local; |
| 439 } |
| 440 |
| 441 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat; |
| 442 HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName, |
| 443 fFontCollection.get(), |
| 444 dwStyle.fWeight, |
| 445 dwStyle.fSlant, |
| 446 dwStyle.fWidth, |
| 447 72.0f, |
| 448 *dwBpc47, |
| 449 &fallbackFormat), |
| 450 "Could not create text format.", |
| 451 identity); |
| 452 |
| 453 WCHAR str[16]; |
| 454 UINT32 strLen = SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t
*>(str)); |
| 455 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout; |
| 456 HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get()
, |
| 457 200.0f, 200.0f, |
| 458 &fallbackLayout), |
| 459 "Could not create text layout.", |
| 460 identity); |
| 461 |
| 462 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer( |
| 463 new FontFallbackRenderer(this, character)); |
| 464 |
| 465 HR_GENERAL(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f,
50.0f), |
| 466 "Could not draw layout with renderer.", |
| 467 identity); |
| 468 |
| 469 return fontFallbackRenderer->FallbackIdentity(); |
| 470 } |
| 471 |
| 472 virtual SkStreamAsset* getData(int dataId) const SK_OVERRIDE { |
| 473 SkAutoMutexAcquire ama(fDataIdCacheMutex); |
| 474 if (dataId >= fDataIdCache.count()) { |
| 475 return NULL; |
| 476 } |
| 477 const DataId& id = fDataIdCache[dataId]; |
| 478 |
| 479 SkTScopedComPtr<IDWriteFontFileLoader> loader; |
| 480 HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFi
leLoader failed"); |
| 481 |
| 482 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream; |
| 483 HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream), |
| 484 "Could not create font file stream."); |
| 485 |
| 486 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get())); |
| 487 } |
| 488 |
| 489 private: |
| 490 SkTScopedComPtr<IDWriteFontCollection> fFontCollection; |
| 491 SkSMallocWCHAR fLocaleName; |
| 492 |
| 493 typedef SkRemotableFontMgr INHERITED; |
| 494 }; |
| 495 |
| 496 SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() { |
| 497 IDWriteFactory* factory = sk_get_dwrite_factory(); |
| 498 if (NULL == factory) { |
| 499 return NULL; |
| 500 } |
| 501 |
| 502 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; |
| 503 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE), |
| 504 "Could not get system font collection."); |
| 505 |
| 506 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; |
| 507 WCHAR* localeName = NULL; |
| 508 int localeNameLen = 0; |
| 509 |
| 510 // Dynamically load GetUserDefaultLocaleName function, as it is not availabl
e on XP. |
| 511 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; |
| 512 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc
); |
| 513 if (NULL == getUserDefaultLocaleNameProc) { |
| 514 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); |
| 515 } else { |
| 516 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_N
AME_MAX_LENGTH); |
| 517 if (localeNameLen) { |
| 518 localeName = localeNameStorage; |
| 519 }; |
| 520 } |
| 521 |
| 522 return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(), |
| 523 localeName, localeNameLen
)); |
| 524 } |
OLD | NEW |