Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkFontMgr_win_dw.cpp
Go to the documentation of this file.
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 */
8
10#if defined(SK_BUILD_FOR_WIN)
11
18#include "src/base/SkEndian.h"
19#include "src/base/SkUTF.h"
28
29#include <dwrite.h>
30#include <dwrite_2.h>
31#include <dwrite_3.h>
32
33using namespace skia_private;
34
35namespace {
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
43bool 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().
58HRESULT 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
97class SkFontMgr_DirectWrite : public SkFontMgr {
98public:
99 /** localeNameLength and defaultFamilyNameLength must include the null terminator. */
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
114protected:
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
130private:
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
154class SkFontStyleSet_DirectWrite : public SkFontStyleSet {
155public:
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
167private:
169 SkTScopedComPtr<IDWriteFontFamily> fFontFamily;
170};
171
172static 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
183struct ProtoDWriteTypeface {
184 IDWriteFontFace* fDWriteFontFace;
185 IDWriteFont* fDWriteFont;
186 IDWriteFontFamily* fDWriteFontFamily;
187};
188
189static 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
293sk_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
310int SkFontMgr_DirectWrite::onCountFamilies() const {
311 return fFontCollection->GetFontFamilyCount();
312}
313
314void 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
324sk_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
331sk_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
350sk_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
356class FontFallbackRenderer : public IDWriteTextRenderer {
357public:
358 FontFallbackRenderer(const SkFontMgr_DirectWrite* outer, UINT32 character)
359 : fRefCount(1), fOuter(SkSafeRef(outer)), fCharacter(character), fResolvedTypeface(nullptr) {
360 }
361
362 // IUnknown methods
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
376 SK_STDMETHODIMP_(ULONG) AddRef() override {
377 return InterlockedIncrement(&fRefCount);
378 }
379
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
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
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
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
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
452 SK_STDMETHODIMP IsPixelSnappingDisabled(
453 void* clientDrawingContext,
454 BOOL* isDisabled) override
455 {
456 *isDisabled = FALSE;
457 return S_OK;
458 }
459
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
469 SK_STDMETHODIMP GetPixelsPerDip(
470 void* clientDrawingContext,
471 FLOAT* pixelsPerDip) override
472 {
473 *pixelsPerDip = 1.0f;
474 return S_OK;
475 }
476
477 sk_sp<SkTypeface> ConsumeFallbackTypeface() { return std::move(fResolvedTypeface); }
478
479 bool FallbackTypefaceHasSimulations() { return fHasSimulations; }
480
481private:
482 virtual ~FontFallbackRenderer() { }
483
484 ULONG fRefCount;
486 UINT32 fCharacter;
487 sk_sp<SkTypeface> fResolvedTypeface;
488 bool fHasSimulations{false};
489};
490
491class FontFallbackSource : public IDWriteTextAnalysisSource {
492public:
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
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
515 SK_STDMETHODIMP_(ULONG) AddRef() override {
516 return InterlockedIncrement(&fRefCount);
517 }
518
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
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
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
558 SK_STDMETHODIMP_(DWRITE_READING_DIRECTION) GetParagraphReadingDirection() override {
559 // TODO: this is also interesting.
560 return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
561 }
562
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
572 SK_STDMETHODIMP GetNumberSubstitution(
573 UINT32 textPosition,
574 UINT32* textLength,
575 IDWriteNumberSubstitution** numberSubstitution) override
576 {
577 *numberSubstitution = fNumberSubstitution;
578 return S_OK;
579 }
580
581private:
582 virtual ~FontFallbackSource() { }
583
584 ULONG fRefCount;
585 const WCHAR* fString;
586 UINT32 fLength;
587 const WCHAR* fLocale;
588 IDWriteNumberSubstitution* fNumberSubstitution;
589};
590
591sk_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
625sk_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
693sk_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
754sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
755 int ttcIndex) const {
757 args.setCollectionIndex(ttcIndex);
758 return this->onMakeFromStreamArgs(std::move(stream), args);
759}
760
761sk_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
766sk_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
770sk_sp<SkTypeface> SkFontMgr_DirectWrite::onMakeFromFile(const char path[], int ttcIndex) const {
771 return this->makeFromStream(SkStream::MakeFromFile(path), ttcIndex);
772}
773
774HRESULT 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
786sk_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
829int SkFontStyleSet_DirectWrite::count() {
830 return fFontFamily->GetFontCount();
831}
832
833sk_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
843void 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
861sk_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////////////////////////////////////////////////////////////////////////////////
876
877sk_sp<SkFontMgr> SkFontMgr_New_DirectWrite(IDWriteFactory* factory,
878 IDWriteFontCollection* collection) {
879 return SkFontMgr_New_DirectWrite(factory, collection, nullptr);
880}
881
882sk_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)
#define SkASSERT_RELEASE(cond)
Definition SkAssert.h:100
HRESULT sk_get_locale_string(IDWriteLocalizedStrings *names, const WCHAR *preferedLocale, SkString *skname)
int(WINAPI * SkGetUserDefaultLocaleNameProc)(LPWSTR, int)
Definition SkDWrite.h:44
HRESULT sk_cstring_to_wchar(const char *skname, SkSMallocWCHAR *name)
HRESULT SkGetGetUserDefaultLocaleNameProc(SkGetUserDefaultLocaleNameProc *proc)
IDWriteFactory * sk_get_dwrite_factory()
#define SkEndian_SwapBE32(n)
Definition SkEndian.h:136
#define SK_STDMETHODIMP_(type)
Definition SkObjBase.h:23
#define SK_STDMETHODIMP
Definition SkObjBase.h:22
static T * SkSafeRef(T *obj)
Definition SkRefCnt.h:140
static T * SkRef(T *obj)
Definition SkRefCnt.h:132
int32_t SkUnichar
Definition SkTypes.h:175
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
static sk_sp< SkTypeface > SK_SPI MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
static SkFontStyle GetStyle(IDWriteFont *font, IDWriteFontFace *fontFace)
SkTScopedComPtr< IDWriteFontFamily > fDWriteFontFamily
SkTScopedComPtr< IDWriteFontFace > fDWriteFontFace
SkTScopedComPtr< IDWriteFont > fDWriteFont
static sk_sp< DWriteFontTypeface > Make(IDWriteFactory *factory, IDWriteFontFace *fontFace, IDWriteFont *font, IDWriteFontFamily *fontFamily, sk_sp< Loaders > loaders, const SkFontArguments::Palette &palette)
virtual void onGetFamilyName(int index, SkString *familyName) const =0
virtual sk_sp< SkTypeface > onMakeFromData(sk_sp< SkData >, int ttcIndex) const =0
virtual sk_sp< SkFontStyleSet > onCreateStyleSet(int index) const =0
virtual sk_sp< SkTypeface > onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle &, const char *bcp47[], int bcp47Count, SkUnichar character) const =0
virtual sk_sp< SkFontStyleSet > onMatchFamily(const char familyName[]) const =0
virtual sk_sp< SkTypeface > onMakeFromStreamIndex(std::unique_ptr< SkStreamAsset >, int ttcIndex) const =0
virtual sk_sp< SkTypeface > onMakeFromStreamArgs(std::unique_ptr< SkStreamAsset >, const SkFontArguments &) const =0
virtual sk_sp< SkTypeface > onMatchFamilyStyle(const char familyName[], const SkFontStyle &) const =0
virtual sk_sp< SkTypeface > onLegacyMakeTypeface(const char familyName[], SkFontStyle) const =0
virtual sk_sp< SkTypeface > onMakeFromFile(const char path[], int ttcIndex) const =0
virtual int onCountFamilies() const =0
virtual sk_sp< SkTypeface > createTypeface(int index)=0
virtual sk_sp< SkTypeface > matchStyle(const SkFontStyle &pattern)=0
virtual int count()=0
virtual void getStyle(int index, SkFontStyle *, SkString *style)=0
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
Definition SkStream.cpp:922
sk_sp< SkFontMgr > fontMgr
Definition examples.cpp:32
static bool b
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
size_t length
return FALSE
SK_SPI size_t ToUTF16(SkUnichar uni, uint16_t utf16[2]=nullptr)
Definition SkUTF.cpp:243
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port fallback
Definition switches.h:154
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
font
Font Metadata and Metrics.
const myers::Point & get(const myers::Segment &)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47
const Scalar scale
DWRITE_FONT_WEIGHT fWeight
Definition SkDWrite.h:94
DWRITE_FONT_STRETCH fWidth
Definition SkDWrite.h:95
DWRITE_FONT_STYLE fSlant
Definition SkDWrite.h:96
SkFontArguments & setCollectionIndex(int collectionIndex)
int BOOL
#define SUCCEEDED(hr)
DWORD ULONG