2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkDataTable.h"
10 #include "SkDWriteFontFileStream.h"
11 #include "SkHRESULT.h"
12 #include "SkRemotableFontMgr.h"
17 #include "SkTScopedComPtr.h"
18 #include "SkTypeface_win.h"
25 explicit DWriteStyle(const SkFontStyle& pattern) {
26 switch (pattern.slant()) {
27 case SkFontStyle::kUpright_Slant:
28 fSlant = DWRITE_FONT_STYLE_NORMAL;
30 case SkFontStyle::kItalic_Slant:
31 fSlant = DWRITE_FONT_STYLE_ITALIC;
37 fWeight = (DWRITE_FONT_WEIGHT)pattern.weight();
38 fWidth = (DWRITE_FONT_STRETCH)pattern.width();
40 DWRITE_FONT_STYLE fSlant;
41 DWRITE_FONT_WEIGHT fWeight;
42 DWRITE_FONT_STRETCH fWidth;
45 class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr {
48 IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity.
54 // This is actually a move!!!
55 explicit DataId(DataId& that)
56 : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize)
60 SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;)
71 mutable SkTArray<DataId> fDataIdCache;
72 mutable SkMutex fDataIdCacheMutex;
74 int FindOrAdd(IDWriteFontFileLoader* fontFileLoader,
75 const void* refKey, UINT32 refKeySize) const
77 SkTScopedComPtr<IUnknown> fontFileLoaderId;
78 HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId),
79 "Failed to re-convert to IDWriteFontFileLoader.",
80 SkFontIdentity::kInvalidDataId);
82 SkAutoMutexAcquire ama(fDataIdCacheMutex);
83 int count = fDataIdCache.count();
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))
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;
104 SK_DECLARE_INST_COUNT(SkRemotableFontMgr_DirectWrite)
106 /** localeNameLength must include the null terminator. */
107 SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection,
108 WCHAR* localeName, int localeNameLength)
109 : fFontCollection(SkRefComPtr(fontCollection))
110 , fLocaleName(localeNameLength)
112 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
115 virtual SkDataTable* getFamilyNames() const SK_OVERRIDE {
116 int count = fFontCollection->GetFontFamilyCount();
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.");
124 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
125 HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
128 sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName);
130 names.appendString(familyName);
132 return names.detachDataTable();
135 HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const {
136 SkTScopedComPtr<IDWriteFontFace> fontFace;
137 HRM(font->CreateFontFace(&fontFace), "Could not create font face.");
140 HR(fontFace->GetFiles(&numFiles, NULL));
146 SkTScopedComPtr<IDWriteFontFile> fontFile;
147 HR(fontFace->GetFiles(&numFiles, &fontFile));
149 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
150 HR(fontFile->GetLoader(&fontFileLoader));
154 HR(fontFile->GetReferenceKey(&refKey, &refKeySize));
156 fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize);
159 fontId->fTtcIndex = fontFace->GetIndex();
162 SkFontStyle::Slant slant;
163 switch (font->GetStyle()) {
164 case DWRITE_FONT_STYLE_NORMAL:
165 slant = SkFontStyle::kUpright_Slant;
167 case DWRITE_FONT_STYLE_OBLIQUE:
168 case DWRITE_FONT_STYLE_ITALIC:
169 slant = SkFontStyle::kItalic_Slant;
175 int weight = font->GetWeight();
176 int width = font->GetStretch();
178 fontId->fFontStyle = SkFontStyle(weight, width, slant);
182 virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const SK_OVERRIDE {
183 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
184 HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
185 "Could not get requested family.");
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.");
195 HRN(FontToIdentity(font.get(), &fontIds[fontIndex]));
197 return fontIdSet.detach();
200 virtual SkFontIdentity matchIndexStyle(int familyIndex,
201 const SkFontStyle& pattern) const SK_OVERRIDE
203 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
205 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
206 HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
207 "Could not get requested family.",
210 const DWriteStyle dwStyle(pattern);
211 SkTScopedComPtr<IDWriteFont> font;
212 HR_GENERAL(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth,
213 dwStyle.fSlant, &font),
214 "Could not match font in family.",
217 HR_GENERAL(FontToIdentity(font.get(), &identity), NULL, identity);
222 static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) {
223 NONCLIENTMETRICSW metrics;
224 metrics.cbSize = sizeof(metrics);
225 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
232 size_t len = wcsnlen_s(metrics.lfMessageFont.lfFaceName, LF_FACESIZE) + 1;
233 if (0 != wcsncpy_s(name->reset(len), len, metrics.lfMessageFont.lfFaceName, _TRUNCATE)) {
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());
246 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName),
247 NULL, SkRemotableFontIdentitySet::NewEmpty());
252 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
253 "Failed while finding family by name.",
254 SkRemotableFontIdentitySet::NewEmpty());
256 return SkRemotableFontIdentitySet::NewEmpty();
259 return this->getIndex(index);
262 virtual SkFontIdentity matchNameStyle(const char familyName[],
263 const SkFontStyle& style) const SK_OVERRIDE
265 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
267 SkSMallocWCHAR dwFamilyName;
268 if (NULL == familyName) {
269 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
271 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
276 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
277 "Failed while finding family by name.",
283 return this->matchIndexStyle(index, style);
286 class FontFallbackRenderer : public IDWriteTextRenderer {
288 FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character)
289 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) {
290 fIdentity.fDataId = SkFontIdentity::kInvalidDataId;
293 virtual ~FontFallbackRenderer() { }
295 // IDWriteTextRenderer methods
296 virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(
297 void* clientDrawingContext,
298 FLOAT baselineOriginX,
299 FLOAT baselineOriginY,
300 DWRITE_MEASURING_MODE measuringMode,
301 DWRITE_GLYPH_RUN const* glyphRun,
302 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
303 IUnknown* clientDrawingEffect) SK_OVERRIDE
305 SkTScopedComPtr<IDWriteFont> font;
306 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
307 "Could not get font from font face.");
309 // It is possible that the font passed does not actually have the requested character,
310 // due to no font being found and getting the fallback font.
311 // Check that the font actually contains the requested character.
313 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
316 HR(fOuter->FontToIdentity(font.get(), &fIdentity));
322 virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
323 void* clientDrawingContext,
324 FLOAT baselineOriginX,
325 FLOAT baselineOriginY,
326 DWRITE_UNDERLINE const* underline,
327 IUnknown* clientDrawingEffect) SK_OVERRIDE
328 { return E_NOTIMPL; }
330 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
331 void* clientDrawingContext,
332 FLOAT baselineOriginX,
333 FLOAT baselineOriginY,
334 DWRITE_STRIKETHROUGH const* strikethrough,
335 IUnknown* clientDrawingEffect) SK_OVERRIDE
336 { return E_NOTIMPL; }
338 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
339 void* clientDrawingContext,
342 IDWriteInlineObject* inlineObject,
345 IUnknown* clientDrawingEffect) SK_OVERRIDE
346 { return E_NOTIMPL; }
348 // IDWritePixelSnapping methods
349 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
350 void* clientDrawingContext,
351 BOOL* isDisabled) SK_OVERRIDE
357 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
358 void* clientDrawingContext,
359 DWRITE_MATRIX* transform) SK_OVERRIDE
361 const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
366 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
367 void* clientDrawingContext,
368 FLOAT* pixelsPerDip) SK_OVERRIDE
370 *pixelsPerDip = 1.0f;
375 virtual ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE {
376 return InterlockedIncrement(&fRefCount);
379 virtual ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE {
380 ULONG newCount = InterlockedDecrement(&fRefCount);
387 virtual HRESULT STDMETHODCALLTYPE QueryInterface(
388 IID const& riid, void** ppvObject) SK_OVERRIDE
390 if (__uuidof(IUnknown) == riid ||
391 __uuidof(IDWritePixelSnapping) == riid ||
392 __uuidof(IDWriteTextRenderer) == riid)
402 const SkFontIdentity FallbackIdentity() { return fIdentity; }
406 SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter;
408 SkFontIdentity fIdentity;
411 virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
412 const SkFontStyle& pattern,
414 SkUnichar character) const SK_OVERRIDE
416 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
418 IDWriteFactory* dwFactory = sk_get_dwrite_factory();
419 if (NULL == dwFactory) {
423 // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
425 const DWriteStyle dwStyle(pattern);
427 SkSMallocWCHAR dwFamilyName;
428 if (NULL == familyName) {
429 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
431 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
434 const SkSMallocWCHAR* dwBpc47;
435 SkSMallocWCHAR dwBpc47Local;
437 dwBpc47 = &fLocaleName;
439 HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity);
440 dwBpc47 = &dwBpc47Local;
443 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
444 HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName,
445 fFontCollection.get(),
452 "Could not create text format.",
456 UINT32 strLen = static_cast<UINT32>(
457 SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str)));
458 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
459 HR_GENERAL(dwFactory->CreateTextLayout(str, strLen, fallbackFormat.get(),
462 "Could not create text layout.",
465 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
466 new FontFallbackRenderer(this, character));
468 HR_GENERAL(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f),
469 "Could not draw layout with renderer.",
472 return fontFallbackRenderer->FallbackIdentity();
475 virtual SkStreamAsset* getData(int dataId) const SK_OVERRIDE {
476 SkAutoMutexAcquire ama(fDataIdCacheMutex);
477 if (dataId >= fDataIdCache.count()) {
480 const DataId& id = fDataIdCache[dataId];
482 SkTScopedComPtr<IDWriteFontFileLoader> loader;
483 HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed");
485 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
486 HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream),
487 "Could not create font file stream.");
489 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
493 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
494 SkSMallocWCHAR fLocaleName;
496 typedef SkRemotableFontMgr INHERITED;
499 SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() {
500 IDWriteFactory* factory = sk_get_dwrite_factory();
501 if (NULL == factory) {
505 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
506 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
507 "Could not get system font collection.");
509 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
510 WCHAR* localeName = NULL;
511 int localeNameLen = 0;
513 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
514 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL;
515 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
516 if (NULL == getUserDefaultLocaleNameProc) {
517 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
519 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
521 localeName = localeNameStorage;
525 return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(),
526 localeName, localeNameLen));