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 "src/utils/win/SkDWriteNTDDI_VERSION.h"
8
9 #include "include/core/SkTypes.h"
10 #if defined(SK_BUILD_FOR_WIN)
11
12 #include "include/core/SkFontMgr.h"
13 #include "include/core/SkStream.h"
14 #include "include/core/SkTypeface.h"
15 #include "include/core/SkTypes.h"
16 #include "include/private/base/SkMutex.h"
17 #include "include/private/base/SkTPin.h"
18 #include "src/base/SkEndian.h"
19 #include "src/base/SkUTF.h"
20 #include "src/core/SkFontDescriptor.h"
21 #include "src/core/SkTypefaceCache.h"
22 #include "src/ports/SkTypeface_win_dw.h"
23 #include "src/utils/win/SkDWrite.h"
24 #include "src/utils/win/SkDWriteFontFileStream.h"
25 #include "src/utils/win/SkHRESULT.h"
26 #include "src/utils/win/SkObjBase.h"
27 #include "src/utils/win/SkTScopedComPtr.h"
28
29 #include <dwrite.h>
30 #include <dwrite_2.h>
31 #include <dwrite_3.h>
32
33 using namespace skia_private;
34
35 namespace {
36
37 // Korean fonts Gulim, Dotum, Batang, Gungsuh have bitmap strikes that get
38 // artifically emboldened by Windows without antialiasing. Korean users prefer
39 // these over the synthetic boldening performed by Skia. So let's make an
40 // exception for fonts with bitmap strikes and allow passing through Windows
41 // simulations for those, until Skia provides more control over simulations in
42 // font matching, see https://crbug.com/1258378
HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont> & font)43 bool HasBitmapStrikes(const SkTScopedComPtr<IDWriteFont>& font) {
44 SkTScopedComPtr<IDWriteFontFace> fontFace;
45 HRB(font->CreateFontFace(&fontFace));
46
47 AutoDWriteTable ebdtTable(fontFace.get(),
48 SkEndian_SwapBE32(SkSetFourByteTag('E', 'B', 'D', 'T')));
49 return ebdtTable.fExists;
50 }
51
52 // Iterate calls to GetFirstMatchingFont incrementally removing bold or italic
53 // styling that can trigger the simulations. Implementing it this way gets us a
54 // IDWriteFont that can be used as before and has the correct information on its
55 // own style. Stripping simulations from IDWriteFontFace is possible via
56 // IDWriteFontList1, IDWriteFontFaceReference and CreateFontFace, but this way
57 // we won't have a matching IDWriteFont which is still used in get_style().
FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily> & family,DWriteStyle dwStyle,SkTScopedComPtr<IDWriteFont> & font)58 HRESULT FirstMatchingFontWithoutSimulations(const SkTScopedComPtr<IDWriteFontFamily>& family,
59 DWriteStyle dwStyle,
60 SkTScopedComPtr<IDWriteFont>& font) {
61 bool noSimulations = false;
62 while (!noSimulations) {
63 SkTScopedComPtr<IDWriteFont> searchFont;
64 HR(family->GetFirstMatchingFont(
65 dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &searchFont));
66 DWRITE_FONT_SIMULATIONS simulations = searchFont->GetSimulations();
67 // If we still get simulations even though we're not asking for bold or
68 // italic, we can't help it and exit the loop.
69
70 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
71 noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE ||
72 (dwStyle.fWeight == DWRITE_FONT_WEIGHT_REGULAR &&
73 dwStyle.fSlant == DWRITE_FONT_STYLE_NORMAL) ||
74 HasBitmapStrikes(searchFont);
75 #else
76 noSimulations = true;
77 #endif
78 if (noSimulations) {
79 font = std::move(searchFont);
80 break;
81 }
82 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
83 dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
84 continue;
85 }
86 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
87 dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
88 continue;
89 }
90 }
91 return S_OK;
92 }
93 }
94
95 ////////////////////////////////////////////////////////////////////////////////
96
97 class SkFontMgr_DirectWrite : public SkFontMgr {
98 public:
99 /** localeNameLength and defaultFamilyNameLength must include the null terminator. */
SkFontMgr_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * fontCollection,IDWriteFontFallback * fallback,const WCHAR * localeName,int localeNameLength,const WCHAR * defaultFamilyName,int defaultFamilyNameLength)100 SkFontMgr_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* fontCollection,
101 IDWriteFontFallback* fallback,
102 const WCHAR* localeName, int localeNameLength,
103 const WCHAR* defaultFamilyName, int defaultFamilyNameLength)
104 : fFactory(SkRefComPtr(factory))
105 , fFontFallback(SkSafeRefComPtr(fallback))
106 , fFontCollection(SkRefComPtr(fontCollection))
107 , fLocaleName(localeNameLength)
108 , fDefaultFamilyName(defaultFamilyNameLength)
109 {
110 memcpy(fLocaleName.get(), localeName, localeNameLength * sizeof(WCHAR));
111 memcpy(fDefaultFamilyName.get(), defaultFamilyName, defaultFamilyNameLength*sizeof(WCHAR));
112 }
113
114 protected:
115 int onCountFamilies() const override;
116 void onGetFamilyName(int index, SkString* familyName) const override;
117 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override;
118 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override;
119 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
120 const SkFontStyle& fontstyle) const override;
121 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
122 const char* bcp47[], int bcp47Count,
123 SkUnichar character) const override;
124 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>, int ttcIndex) const override;
125 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const override;
126 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
127 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
128 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
129
130 private:
131 HRESULT getByFamilyName(const WCHAR familyName[], IDWriteFontFamily** fontFamily) const;
132 sk_sp<SkTypeface> fallback(const WCHAR* dwFamilyName, DWriteStyle,
133 const WCHAR* dwBcp47, UINT32 character) const;
134 sk_sp<SkTypeface> layoutFallback(const WCHAR* dwFamilyName, DWriteStyle,
135 const WCHAR* dwBcp47, UINT32 character) const;
136
137 /** Creates a typeface using a typeface cache. */
138 sk_sp<SkTypeface> makeTypefaceFromDWriteFont(IDWriteFontFace* fontFace,
139 IDWriteFont* font,
140 IDWriteFontFamily* fontFamily) const;
141
142 SkTScopedComPtr<IDWriteFactory> fFactory;
143 SkTScopedComPtr<IDWriteFontFallback> fFontFallback;
144 SkTScopedComPtr<IDWriteFontCollection> fFontCollection;
145 SkSMallocWCHAR fLocaleName;
146 SkSMallocWCHAR fDefaultFamilyName;
147 mutable SkMutex fTFCacheMutex;
148 mutable SkTypefaceCache fTFCache;
149
150 friend class SkFontStyleSet_DirectWrite;
151 friend class FontFallbackRenderer;
152 };
153
154 class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
155 public:
SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite * fontMgr,IDWriteFontFamily * fontFamily)156 SkFontStyleSet_DirectWrite(const SkFontMgr_DirectWrite* fontMgr,
157 IDWriteFontFamily* fontFamily)
158 : fFontMgr(SkRef(fontMgr))
159 , fFontFamily(SkRefComPtr(fontFamily))
160 { }
161
162 int count() override;
163 void getStyle(int index, SkFontStyle* fs, SkString* styleName) override;
164 sk_sp<SkTypeface> createTypeface(int index) override;
165 sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override;
166
167 private:
168 sk_sp<const SkFontMgr_DirectWrite> fFontMgr;
169 SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
170 };
171
are_same(IUnknown * a,IUnknown * b,bool & same)172 static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) {
173 SkTScopedComPtr<IUnknown> iunkA;
174 HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a.");
175
176 SkTScopedComPtr<IUnknown> iunkB;
177 HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b.");
178
179 same = (iunkA.get() == iunkB.get());
180 return S_OK;
181 }
182
183 struct ProtoDWriteTypeface {
184 IDWriteFontFace* fDWriteFontFace;
185 IDWriteFont* fDWriteFont;
186 IDWriteFontFamily* fDWriteFontFamily;
187 };
188
FindByDWriteFont(SkTypeface * cached,void * ctx)189 static bool FindByDWriteFont(SkTypeface* cached, void* ctx) {
190 DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached);
191 ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx);
192
193 // IDWriteFontFace5 introduced both Equals and HasVariations
194 SkTScopedComPtr<IDWriteFontFace5> cshFontFace5;
195 SkTScopedComPtr<IDWriteFontFace5> ctxFontFace5;
196 cshFace->fDWriteFontFace->QueryInterface(&cshFontFace5);
197 ctxFace->fDWriteFontFace->QueryInterface(&ctxFontFace5);
198 if (cshFontFace5 && ctxFontFace5) {
199 return cshFontFace5->Equals(ctxFontFace5.get());
200 }
201
202 bool same;
203
204 //Check to see if the two fonts are identical.
205 HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same));
206 if (same) {
207 return true;
208 }
209
210 HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same));
211 if (same) {
212 return true;
213 }
214
215 //Check if the two fonts share the same loader and have the same key.
216 UINT32 cshNumFiles;
217 UINT32 ctxNumFiles;
218 HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr));
219 HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr));
220 if (cshNumFiles != ctxNumFiles) {
221 return false;
222 }
223
224 SkTScopedComPtr<IDWriteFontFile> cshFontFile;
225 SkTScopedComPtr<IDWriteFontFile> ctxFontFile;
226 HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile));
227 HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile));
228
229 //for (each file) { //we currently only admit fonts from one file.
230 SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader;
231 SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader;
232 HRB(cshFontFile->GetLoader(&cshFontFileLoader));
233 HRB(ctxFontFile->GetLoader(&ctxFontFileLoader));
234 HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same));
235 if (!same) {
236 return false;
237 }
238 //}
239
240 const void* cshRefKey;
241 UINT32 cshRefKeySize;
242 const void* ctxRefKey;
243 UINT32 ctxRefKeySize;
244 HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize));
245 HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize));
246 if (cshRefKeySize != ctxRefKeySize) {
247 return false;
248 }
249 if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) {
250 return false;
251 }
252
253 //TODO: better means than comparing name strings?
254 //NOTE: .ttc and fake bold/italic will end up here.
255 SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames;
256 SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames;
257 HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames));
258 HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames));
259 UINT32 cshFamilyNameLength;
260 UINT32 cshFaceNameLength;
261 HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength));
262 HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength));
263
264 SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames;
265 SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames;
266 HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames));
267 HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames));
268 UINT32 ctxFamilyNameLength;
269 UINT32 ctxFaceNameLength;
270 HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength));
271 HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength));
272
273 if (cshFamilyNameLength != ctxFamilyNameLength ||
274 cshFaceNameLength != ctxFaceNameLength)
275 {
276 return false;
277 }
278
279 SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1);
280 SkSMallocWCHAR cshFaceName(cshFaceNameLength+1);
281 HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1));
282 HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1));
283
284 SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1);
285 SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1);
286 HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1));
287 HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1));
288
289 return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 &&
290 wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0;
291 }
292
makeTypefaceFromDWriteFont(IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily) const293 sk_sp<SkTypeface> SkFontMgr_DirectWrite::makeTypefaceFromDWriteFont(
294 IDWriteFontFace* fontFace,
295 IDWriteFont* font,
296 IDWriteFontFamily* fontFamily) const {
297 SkAutoMutexExclusive ama(fTFCacheMutex);
298 ProtoDWriteTypeface spec = { fontFace, font, fontFamily };
299 sk_sp<SkTypeface> face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec);
300 if (nullptr == face) {
301 face = DWriteFontTypeface::Make(fFactory.get(), fontFace, font, fontFamily, nullptr,
302 SkFontArguments::Palette{0, nullptr, 0});
303 if (face) {
304 fTFCache.add(face);
305 }
306 }
307 return face;
308 }
309
onCountFamilies() const310 int SkFontMgr_DirectWrite::onCountFamilies() const {
311 return fFontCollection->GetFontFamilyCount();
312 }
313
onGetFamilyName(int index,SkString * familyName) const314 void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const {
315 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
316 HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
317
318 SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
319 HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names.");
320
321 sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName);
322 }
323
onCreateStyleSet(int index) const324 sk_sp<SkFontStyleSet> SkFontMgr_DirectWrite::onCreateStyleSet(int index) const {
325 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
326 HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family.");
327
328 return sk_sp<SkFontStyleSet>(new SkFontStyleSet_DirectWrite(this, fontFamily.get()));
329 }
330
onMatchFamily(const char familyName[]) const331 sk_sp<SkFontStyleSet> SkFontMgr_DirectWrite::onMatchFamily(const char familyName[]) const {
332 if (!familyName) {
333 return nullptr;
334 }
335
336 SkSMallocWCHAR dwFamilyName;
337 HRN(sk_cstring_to_wchar(familyName, &dwFamilyName));
338
339 UINT32 index;
340 BOOL exists;
341 HRNM(fFontCollection->FindFamilyName(dwFamilyName.get(), &index, &exists),
342 "Failed while finding family by name.");
343 if (!exists) {
344 return nullptr;
345 }
346
347 return this->onCreateStyleSet(index);
348 }
349
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const350 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMatchFamilyStyle(const char familyName[],
351 const SkFontStyle& fontstyle) const {
352 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
353 return sset->matchStyle(fontstyle);
354 }
355
356 class FontFallbackRenderer : public IDWriteTextRenderer {
357 public:
FontFallbackRenderer(const SkFontMgr_DirectWrite * outer,UINT32 character)358 FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
359 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
360 }
361
362 // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)363 SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
364 if (__uuidof(IUnknown) == riid ||
365 __uuidof(IDWritePixelSnapping) == riid ||
366 __uuidof(IDWriteTextRenderer) == riid)
367 {
368 *ppvObject = this;
369 this->AddRef();
370 return S_OK;
371 }
372 *ppvObject = nullptr;
373 return E_FAIL;
374 }
375
AddRef()376 SK_STDMETHODIMP_(ULONG) AddRef() override {
377 return InterlockedIncrement(&fRefCount);
378 }
379
Release()380 SK_STDMETHODIMP_(ULONG) Release() override {
381 ULONG newCount = InterlockedDecrement(&fRefCount);
382 if (0 == newCount) {
383 delete this;
384 }
385 return newCount;
386 }
387
388 // IDWriteTextRenderer methods
DrawGlyphRun(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_MEASURING_MODE measuringMode,DWRITE_GLYPH_RUN const * glyphRun,DWRITE_GLYPH_RUN_DESCRIPTION const * glyphRunDescription,IUnknown * clientDrawingEffect)389 SK_STDMETHODIMP DrawGlyphRun(
390 void* clientDrawingContext,
391 FLOAT baselineOriginX,
392 FLOAT baselineOriginY,
393 DWRITE_MEASURING_MODE measuringMode,
394 DWRITE_GLYPH_RUN const* glyphRun,
395 DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
396 IUnknown* clientDrawingEffect) override
397 {
398 if (!glyphRun->fontFace) {
399 HRM(E_INVALIDARG, "Glyph run without font face.");
400 }
401
402 SkTScopedComPtr<IDWriteFont> font;
403 HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font),
404 "Could not get font from font face.");
405
406 // It is possible that the font passed does not actually have the requested character,
407 // due to no font being found and getting the fallback font.
408 // Check that the font actually contains the requested character.
409 BOOL exists;
410 HRM(font->HasCharacter(fCharacter, &exists), "Could not find character.");
411
412 if (exists) {
413 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
414 HRM(font->GetFontFamily(&fontFamily), "Could not get family.");
415 fResolvedTypeface = fOuter->makeTypefaceFromDWriteFont(glyphRun->fontFace,
416 font.get(),
417 fontFamily.get());
418 fHasSimulations = (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) &&
419 !HasBitmapStrikes(font);
420 }
421
422 return S_OK;
423 }
424
DrawUnderline(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_UNDERLINE const * underline,IUnknown * clientDrawingEffect)425 SK_STDMETHODIMP DrawUnderline(
426 void* clientDrawingContext,
427 FLOAT baselineOriginX,
428 FLOAT baselineOriginY,
429 DWRITE_UNDERLINE const* underline,
430 IUnknown* clientDrawingEffect) override
431 { return E_NOTIMPL; }
432
DrawStrikethrough(void * clientDrawingContext,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_STRIKETHROUGH const * strikethrough,IUnknown * clientDrawingEffect)433 SK_STDMETHODIMP DrawStrikethrough(
434 void* clientDrawingContext,
435 FLOAT baselineOriginX,
436 FLOAT baselineOriginY,
437 DWRITE_STRIKETHROUGH const* strikethrough,
438 IUnknown* clientDrawingEffect) override
439 { return E_NOTIMPL; }
440
DrawInlineObject(void * clientDrawingContext,FLOAT originX,FLOAT originY,IDWriteInlineObject * inlineObject,BOOL isSideways,BOOL isRightToLeft,IUnknown * clientDrawingEffect)441 SK_STDMETHODIMP DrawInlineObject(
442 void* clientDrawingContext,
443 FLOAT originX,
444 FLOAT originY,
445 IDWriteInlineObject* inlineObject,
446 BOOL isSideways,
447 BOOL isRightToLeft,
448 IUnknown* clientDrawingEffect) override
449 { return E_NOTIMPL; }
450
451 // IDWritePixelSnapping methods
IsPixelSnappingDisabled(void * clientDrawingContext,BOOL * isDisabled)452 SK_STDMETHODIMP IsPixelSnappingDisabled(
453 void* clientDrawingContext,
454 BOOL* isDisabled) override
455 {
456 *isDisabled = FALSE;
457 return S_OK;
458 }
459
GetCurrentTransform(void * clientDrawingContext,DWRITE_MATRIX * transform)460 SK_STDMETHODIMP GetCurrentTransform(
461 void* clientDrawingContext,
462 DWRITE_MATRIX* transform) override
463 {
464 const DWRITE_MATRIX ident = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 };
465 *transform = ident;
466 return S_OK;
467 }
468
GetPixelsPerDip(void * clientDrawingContext,FLOAT * pixelsPerDip)469 SK_STDMETHODIMP GetPixelsPerDip(
470 void* clientDrawingContext,
471 FLOAT* pixelsPerDip) override
472 {
473 *pixelsPerDip = 1.0f;
474 return S_OK;
475 }
476
ConsumeFallbackTypeface()477 sk_sp<SkTypeface> ConsumeFallbackTypeface() { return std::move(fResolvedTypeface); }
478
FallbackTypefaceHasSimulations()479 bool FallbackTypefaceHasSimulations() { return fHasSimulations; }
480
481 private:
~FontFallbackRenderer()482 virtual ~FontFallbackRenderer() { }
483
484 ULONG fRefCount;
485 sk_sp<const SkFontMgr_DirectWrite> fOuter;
486 UINT32 fCharacter;
487 sk_sp<SkTypeface> fResolvedTypeface;
488 bool fHasSimulations{false};
489 };
490
491 class FontFallbackSource : public IDWriteTextAnalysisSource {
492 public:
FontFallbackSource(const WCHAR * string,UINT32 length,const WCHAR * locale,IDWriteNumberSubstitution * numberSubstitution)493 FontFallbackSource(const WCHAR* string, UINT32 length, const WCHAR* locale,
494 IDWriteNumberSubstitution* numberSubstitution)
495 : fRefCount(1)
496 , fString(string)
497 , fLength(length)
498 , fLocale(locale)
499 , fNumberSubstitution(numberSubstitution)
500 { }
501
502 // IUnknown methods
QueryInterface(IID const & riid,void ** ppvObject)503 SK_STDMETHODIMP QueryInterface(IID const& riid, void** ppvObject) override {
504 if (__uuidof(IUnknown) == riid ||
505 __uuidof(IDWriteTextAnalysisSource) == riid)
506 {
507 *ppvObject = this;
508 this->AddRef();
509 return S_OK;
510 }
511 *ppvObject = nullptr;
512 return E_FAIL;
513 }
514
AddRef()515 SK_STDMETHODIMP_(ULONG) AddRef() override {
516 return InterlockedIncrement(&fRefCount);
517 }
518
Release()519 SK_STDMETHODIMP_(ULONG) Release() override {
520 ULONG newCount = InterlockedDecrement(&fRefCount);
521 if (0 == newCount) {
522 delete this;
523 }
524 return newCount;
525 }
526
527 // IDWriteTextAnalysisSource methods
GetTextAtPosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)528 SK_STDMETHODIMP GetTextAtPosition(
529 UINT32 textPosition,
530 WCHAR const** textString,
531 UINT32* textLength) override
532 {
533 if (fLength <= textPosition) {
534 *textString = nullptr;
535 *textLength = 0;
536 return S_OK;
537 }
538 *textString = fString + textPosition;
539 *textLength = fLength - textPosition;
540 return S_OK;
541 }
542
GetTextBeforePosition(UINT32 textPosition,WCHAR const ** textString,UINT32 * textLength)543 SK_STDMETHODIMP GetTextBeforePosition(
544 UINT32 textPosition,
545 WCHAR const** textString,
546 UINT32* textLength) override
547 {
548 if (textPosition < 1 || fLength <= textPosition) {
549 *textString = nullptr;
550 *textLength = 0;
551 return S_OK;
552 }
553 *textString = fString;
554 *textLength = textPosition;
555 return S_OK;
556 }
557
GetParagraphReadingDirection()558 SK_STDMETHODIMP_(DWRITE_READING_DIRECTION) GetParagraphReadingDirection() override {
559 // TODO: this is also interesting.
560 return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
561 }
562
GetLocaleName(UINT32 textPosition,UINT32 * textLength,WCHAR const ** localeName)563 SK_STDMETHODIMP GetLocaleName(
564 UINT32 textPosition,
565 UINT32* textLength,
566 WCHAR const** localeName) override
567 {
568 *localeName = fLocale;
569 return S_OK;
570 }
571
GetNumberSubstitution(UINT32 textPosition,UINT32 * textLength,IDWriteNumberSubstitution ** numberSubstitution)572 SK_STDMETHODIMP GetNumberSubstitution(
573 UINT32 textPosition,
574 UINT32* textLength,
575 IDWriteNumberSubstitution** numberSubstitution) override
576 {
577 *numberSubstitution = fNumberSubstitution;
578 return S_OK;
579 }
580
581 private:
~FontFallbackSource()582 virtual ~FontFallbackSource() { }
583
584 ULONG fRefCount;
585 const WCHAR* fString;
586 UINT32 fLength;
587 const WCHAR* fLocale;
588 IDWriteNumberSubstitution* fNumberSubstitution;
589 };
590
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle & style,const char * bcp47[],int bcp47Count,SkUnichar character) const591 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(
592 const char familyName[], const SkFontStyle& style,
593 const char* bcp47[], int bcp47Count,
594 SkUnichar character) const
595 {
596 DWriteStyle dwStyle(style);
597
598 const WCHAR* dwFamilyName = nullptr;
599 SkSMallocWCHAR dwFamilyNameLocal;
600 if (familyName) {
601 HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal));
602 dwFamilyName = dwFamilyNameLocal;
603 }
604
605 const SkSMallocWCHAR* dwBcp47;
606 SkSMallocWCHAR dwBcp47Local;
607 if (bcp47Count < 1) {
608 dwBcp47 = &fLocaleName;
609 } else {
610 // TODO: support fallback stack.
611 // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely
612 // and may produce a Japanese font.
613 HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local));
614 dwBcp47 = &dwBcp47Local;
615 }
616
617 if (fFontFallback) {
618 return this->fallback(dwFamilyName, dwStyle, dwBcp47->get(), character);
619 }
620
621 // LayoutFallback may use the system font collection for fallback.
622 return this->layoutFallback(dwFamilyName, dwStyle, dwBcp47->get(), character);
623 }
624
fallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const625 sk_sp<SkTypeface> SkFontMgr_DirectWrite::fallback(const WCHAR* dwFamilyName,
626 DWriteStyle dwStyle,
627 const WCHAR* dwBcp47,
628 UINT32 character) const {
629 WCHAR str[16];
630 UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
631
632 if (!fFontFallback) {
633 return nullptr;
634 }
635
636 SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution;
637 HRNM(fFactory->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, dwBcp47,
638 TRUE, &numberSubstitution),
639 "Could not create number substitution.");
640 SkTScopedComPtr<FontFallbackSource> fontFallbackSource(
641 new FontFallbackSource(str, strLen, dwBcp47, numberSubstitution.get()));
642
643 UINT32 mappedLength;
644 SkTScopedComPtr<IDWriteFont> font;
645 FLOAT scale;
646
647 bool noSimulations = false;
648 while (!noSimulations) {
649 font.reset();
650 HRNM(fFontFallback->MapCharacters(fontFallbackSource.get(),
651 0, // textPosition,
652 strLen,
653 fFontCollection.get(),
654 dwFamilyName,
655 dwStyle.fWeight,
656 dwStyle.fSlant,
657 dwStyle.fWidth,
658 &mappedLength,
659 &font,
660 &scale),
661 "Could not map characters");
662 if (!font.get()) {
663 return nullptr;
664 }
665
666 DWRITE_FONT_SIMULATIONS simulations = font->GetSimulations();
667
668 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
669 noSimulations = simulations == DWRITE_FONT_SIMULATIONS_NONE || HasBitmapStrikes(font);
670 #else
671 noSimulations = true;
672 #endif
673
674 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) {
675 dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
676 continue;
677 }
678
679 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
680 dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
681 continue;
682 }
683 }
684
685 SkTScopedComPtr<IDWriteFontFace> fontFace;
686 HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font.");
687
688 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
689 HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font.");
690 return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
691 }
692
layoutFallback(const WCHAR * dwFamilyName,DWriteStyle dwStyle,const WCHAR * dwBcp47,UINT32 character) const693 sk_sp<SkTypeface> SkFontMgr_DirectWrite::layoutFallback(const WCHAR* dwFamilyName,
694 DWriteStyle dwStyle,
695 const WCHAR* dwBcp47,
696 UINT32 character) const
697 {
698 WCHAR str[16];
699 UINT32 strLen = SkTo<UINT32>(SkUTF::ToUTF16(character, reinterpret_cast<uint16_t*>(str)));
700
701 bool noSimulations = false;
702 sk_sp<SkTypeface> returnTypeface(nullptr);
703 while (!noSimulations) {
704 SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
705 HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"",
706 fFontCollection.get(),
707 dwStyle.fWeight,
708 dwStyle.fSlant,
709 dwStyle.fWidth,
710 72.0f,
711 dwBcp47,
712 &fallbackFormat),
713 "Could not create text format.");
714
715 // No matter how the font collection is set on this IDWriteTextLayout, it is not possible to
716 // disable use of the system font collection in fallback.
717 SkTScopedComPtr<IDWriteTextLayout> fallbackLayout;
718 HRNM(fFactory->CreateTextLayout(
719 str, strLen, fallbackFormat.get(), 200.0f, 200.0f, &fallbackLayout),
720 "Could not create text layout.");
721
722 SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer(
723 new FontFallbackRenderer(this, character));
724
725 HRNM(fallbackLayout->SetFontCollection(fFontCollection.get(), {0, strLen}),
726 "Could not set layout font collection.");
727 HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f),
728 "Could not draw layout with renderer.");
729
730 #ifdef SK_WIN_FONTMGR_NO_SIMULATIONS
731 noSimulations = !fontFallbackRenderer->FallbackTypefaceHasSimulations();
732 #else
733 noSimulations = true;
734 #endif
735
736 if (noSimulations) {
737 returnTypeface = fontFallbackRenderer->ConsumeFallbackTypeface();
738 }
739
740 if (dwStyle.fWeight != DWRITE_FONT_WEIGHT_REGULAR) {
741 dwStyle.fWeight = DWRITE_FONT_WEIGHT_REGULAR;
742 continue;
743 }
744
745 if (dwStyle.fSlant != DWRITE_FONT_STYLE_NORMAL) {
746 dwStyle.fSlant = DWRITE_FONT_STYLE_NORMAL;
747 continue;
748 }
749 }
750
751 return returnTypeface;
752 }
753
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const754 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
755 int ttcIndex) const {
756 SkFontArguments args;
757 args.setCollectionIndex(ttcIndex);
758 return this->onMakeFromStreamArgs(std::move(stream), args);
759 }
760
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const761 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
762 const SkFontArguments& args) const {
763 return DWriteFontTypeface::MakeFromStream(std::move(stream), args);
764 }
765
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const766 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromData(sk_sp<SkData> data, int ttcIndex) const {
767 return this->makeFromStream(std::make_unique<SkMemoryStream>(std::move(data)), ttcIndex);
768 }
769
onMakeFromFile(const char path[],int ttcIndex) const770 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
771 return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
772 }
773
getByFamilyName(const WCHAR wideFamilyName[],IDWriteFontFamily ** fontFamily) const774 HRESULT SkFontMgr_DirectWrite::getByFamilyName(const WCHAR wideFamilyName[],
775 IDWriteFontFamily** fontFamily) const {
776 UINT32 index;
777 BOOL exists;
778 HR(fFontCollection->FindFamilyName(wideFamilyName, &index, &exists));
779
780 if (exists) {
781 HR(fFontCollection->GetFontFamily(index, fontFamily));
782 }
783 return S_OK;
784 }
785
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const786 sk_sp<SkTypeface> SkFontMgr_DirectWrite::onLegacyMakeTypeface(const char familyName[],
787 SkFontStyle style) const {
788 SkTScopedComPtr<IDWriteFontFamily> fontFamily;
789 DWriteStyle dwStyle(style);
790 if (familyName) {
791 SkSMallocWCHAR dwFamilyName;
792 if (SUCCEEDED(sk_cstring_to_wchar(familyName, &dwFamilyName))) {
793 this->getByFamilyName(dwFamilyName, &fontFamily);
794 if (!fontFamily && fFontFallback) {
795 return this->fallback(
796 dwFamilyName, dwStyle, fLocaleName.get(), 32);
797 }
798 }
799 }
800
801 if (!fontFamily) {
802 if (fFontFallback) {
803 return this->fallback(nullptr, dwStyle, fLocaleName.get(), 32);
804 }
805 // SPI_GETNONCLIENTMETRICS lfMessageFont can fail in Win8. (DisallowWin32kSystemCalls)
806 // layoutFallback causes DCHECK in Chromium. (Uses system font collection.)
807 HRNM(this->getByFamilyName(fDefaultFamilyName, &fontFamily),
808 "Could not create DWrite font family from LOGFONT.");
809 }
810
811 if (!fontFamily) {
812 // Could not obtain the default font.
813 HRNM(fFontCollection->GetFontFamily(0, &fontFamily),
814 "Could not get default-default font family.");
815 }
816
817 SkTScopedComPtr<IDWriteFont> font;
818 HRNM(FirstMatchingFontWithoutSimulations(fontFamily, dwStyle, font),
819 "No font found from family.");
820
821 SkTScopedComPtr<IDWriteFontFace> fontFace;
822 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
823
824 return this->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get());
825 }
826
827 ///////////////////////////////////////////////////////////////////////////////
828
count()829 int SkFontStyleSet_DirectWrite::count() {
830 return fFontFamily->GetFontCount();
831 }
832
createTypeface(int index)833 sk_sp<SkTypeface> SkFontStyleSet_DirectWrite::createTypeface(int index) {
834 SkTScopedComPtr<IDWriteFont> font;
835 HRNM(fFontFamily->GetFont(index, &font), "Could not get font.");
836
837 SkTScopedComPtr<IDWriteFontFace> fontFace;
838 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
839
840 return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
841 }
842
getStyle(int index,SkFontStyle * fs,SkString * styleName)843 void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) {
844 SkTScopedComPtr<IDWriteFont> font;
845 HRVM(fFontFamily->GetFont(index, &font), "Could not get font.");
846
847 if (fs) {
848 SkTScopedComPtr<IDWriteFontFace> face;
849 HRVM(font->CreateFontFace(&face), "Could not get face.");
850 *fs = DWriteFontTypeface::GetStyle(font.get(), face.get());
851 }
852
853 if (styleName) {
854 SkTScopedComPtr<IDWriteLocalizedStrings> faceNames;
855 if (SUCCEEDED(font->GetFaceNames(&faceNames))) {
856 sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName);
857 }
858 }
859 }
860
matchStyle(const SkFontStyle & pattern)861 sk_sp<SkTypeface> SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) {
862 SkTScopedComPtr<IDWriteFont> font;
863 DWriteStyle dwStyle(pattern);
864
865 HRNM(FirstMatchingFontWithoutSimulations(fFontFamily, dwStyle, font),
866 "No font found from family.");
867
868 SkTScopedComPtr<IDWriteFontFace> fontFace;
869 HRNM(font->CreateFontFace(&fontFace), "Could not create font face.");
870
871 return fFontMgr->makeTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get());
872 }
873
874 ////////////////////////////////////////////////////////////////////////////////
875 #include "include/ports/SkTypeface_win.h"
876
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection)877 sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
878 IDWriteFontCollection* collection) {
879 return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
880 }
881
SkFontMgr_New_DirectWrite(IDWriteFactory * factory,IDWriteFontCollection * collection,IDWriteFontFallback * fallback)882 sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
883 IDWriteFontCollection* collection,
884 IDWriteFontFallback* fallback) {
885 if (nullptr == factory) {
886 factory = sk_get_dwrite_factory();
887 if (nullptr == factory) {
888 return nullptr;
889 }
890 }
891
892 SkTScopedComPtr<IDWriteFontCollection> systemFontCollection;
893 if (nullptr == collection) {
894 HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE),
895 "Could not get system font collection.");
896 collection = systemFontCollection.get();
897 }
898
899 // It is possible to have been provided a font fallback when factory2 is not available.
900 SkTScopedComPtr<IDWriteFontFallback> systemFontFallback;
901 if (nullptr == fallback) {
902 SkTScopedComPtr<IDWriteFactory2> factory2;
903 if (!SUCCEEDED(factory->QueryInterface(&factory2))) {
904 // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
905 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
906 SkASSERT_RELEASE(nullptr == factory2.get());
907 } else {
908 HRNM(factory2->GetSystemFontFallback(&systemFontFallback),
909 "Could not get system fallback.");
910 fallback = systemFontFallback.get();
911 }
912 }
913
914 const WCHAR* defaultFamilyName = L"";
915 int defaultFamilyNameLen = 1;
916 NONCLIENTMETRICSW metrics;
917 metrics.cbSize = sizeof(metrics);
918
919 #ifndef SK_WINUWP
920 if (nullptr == fallback) {
921 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
922 defaultFamilyName = metrics.lfMessageFont.lfFaceName;
923 defaultFamilyNameLen = LF_FACESIZE;
924 }
925 }
926 #endif //SK_WINUWP
927
928 WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH];
929 const WCHAR* localeName = L"";
930 int localeNameLen = 1;
931
932 // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP.
933 SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr;
934 HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc);
935 if (nullptr == getUserDefaultLocaleNameProc) {
936 SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName.");
937 } else {
938 int size = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH);
939 if (size) {
940 localeName = localeNameStorage;
941 localeNameLen = size;
942 }
943 }
944
945 return sk_make_sp<SkFontMgr_DirectWrite>(factory, collection, fallback,
946 localeName, localeNameLen,
947 defaultFamilyName, defaultFamilyNameLen);
948 }
949
950 #endif//defined(SK_BUILD_FOR_WIN)
951