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"
24 class SK_API SkRemotableFontMgr_DirectWrite : public SkRemotableFontMgr {
27 IUnknown* fLoader; // In COM only IUnknown pointers may be safely used for identity.
33 // This is actually a move!!!
34 explicit DataId(DataId& that)
35 : fLoader(that.fLoader), fKey(that.fKey), fKeySize(that.fKeySize)
39 SkDEBUGCODE(that.fKeySize = 0xFFFFFFFF;)
50 mutable SkTArray<DataId> fDataIdCache;
51 mutable SkMutex fDataIdCacheMutex;
53 int FindOrAdd(IDWriteFontFileLoader* fontFileLoader,
54 const void* refKey, UINT32 refKeySize) const
56 SkTScopedComPtr<IUnknown> fontFileLoaderId;
57 HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId),
58 "Failed to re-convert to IDWriteFontFileLoader.",
59 SkFontIdentity::kInvalidDataId);
61 SkAutoMutexAcquire ama(fDataIdCacheMutex);
62 int count = fDataIdCache.count();
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))
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;
83 SK_DECLARE_INST_COUNT(SkRemotableFontMgr_DirectWrite)
85 /** localeNameLength must include the null terminator. */
86 SkRemotableFontMgr_DirectWrite(IDWriteFontCollection* fontCollection,
87 WCHAR* localeName, int localeNameLength)
88 : fFontCollection(SkRefComPtr(fontCollection))
89 , fLocaleName(localeNameLength)
91 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
94 SkDataTable* getFamilyNames() const SK_OVERRIDE {
95 int count = fFontCollection->GetFontFamilyCount();
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.");
103 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
104 HRNM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
107 sk_get_locale_string(familyNames.get(), fLocaleName.get(), &familyName);
109 names.appendString(familyName);
111 return names.detachDataTable();
114 HRESULT FontToIdentity(IDWriteFont* font, SkFontIdentity* fontId) const {
115 SkTScopedComPtr<IDWriteFontFace> fontFace;
116 HRM(font->CreateFontFace(&fontFace), "Could not create font face.");
119 HR(fontFace->GetFiles(&numFiles, NULL));
125 SkTScopedComPtr<IDWriteFontFile> fontFile;
126 HR(fontFace->GetFiles(&numFiles, &fontFile));
128 SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
129 HR(fontFile->GetLoader(&fontFileLoader));
133 HR(fontFile->GetReferenceKey(&refKey, &refKeySize));
135 fontId->fDataId = FindOrAdd(fontFileLoader.get(), refKey, refKeySize);
138 fontId->fTtcIndex = fontFace->GetIndex();
141 SkFontStyle::Slant slant;
142 switch (font->GetStyle()) {
143 case DWRITE_FONT_STYLE_NORMAL:
144 slant = SkFontStyle::kUpright_Slant;
146 case DWRITE_FONT_STYLE_OBLIQUE:
147 case DWRITE_FONT_STYLE_ITALIC:
148 slant = SkFontStyle::kItalic_Slant;
154 int weight = font->GetWeight();
155 int width = font->GetStretch();
157 fontId->fFontStyle = SkFontStyle(weight, width, slant);
161 SkRemotableFontIdentitySet* getIndex(int familyIndex) const SK_OVERRIDE {
162 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
163 HRNM(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
164 "Could not get requested family.");
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.");
174 HRN(FontToIdentity(font.get(), &fontIds[fontIndex]));
176 return fontIdSet.detach();
179 virtual SkFontIdentity matchIndexStyle(int familyIndex,
180 const SkFontStyle& pattern) const SK_OVERRIDE
182 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
184 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
185 HR_GENERAL(fFontCollection->GetFontFamily(familyIndex, &fontFamily),
186 "Could not get requested family.",
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.",
196 HR_GENERAL(FontToIdentity(font.get(), &identity), NULL, identity);
201 static HRESULT getDefaultFontFamilyName(SkSMallocWCHAR* name) {
202 NONCLIENTMETRICSW metrics;
203 metrics.cbSize = sizeof(metrics);
204 if (0 == SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
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)) {
219 SkRemotableFontIdentitySet* matchName(const char familyName[]) const SK_OVERRIDE {
220 SkSMallocWCHAR dwFamilyName;
221 if (NULL == familyName) {
222 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName),
223 NULL, SkRemotableFontIdentitySet::NewEmpty());
225 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName),
226 NULL, SkRemotableFontIdentitySet::NewEmpty());
231 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
232 "Failed while finding family by name.",
233 SkRemotableFontIdentitySet::NewEmpty());
235 return SkRemotableFontIdentitySet::NewEmpty();
238 return this->getIndex(index);
241 virtual SkFontIdentity matchNameStyle(const char familyName[],
242 const SkFontStyle& style) const SK_OVERRIDE
244 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
246 SkSMallocWCHAR dwFamilyName;
247 if (NULL == familyName) {
248 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
250 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
255 HR_GENERAL(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
256 "Failed while finding family by name.",
262 return this->matchIndexStyle(index, style);
265 class FontFallbackRenderer : public IDWriteTextRenderer {
267 FontFallbackRenderer(const SkRemotableFontMgr_DirectWrite* outer, UINT32 character)
268 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character) {
269 fIdentity.fDataId = SkFontIdentity::kInvalidDataId;
272 virtual ~FontFallbackRenderer() { }
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) SK_OVERRIDE
284 SkTScopedComPtr<IDWriteFont> font;
285 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
286 "Could not get font from font face.");
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.
292 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
295 HR(fOuter->FontToIdentity(font.get(), &fIdentity));
301 virtual HRESULT STDMETHODCALLTYPE DrawUnderline(
302 void* clientDrawingContext,
303 FLOAT baselineOriginX,
304 FLOAT baselineOriginY,
305 DWRITE_UNDERLINE const* underline,
306 IUnknown* clientDrawingEffect) SK_OVERRIDE
307 { return E_NOTIMPL; }
309 virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(
310 void* clientDrawingContext,
311 FLOAT baselineOriginX,
312 FLOAT baselineOriginY,
313 DWRITE_STRIKETHROUGH const* strikethrough,
314 IUnknown* clientDrawingEffect) SK_OVERRIDE
315 { return E_NOTIMPL; }
317 virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(
318 void* clientDrawingContext,
321 IDWriteInlineObject* inlineObject,
324 IUnknown* clientDrawingEffect) SK_OVERRIDE
325 { return E_NOTIMPL; }
327 // IDWritePixelSnapping methods
328 virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(
329 void* clientDrawingContext,
330 BOOL* isDisabled) SK_OVERRIDE
336 virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(
337 void* clientDrawingContext,
338 DWRITE_MATRIX* transform) SK_OVERRIDE
340 const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
345 virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(
346 void* clientDrawingContext,
347 FLOAT* pixelsPerDip) SK_OVERRIDE
349 *pixelsPerDip = 1.0f;
354 ULONG STDMETHODCALLTYPE AddRef() SK_OVERRIDE {
355 return InterlockedIncrement(&fRefCount);
358 ULONG STDMETHODCALLTYPE Release() SK_OVERRIDE {
359 ULONG newCount = InterlockedDecrement(&fRefCount);
366 virtual HRESULT STDMETHODCALLTYPE QueryInterface(
367 IID const& riid, void** ppvObject) SK_OVERRIDE
369 if (__uuidof(IUnknown) == riid ||
370 __uuidof(IDWritePixelSnapping) == riid ||
371 __uuidof(IDWriteTextRenderer) == riid)
381 const SkFontIdentity FallbackIdentity() { return fIdentity; }
385 SkAutoTUnref<const SkRemotableFontMgr_DirectWrite> fOuter;
387 SkFontIdentity fIdentity;
390 virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
391 const SkFontStyle& pattern,
392 const char* bcp47[], int bcp47Count,
393 SkUnichar character) const SK_OVERRIDE
395 SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
397 IDWriteFactory* dwFactory = sk_get_dwrite_factory();
398 if (NULL == dwFactory) {
402 // TODO: use IDWriteFactory2::GetSystemFontFallback when available.
404 const DWriteStyle dwStyle(pattern);
406 SkSMallocWCHAR dwFamilyName;
407 if (NULL == familyName) {
408 HR_GENERAL(getDefaultFontFamilyName(&dwFamilyName), NULL, identity);
410 HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
413 const SkSMallocWCHAR* dwBcp47;
414 SkSMallocWCHAR dwBcp47Local;
415 if (bcp47Count < 1) {
416 dwBcp47 = &fLocaleName;
418 //TODO: support fallback stack.
419 HR_GENERAL(sk_cstring_to_wchar(bcp47[bcp47Count-1], &dwBcp47Local), NULL, identity);
420 dwBcp47 = &dwBcp47Local;
423 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
424 HR_GENERAL(dwFactory->CreateTextFormat(dwFamilyName,
425 fFontCollection.get(),
432 "Could not create text format.",
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(),
442 "Could not create text layout.",
445 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
446 new FontFallbackRenderer(this, character));
448 HR_GENERAL(fallbackLayout->Draw(NULL, fontFallbackRenderer.get(), 50.0f, 50.0f),
449 "Could not draw layout with renderer.",
452 return fontFallbackRenderer->FallbackIdentity();
455 SkStreamAsset* getData(int dataId) const SK_OVERRIDE {
456 SkAutoMutexAcquire ama(fDataIdCacheMutex);
457 if (dataId >= fDataIdCache.count()) {
460 const DataId& id = fDataIdCache[dataId];
462 SkTScopedComPtr<IDWriteFontFileLoader> loader;
463 HRNM(id.fLoader->QueryInterface(&loader), "QuerryInterface IDWriteFontFileLoader failed");
465 SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
466 HRNM(loader->CreateStreamFromKey(id.fKey, id.fKeySize, &fontFileStream),
467 "Could not create font file stream.");
469 return SkNEW_ARGS(SkDWriteFontFileStream, (fontFileStream.get()));
473 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
474 SkSMallocWCHAR fLocaleName;
476 typedef SkRemotableFontMgr INHERITED;
479 SkRemotableFontMgr* SkRemotableFontMgr_New_DirectWrite() {
480 IDWriteFactory* factory = sk_get_dwrite_factory();
481 if (NULL == factory) {
485 SkTScopedComPtr<IDWriteFontCollection> sysFontCollection;
486 HRNM(factory->GetSystemFontCollection(&sysFontCollection, FALSE),
487 "Could not get system font collection.");
489 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
490 WCHAR* localeName = NULL;
491 int localeNameLen = 0;
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.");
499 localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
501 localeName = localeNameStorage;
505 return SkNEW_ARGS(SkRemotableFontMgr_DirectWrite, (sysFontCollection.get(),
506 localeName, localeNameLen));