xref: /aosp_15_r20/external/skia/src/ports/SkTypeface_win_dw.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "src/base/SkLeanWindows.h"
13 
14 // SkLeanWindows will include Windows.h, which will pull in all of the GDI defines.
15 // GDI #defines GetGlyphIndices to GetGlyphIndicesA or GetGlyphIndicesW, but
16 // IDWriteFontFace has a method called GetGlyphIndices. Since this file does
17 // not use GDI, undefing GetGlyphIndices makes things less confusing.
18 #undef GetGlyphIndices
19 
20 #include "include/core/SkData.h"
21 #include "include/core/SkFontTypes.h"
22 #include "include/private/base/SkTo.h"
23 #include "src/core/SkFontDescriptor.h"
24 #include "src/core/SkFontStream.h"
25 #include "src/core/SkScalerContext.h"
26 #include "src/ports/SkScalerContext_win_dw.h"
27 #include "src/ports/SkTypeface_win_dw.h"
28 #include "src/sfnt/SkOTTable_OS_2.h"
29 #include "src/sfnt/SkOTTable_fvar.h"
30 #include "src/sfnt/SkOTTable_head.h"
31 #include "src/sfnt/SkOTTable_hhea.h"
32 #include "src/sfnt/SkOTTable_post.h"
33 #include "src/sfnt/SkOTUtils.h"
34 #include "src/utils/win/SkDWrite.h"
35 #include "src/utils/win/SkDWriteFontFileStream.h"
36 
37 using namespace skia_private;
38 
GetStyle(IDWriteFont * font,IDWriteFontFace * fontFace)39 SkFontStyle DWriteFontTypeface::GetStyle(IDWriteFont* font, IDWriteFontFace* fontFace) {
40     int weight = font->GetWeight();
41     int width = font->GetStretch();
42     SkFontStyle::Slant slant = SkFontStyle::kUpright_Slant;
43     switch (font->GetStyle()) {
44         case DWRITE_FONT_STYLE_NORMAL: slant = SkFontStyle::kUpright_Slant; break;
45         case DWRITE_FONT_STYLE_OBLIQUE: slant = SkFontStyle::kOblique_Slant; break;
46         case DWRITE_FONT_STYLE_ITALIC: slant = SkFontStyle::kItalic_Slant; break;
47         default: SkASSERT(false); break;
48     }
49 
50 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
51     [&weight, &width, &slant, fontFace]() -> void {
52         SkTScopedComPtr<IDWriteFontFace5> fontFace5;
53         if (FAILED(fontFace->QueryInterface(&fontFace5))) {
54             return;
55         }
56         if (!fontFace5->HasVariations()) {
57             return;
58         }
59 
60         UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
61         SkTScopedComPtr<IDWriteFontResource> fontResource;
62         HRV(fontFace5->GetFontResource(&fontResource));
63 
64         AutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
65         HRV(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount));
66         for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
67             if (fontAxisValue[axisIndex].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT) {
68                weight = fontAxisValue[axisIndex].value;
69             }
70             if (fontAxisValue[axisIndex].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH) {
71                 SkScalar wdthValue = fontAxisValue[axisIndex].value;
72                 width = SkFontDescriptor::SkFontStyleWidthForWidthAxisValue(wdthValue);
73             }
74             if (fontAxisValue[axisIndex].axisTag == DWRITE_FONT_AXIS_TAG_SLANT &&
75                 slant != SkFontStyle::kItalic_Slant)
76             {
77                 if (fontAxisValue[axisIndex].value == 0) {
78                     slant = SkFontStyle::kUpright_Slant;
79                 } else {
80                     slant = SkFontStyle::kOblique_Slant;
81                 }
82             }
83         }
84     }();
85 #endif
86     return SkFontStyle(weight, width, slant);
87 }
88 
Make(IDWriteFactory * factory,IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily,sk_sp<Loaders> loaders,const SkFontArguments::Palette & palette)89 sk_sp<DWriteFontTypeface> DWriteFontTypeface::Make(
90     IDWriteFactory* factory,
91     IDWriteFontFace* fontFace,
92     IDWriteFont* font,
93     IDWriteFontFamily* fontFamily,
94     sk_sp<Loaders> loaders,
95     const SkFontArguments::Palette& palette)
96 {
97     return sk_sp<DWriteFontTypeface>(new DWriteFontTypeface(
98         GetStyle(font, fontFace), factory, fontFace, font, fontFamily, std::move(loaders), palette));
99 }
100 
initializePalette()101 HRESULT DWriteFontTypeface::initializePalette() {
102     if (!fIsColorFont) {
103         return S_OK;
104     }
105 
106     UINT32 dwPaletteCount = fDWriteFontFace2->GetColorPaletteCount();
107     if (dwPaletteCount == 0) {
108         return S_OK;
109     }
110 
111     // Treat out of range palette index values as 0. Still apply overrides.
112     // https://www.w3.org/TR/css-fonts-4/#base-palette-desc
113     UINT32 basePaletteIndex = 0;
114     if (SkTFitsIn<UINT32>(fRequestedPalette.index) &&
115         SkTo<UINT32>(fRequestedPalette.index) < dwPaletteCount)
116     {
117         basePaletteIndex = fRequestedPalette.index;
118     }
119 
120     UINT32 dwPaletteEntryCount = fDWriteFontFace2->GetPaletteEntryCount();
121     AutoSTMalloc<8, DWRITE_COLOR_F> dwPaletteEntry(dwPaletteEntryCount);
122     HRM(fDWriteFontFace2->GetPaletteEntries(basePaletteIndex,
123                                             0, dwPaletteEntryCount,
124                                             dwPaletteEntry),
125         "Could not retrieve palette entries.");
126 
127     fPalette.reset(new SkColor[dwPaletteEntryCount]);
128     fDWPalette.reset(new DWRITE_COLOR_F[dwPaletteEntryCount]);
129     for (UINT32 i = 0; i < dwPaletteEntryCount; ++i) {
130         fPalette[i] = SkColorSetARGB(sk_float_round2int(dwPaletteEntry[i].a * 255),
131                                      sk_float_round2int(dwPaletteEntry[i].r * 255),
132                                      sk_float_round2int(dwPaletteEntry[i].g * 255),
133                                      sk_float_round2int(dwPaletteEntry[i].b * 255));
134         fDWPalette[i] = dwPaletteEntry[i];
135     }
136 
137     for (int i = 0; i < fRequestedPalette.overrideCount; ++i) {
138         const SkFontArguments::Palette::Override& paletteOverride = fRequestedPalette.overrides[i];
139         if (SkTFitsIn<UINT32>(paletteOverride.index) &&
140             SkTo<UINT32>(paletteOverride.index) < dwPaletteEntryCount)
141         {
142             fPalette[paletteOverride.index] = paletteOverride.color;
143 
144             // Avoid brace initialization as DWRITE_COLOR_F can be defined as four floats
145             // (dxgitype.h, d3d9types.h) or four unions of two floats (dwrite_2.h, d3dtypes.h).
146             // The type changed in Direct3D 10, but the change does not appear to be documented.
147             const SkColor4f skColor = SkColor4f::FromColor(paletteOverride.color);
148             DWRITE_COLOR_F& dwColor = fDWPalette[paletteOverride.index];
149             dwColor.r = skColor.fR;
150             dwColor.g = skColor.fG;
151             dwColor.b = skColor.fB;
152             dwColor.a = skColor.fA;
153         }
154     }
155     fPaletteEntryCount = dwPaletteEntryCount;
156 
157     return S_OK;
158 }
159 
DWriteFontTypeface(const SkFontStyle & style,IDWriteFactory * factory,IDWriteFontFace * fontFace,IDWriteFont * font,IDWriteFontFamily * fontFamily,sk_sp<Loaders> loaders,const SkFontArguments::Palette & palette)160 DWriteFontTypeface::DWriteFontTypeface(const SkFontStyle& style,
161                                        IDWriteFactory* factory,
162                                        IDWriteFontFace* fontFace,
163                                        IDWriteFont* font,
164                                        IDWriteFontFamily* fontFamily,
165                                        sk_sp<Loaders> loaders,
166                                        const SkFontArguments::Palette& palette)
167     : SkTypeface(style, false)
168     , fFactory(SkRefComPtr(factory))
169     , fDWriteFontFamily(SkRefComPtr(fontFamily))
170     , fDWriteFont(SkRefComPtr(font))
171     , fDWriteFontFace(SkRefComPtr(fontFace))
172     , fRequestedPaletteEntryOverrides(palette.overrideCount
173         ? (SkFontArguments::Palette::Override*)memcpy(
174              new SkFontArguments::Palette::Override[palette.overrideCount],
175              palette.overrides,
176              palette.overrideCount * sizeof(palette.overrides[0]))
177         : nullptr)
178     , fRequestedPalette{palette.index,
179                         fRequestedPaletteEntryOverrides.get(), palette.overrideCount }
180     , fPaletteEntryCount(0)
181     , fLoaders(std::move(loaders))
182 {
183     if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace1))) {
184         // IUnknown::QueryInterface states that if it fails, punk will be set to nullptr.
185         // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/26/96777.aspx
186         SkASSERT_RELEASE(nullptr == fDWriteFontFace1.get());
187     }
188     if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace2))) {
189         SkASSERT_RELEASE(nullptr == fDWriteFontFace2.get());
190     }
191     if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace4))) {
192         SkASSERT_RELEASE(nullptr == fDWriteFontFace4.get());
193     }
194 #if DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
195     if (!SUCCEEDED(fDWriteFontFace->QueryInterface(&fDWriteFontFace7))) {
196         SkASSERT_RELEASE(nullptr == fDWriteFontFace7/*.get()*/);
197     }
198 #endif
199     if (!SUCCEEDED(fFactory->QueryInterface(&fFactory2))) {
200         SkASSERT_RELEASE(nullptr == fFactory2.get());
201     }
202 
203     if (fDWriteFontFace1 && fDWriteFontFace1->IsMonospacedFont()) {
204         this->setIsFixedPitch(true);
205     }
206 
207     fIsColorFont = fFactory2 && fDWriteFontFace2 && fDWriteFontFace2->IsColorFont();
208     this->initializePalette();
209 }
210 
~DWriteFontTypeface()211 DWriteFontTypeface::~DWriteFontTypeface() {
212 #if DWRITE_CORE || (defined(NTDDI_WIN11_ZN) && NTDDI_VERSION >= NTDDI_WIN11_ZN)
213     if (fDWriteFontFace7) {
214         fDWriteFontFace7->Release();
215     }
216 #endif
217 }
218 
~Loaders()219 DWriteFontTypeface::Loaders::~Loaders() {
220     // Don't return if any fail, just keep going to free up as much as possible.
221     HRESULT hr;
222 
223     hr = fFactory->UnregisterFontCollectionLoader(fDWriteFontCollectionLoader.get());
224     if (FAILED(hr)) {
225         SK_TRACEHR(hr, "FontCollectionLoader");
226     }
227 
228     hr = fFactory->UnregisterFontFileLoader(fDWriteFontFileLoader.get());
229     if (FAILED(hr)) {
230         SK_TRACEHR(hr, "FontFileLoader");
231     }
232 }
233 
onGetFamilyName(SkString * familyName) const234 void DWriteFontTypeface::onGetFamilyName(SkString* familyName) const {
235     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
236     HRV(fDWriteFontFamily->GetFamilyNames(&familyNames));
237 
238     sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, familyName);
239 }
240 
onGetPostScriptName(SkString * skPostScriptName) const241 bool DWriteFontTypeface::onGetPostScriptName(SkString* skPostScriptName) const {
242     SkString localSkPostScriptName;
243     SkTScopedComPtr<IDWriteLocalizedStrings> postScriptNames;
244     BOOL exists = FALSE;
245     if (FAILED(fDWriteFont->GetInformationalStrings(
246                     DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
247                     &postScriptNames,
248                     &exists)) ||
249         !exists ||
250         FAILED(sk_get_locale_string(postScriptNames.get(), nullptr, &localSkPostScriptName)))
251     {
252         return false;
253     }
254     if (skPostScriptName) {
255         *skPostScriptName = localSkPostScriptName;
256     }
257     return true;
258 }
259 
onGetResourceName(SkString * resourceName) const260 int DWriteFontTypeface::onGetResourceName(SkString* resourceName) const {
261     UINT32 numFiles = 0;
262     HRZM(fDWriteFontFace->GetFiles(&numFiles, nullptr),
263          "Could not get number of font files.");
264     if (numFiles < 1 || !resourceName) {
265         return numFiles;
266     }
267 
268     auto fontFiles = std::make_unique<SkTScopedComPtr<IDWriteFontFile>[]>(numFiles);
269     HR_GENERAL(fDWriteFontFace->GetFiles(&numFiles, &fontFiles[0]),
270                "Could not get font files.", numFiles);
271 
272     IDWriteFontFile* fontFile = fontFiles[0].get();
273     const void* fontFileKey;
274     UINT32 fontFileKeySize;
275     HR_GENERAL(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
276                "Could not get font file reference key.", numFiles);
277 
278     SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
279     HR_GENERAL(fontFile->GetLoader(&fontFileLoader),
280                "Could not get font file loader.", numFiles);
281 
282     SkTScopedComPtr<IDWriteLocalFontFileLoader> localFontFileLoader;
283     HR_GENERAL(fontFileLoader->QueryInterface(&localFontFileLoader),
284                nullptr, numFiles);
285 
286     UINT32 fontFilePathLen;
287     HR_GENERAL(localFontFileLoader->GetFilePathLengthFromKey(fontFileKey, fontFileKeySize,
288                                                              &fontFilePathLen),
289                "Could not get file path length.", numFiles);
290 
291     SkSMallocWCHAR fontFilePath(static_cast<size_t>(fontFilePathLen)+1);
292     HR_GENERAL(localFontFileLoader->GetFilePathFromKey(fontFileKey, fontFileKeySize,
293                                                        fontFilePath, fontFilePathLen+1),
294                "Could not get file path.", numFiles);
295 
296     SkString localResourceName;
297     HR_GENERAL(sk_wchar_to_skstring(fontFilePath.get(), fontFilePathLen, &localResourceName),
298                nullptr, numFiles);
299     *resourceName = std::move(localResourceName);
300 
301     return numFiles;
302 }
303 
onGetFontDescriptor(SkFontDescriptor * desc,bool * serialize) const304 void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
305                                              bool* serialize) const {
306     // Get the family name.
307     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
308     HRV(fDWriteFontFamily->GetFamilyNames(&familyNames));
309 
310     SkString utf8FamilyName;
311     sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, &utf8FamilyName);
312 
313     desc->setFamilyName(utf8FamilyName.c_str());
314     desc->setStyle(this->fontStyle());
315 
316     desc->setPaletteIndex(fRequestedPalette.index);
317     sk_careful_memcpy(desc->setPaletteEntryOverrides(fRequestedPalette.overrideCount),
318                       fRequestedPalette.overrides,
319                       fRequestedPalette.overrideCount * sizeof(fRequestedPalette.overrides[0]));
320 
321     desc->setFactoryId(FactoryId);
322     *serialize = SkToBool(fLoaders);
323 }
324 
onCharsToGlyphs(const SkUnichar * uni,int count,SkGlyphID glyphs[]) const325 void DWriteFontTypeface::onCharsToGlyphs(const SkUnichar* uni, int count,
326                                          SkGlyphID glyphs[]) const {
327     fDWriteFontFace->GetGlyphIndices((const UINT32*)uni, count, glyphs);
328 }
329 
onCountGlyphs() const330 int DWriteFontTypeface::onCountGlyphs() const {
331     return fDWriteFontFace->GetGlyphCount();
332 }
333 
getPostScriptGlyphNames(SkString *) const334 void DWriteFontTypeface::getPostScriptGlyphNames(SkString*) const {}
335 
onGetUPEM() const336 int DWriteFontTypeface::onGetUPEM() const {
337     DWRITE_FONT_METRICS metrics;
338     fDWriteFontFace->GetMetrics(&metrics);
339     return metrics.designUnitsPerEm;
340 }
341 
342 class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
343 public:
344     /** Takes ownership of the IDWriteLocalizedStrings. */
LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings * strings)345     explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
346         : fIndex(0), fStrings(strings)
347     { }
348 
next(SkTypeface::LocalizedString * localizedString)349     bool next(SkTypeface::LocalizedString* localizedString) override {
350         if (fIndex >= fStrings->GetCount()) {
351             return false;
352         }
353 
354         // String
355         UINT32 stringLen;
356         HRBM(fStrings->GetStringLength(fIndex, &stringLen), "Could not get string length.");
357 
358         SkSMallocWCHAR wString(static_cast<size_t>(stringLen)+1);
359         HRBM(fStrings->GetString(fIndex, wString.get(), stringLen+1), "Could not get string.");
360 
361         HRB(sk_wchar_to_skstring(wString.get(), stringLen, &localizedString->fString));
362 
363         // Locale
364         UINT32 localeLen;
365         HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLen), "Could not get locale length.");
366 
367         SkSMallocWCHAR wLocale(static_cast<size_t>(localeLen)+1);
368         HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLen+1), "Could not get locale.");
369 
370         HRB(sk_wchar_to_skstring(wLocale.get(), localeLen, &localizedString->fLanguage));
371 
372         ++fIndex;
373         return true;
374     }
375 
376 private:
377     UINT32 fIndex;
378     SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
379 };
380 
onCreateFamilyNameIterator() const381 SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
382     sk_sp<SkTypeface::LocalizedStrings> nameIter =
383         SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
384     if (!nameIter) {
385         SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
386         HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
387         nameIter = sk_make_sp<LocalizedStrings_IDWriteLocalizedStrings>(familyNames.release());
388     }
389     return nameIter.release();
390 }
391 
onGlyphMaskNeedsCurrentColor() const392 bool DWriteFontTypeface::onGlyphMaskNeedsCurrentColor() const {
393     return fDWriteFontFace2 && fDWriteFontFace2->GetColorPaletteCount() > 0;
394 }
395 
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const396 int DWriteFontTypeface::onGetVariationDesignPosition(
397     SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
398 {
399 
400 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
401 
402     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
403     if (FAILED(fDWriteFontFace->QueryInterface(&fontFace5))) {
404         return -1;
405     }
406 
407     // Return 0 if the font is not variable font.
408     if (!fontFace5->HasVariations()) {
409         return 0;
410     }
411 
412     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
413     SkTScopedComPtr<IDWriteFontResource> fontResource;
414     HR_GENERAL(fontFace5->GetFontResource(&fontResource), nullptr, -1);
415     UINT32 variableAxisCount = 0;
416     for (UINT32 i = 0; i < fontAxisCount; ++i) {
417         if (fontResource->GetFontAxisAttributes(i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
418             ++variableAxisCount;
419         }
420     }
421 
422     if (!coordinates || coordinateCount < 0 || (unsigned)coordinateCount < variableAxisCount) {
423         return SkTo<int>(variableAxisCount);
424     }
425 
426     AutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
427     HR_GENERAL(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount), nullptr, -1);
428     UINT32 coordIndex = 0;
429     for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
430         if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
431             coordinates[coordIndex].axis = SkEndian_SwapBE32(fontAxisValue[axisIndex].axisTag);
432             coordinates[coordIndex].value = fontAxisValue[axisIndex].value;
433             ++coordIndex;
434         }
435     }
436 
437     SkASSERT(coordIndex == variableAxisCount);
438     return SkTo<int>(variableAxisCount);
439 
440 #else
441     return -1;
442 #endif
443 }
444 
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const445 int DWriteFontTypeface::onGetVariationDesignParameters(
446     SkFontParameters::Variation::Axis parameters[], int parameterCount) const
447 {
448 
449 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
450 
451     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
452     if (FAILED(fDWriteFontFace->QueryInterface(&fontFace5))) {
453         return -1;
454     }
455 
456     // Return 0 if the font is not variable font.
457     if (!fontFace5->HasVariations()) {
458         return 0;
459     }
460 
461     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
462     SkTScopedComPtr<IDWriteFontResource> fontResource;
463     HR_GENERAL(fontFace5->GetFontResource(&fontResource), nullptr, -1);
464     int variableAxisCount = 0;
465     for (UINT32 i = 0; i < fontAxisCount; ++i) {
466         if (fontResource->GetFontAxisAttributes(i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
467             variableAxisCount++;
468         }
469     }
470 
471     if (!parameters || parameterCount < variableAxisCount) {
472         return variableAxisCount;
473     }
474 
475     AutoSTMalloc<8, DWRITE_FONT_AXIS_RANGE> fontAxisRange(fontAxisCount);
476     HR_GENERAL(fontResource->GetFontAxisRanges(fontAxisRange.get(), fontAxisCount), nullptr, -1);
477     AutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisDefaultValue(fontAxisCount);
478     HR_GENERAL(fontResource->GetDefaultFontAxisValues(fontAxisDefaultValue.get(), fontAxisCount),
479                nullptr, -1);
480     UINT32 coordIndex = 0;
481 
482     for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
483         if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
484             parameters[coordIndex].tag = SkEndian_SwapBE32(fontAxisDefaultValue[axisIndex].axisTag);
485             parameters[coordIndex].min = fontAxisRange[axisIndex].minValue;
486             parameters[coordIndex].def = fontAxisDefaultValue[axisIndex].value;
487             parameters[coordIndex].max = fontAxisRange[axisIndex].maxValue;
488             parameters[coordIndex].setHidden(fontResource->GetFontAxisAttributes(axisIndex) &
489                                              DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN);
490             ++coordIndex;
491         }
492     }
493 
494     return variableAxisCount;
495 
496 #else
497     return -1;
498 #endif
499 }
500 
onGetTableTags(SkFontTableTag tags[]) const501 int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
502     DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
503     if (type != DWRITE_FONT_FACE_TYPE_CFF &&
504         type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
505         type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
506     {
507         return 0;
508     }
509 
510     int ttcIndex;
511     std::unique_ptr<SkStreamAsset> stream = this->openStream(&ttcIndex);
512     return stream.get() ? SkFontStream::GetTableTags(stream.get(), ttcIndex, tags) : 0;
513 }
514 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const515 size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
516                                           size_t length, void* data) const
517 {
518     AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
519     if (!table.fExists) {
520         return 0;
521     }
522 
523     if (offset > table.fSize) {
524         return 0;
525     }
526     size_t size = std::min(length, table.fSize - offset);
527     if (data) {
528         memcpy(data, table.fData + offset, size);
529     }
530 
531     return size;
532 }
533 
onCopyTableData(SkFontTableTag tag) const534 sk_sp<SkData> DWriteFontTypeface::onCopyTableData(SkFontTableTag tag) const {
535     const uint8_t* data;
536     UINT32 size;
537     void* lock;
538     BOOL exists;
539     fDWriteFontFace->TryGetFontTable(SkEndian_SwapBE32(tag),
540             reinterpret_cast<const void **>(&data), &size, &lock, &exists);
541     if (!exists) {
542         return nullptr;
543     }
544     struct Context {
545         Context(void* lock, IDWriteFontFace* face) : fLock(lock), fFontFace(SkRefComPtr(face)) {}
546         ~Context() { fFontFace->ReleaseFontTable(fLock); }
547         void* fLock;
548         SkTScopedComPtr<IDWriteFontFace> fFontFace;
549     };
550     return SkData::MakeWithProc(data, size,
551                                 [](const void*, void* ctx) { delete (Context*)ctx; },
552                                 new Context(lock, fDWriteFontFace.get()));
553 }
554 
onMakeClone(const SkFontArguments & args) const555 sk_sp<SkTypeface> DWriteFontTypeface::onMakeClone(const SkFontArguments& args) const {
556     // Skip if the current face index does not match the ttcIndex
557     if (fDWriteFontFace->GetIndex() != SkTo<UINT32>(args.getCollectionIndex())) {
558         return sk_ref_sp(this);
559     }
560 
561 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
562 
563     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
564 
565     if (SUCCEEDED(fDWriteFontFace->QueryInterface(&fontFace5)) && fontFace5->HasVariations()) {
566         UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
567         UINT32 argsCoordCount = args.getVariationDesignPosition().coordinateCount;
568         AutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
569         HRN(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount));
570 
571         for (UINT32 fontIndex = 0; fontIndex < fontAxisCount; ++fontIndex) {
572             for (UINT32 argsIndex = 0; argsIndex < argsCoordCount; ++argsIndex) {
573                 if (SkEndian_SwapBE32(fontAxisValue[fontIndex].axisTag) ==
574                     args.getVariationDesignPosition().coordinates[argsIndex].axis) {
575                     fontAxisValue[fontIndex].value =
576                         args.getVariationDesignPosition().coordinates[argsIndex].value;
577                 }
578             }
579         }
580         SkTScopedComPtr<IDWriteFontResource> fontResource;
581         HRN(fontFace5->GetFontResource(&fontResource));
582         SkTScopedComPtr<IDWriteFontFace5> newFontFace5;
583         HRN(fontResource->CreateFontFace(fDWriteFont->GetSimulations(),
584                                          fontAxisValue.get(),
585                                          fontAxisCount,
586                                          &newFontFace5));
587 
588         SkTScopedComPtr<IDWriteFontFace> newFontFace;
589         HRN(newFontFace5->QueryInterface(&newFontFace));
590         return DWriteFontTypeface::Make(fFactory.get(),
591                                         newFontFace.get(),
592                                         fDWriteFont.get(),
593                                         fDWriteFontFamily.get(),
594                                         fLoaders,
595                                         args.getPalette());
596     }
597 
598 #endif
599 
600     // If the palette args have changed, a new font will need to be created.
601     if (args.getPalette().index != fRequestedPalette.index ||
602         args.getPalette().overrideCount != fRequestedPalette.overrideCount ||
603         memcmp(args.getPalette().overrides, fRequestedPalette.overrides,
604                fRequestedPalette.overrideCount * sizeof(fRequestedPalette.overrides[0])))
605     {
606         return DWriteFontTypeface::Make(fFactory.get(),
607                                         fDWriteFontFace.get(),
608                                         fDWriteFont.get(),
609                                         fDWriteFontFamily.get(),
610                                         fLoaders,
611                                         args.getPalette());
612     }
613 
614     return sk_ref_sp(this);
615 }
616 
onOpenStream(int * ttcIndex) const617 std::unique_ptr<SkStreamAsset> DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
618     *ttcIndex = fDWriteFontFace->GetIndex();
619 
620     UINT32 numFiles = 0;
621     HRNM(fDWriteFontFace->GetFiles(&numFiles, nullptr),
622          "Could not get number of font files.");
623     if (numFiles != 1) {
624         return nullptr;
625     }
626 
627     SkTScopedComPtr<IDWriteFontFile> fontFile;
628     HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
629 
630     const void* fontFileKey;
631     UINT32 fontFileKeySize;
632     HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
633          "Could not get font file reference key.");
634 
635     SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
636     HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
637 
638     SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
639     HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
640                                              &fontFileStream),
641          "Could not create font file stream.");
642 
643     return std::unique_ptr<SkStreamAsset>(new SkDWriteFontFileStream(fontFileStream.get()));
644 }
645 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const646 std::unique_ptr<SkScalerContext> DWriteFontTypeface::onCreateScalerContext(
647     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
648 {
649     return std::make_unique<SkScalerContext_DW>(
650             sk_ref_sp(const_cast<DWriteFontTypeface*>(this)), effects, desc);
651 }
652 
onFilterRec(SkScalerContextRec * rec) const653 void DWriteFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
654     rec->useStrokeForFakeBold();
655 
656     if (rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) {
657         rec->fMaskFormat = SkMask::kA8_Format;
658         rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
659     }
660 
661     unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
662                                   SkScalerContext::kEmbolden_Flag |
663                                   SkScalerContext::kLCD_Vertical_Flag;
664     rec->fFlags &= ~flagsWeDontSupport;
665 
666     SkFontHinting h = rec->getHinting();
667     // DirectWrite2 allows for hinting to be turned off. Force everything else to normal.
668     if (h != SkFontHinting::kNone || !fFactory2 || !fDWriteFontFace2) {
669         h = SkFontHinting::kNormal;
670     }
671     rec->setHinting(h);
672 
673 #if defined(SK_FONT_HOST_USE_SYSTEM_SETTINGS)
674     IDWriteFactory* factory = sk_get_dwrite_factory();
675     if (factory != nullptr) {
676         SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
677         if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
678             float gamma = defaultRenderingParams->GetGamma();
679             rec->setDeviceGamma(gamma);
680             rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
681         }
682     }
683 #endif
684 }
685 
686 ///////////////////////////////////////////////////////////////////////////////
687 //PDF Support
688 
glyph_to_unicode_map(IDWriteFontFace * fontFace,DWRITE_UNICODE_RANGE range,UINT32 * remainingGlyphCount,UINT32 numGlyphs,SkUnichar * glyphToUnicode)689 static void glyph_to_unicode_map(IDWriteFontFace* fontFace, DWRITE_UNICODE_RANGE range,
690                                  UINT32* remainingGlyphCount, UINT32 numGlyphs,
691                                  SkUnichar* glyphToUnicode)
692 {
693     constexpr const int batchSize = 128;
694     UINT32 codepoints[batchSize];
695     UINT16 glyphs[batchSize];
696     for (UINT32 c = range.first; c <= range.last && *remainingGlyphCount != 0; c += batchSize) {
697         UINT32 numBatchedCodePoints = std::min<UINT32>(range.last - c + 1, batchSize);
698         for (UINT32 i = 0; i < numBatchedCodePoints; ++i) {
699             codepoints[i] = c + i;
700         }
701         HRVM(fontFace->GetGlyphIndices(codepoints, numBatchedCodePoints, glyphs),
702              "Failed to get glyph indexes.");
703         for (UINT32 i = 0; i < numBatchedCodePoints; ++i) {
704             UINT16 glyph = glyphs[i];
705             // Intermittent DW bug on Windows 10. See crbug.com/470146.
706             if (glyph >= numGlyphs) {
707                 return;
708             }
709             if (0 < glyph && glyphToUnicode[glyph] == 0) {
710                 glyphToUnicode[glyph] = c + i;  // Always use lowest-index unichar.
711                 --*remainingGlyphCount;
712             }
713         }
714     }
715 }
716 
getGlyphToUnicodeMap(SkUnichar * glyphToUnicode) const717 void DWriteFontTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
718     IDWriteFontFace* face = fDWriteFontFace.get();
719     UINT32 numGlyphs = face->GetGlyphCount();
720     sk_bzero(glyphToUnicode, sizeof(SkUnichar) * numGlyphs);
721     UINT32 remainingGlyphCount = numGlyphs;
722 
723     if (fDWriteFontFace1) {
724         IDWriteFontFace1* face1 = fDWriteFontFace1.get();
725         UINT32 numRanges = 0;
726         HRESULT hr = face1->GetUnicodeRanges(0, nullptr, &numRanges);
727         if (hr != E_NOT_SUFFICIENT_BUFFER && FAILED(hr)) {
728             HRVM(hr, "Failed to get number of ranges.");
729         }
730         std::unique_ptr<DWRITE_UNICODE_RANGE[]> ranges(new DWRITE_UNICODE_RANGE[numRanges]);
731         HRVM(face1->GetUnicodeRanges(numRanges, ranges.get(), &numRanges), "Failed to get ranges.");
732         for (UINT32 i = 0; i < numRanges; ++i) {
733             glyph_to_unicode_map(face1, ranges[i], &remainingGlyphCount, numGlyphs, glyphToUnicode);
734         }
735     } else {
736         glyph_to_unicode_map(face, {0, 0x10FFFF}, &remainingGlyphCount, numGlyphs, glyphToUnicode);
737     }
738 }
739 
onGetAdvancedMetrics() const740 std::unique_ptr<SkAdvancedTypefaceMetrics> DWriteFontTypeface::onGetAdvancedMetrics() const {
741 
742     std::unique_ptr<SkAdvancedTypefaceMetrics> info(nullptr);
743 
744     DWRITE_FONT_METRICS dwfm;
745     fDWriteFontFace->GetMetrics(&dwfm);
746 
747     info.reset(new SkAdvancedTypefaceMetrics);
748 
749     info->fAscent = SkToS16(dwfm.ascent);
750     info->fDescent = SkToS16(dwfm.descent);
751     info->fCapHeight = SkToS16(dwfm.capHeight);
752 
753     {
754         SkTScopedComPtr<IDWriteLocalizedStrings> postScriptNames;
755         BOOL exists = FALSE;
756         if (FAILED(fDWriteFont->GetInformationalStrings(
757                         DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
758                         &postScriptNames,
759                         &exists)) ||
760             !exists ||
761             FAILED(sk_get_locale_string(postScriptNames.get(), nullptr, &info->fPostScriptName)))
762         {
763             SkDEBUGF("Unable to get postscript name for typeface %p\n", this);
764         }
765     }
766 
767     DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
768     if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
769         fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
770     {
771         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
772     } else if (fontType == DWRITE_FONT_FACE_TYPE_CFF ||
773                fontType == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION)
774     {
775         info->fType = SkAdvancedTypefaceMetrics::kCFF_Font;
776     } else {
777         return info;
778     }
779 
780     // Simulated fonts aren't really OpenType fonts.
781     if (fDWriteFontFace->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
782         info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
783     }
784 
785     AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
786     AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
787     AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
788     AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
789     if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
790         return info;
791     }
792 
793     SkOTUtils::SetAdvancedTypefaceFlags(os2Table->version.v4.fsType, info.get());
794 
795     // There are versions of DirectWrite which support named instances for system variation fonts,
796     // but no means to indicate that such a typeface is a variation.
797     AutoTDWriteTable<SkOTTableFontVariations> fvarTable(fDWriteFontFace.get());
798     if (fvarTable.fExists) {
799         info->fFlags |= SkAdvancedTypefaceMetrics::kVariable_FontFlag;
800     }
801 
802     //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
803     //but have full width, latin half-width, and half-width kana.
804     bool fixedWidth = (postTable->isFixedPitch &&
805                       (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
806     //Monospace
807     if (fixedWidth) {
808         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
809     }
810     //Italic
811     if (os2Table->version.v0.fsSelection.field.Italic) {
812         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
813     }
814     //Serif
815     using SerifStyle = SkPanose::Data::TextAndDisplay::SerifStyle;
816     SerifStyle serifStyle = os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle;
817     if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType) {
818         if (SerifStyle::Cove == serifStyle ||
819             SerifStyle::ObtuseCove == serifStyle ||
820             SerifStyle::SquareCove == serifStyle ||
821             SerifStyle::ObtuseSquareCove == serifStyle ||
822             SerifStyle::Square == serifStyle ||
823             SerifStyle::Thin == serifStyle ||
824             SerifStyle::Bone == serifStyle ||
825             SerifStyle::Exaggerated == serifStyle ||
826             SerifStyle::Triangle == serifStyle)
827         {
828             info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
829         }
830     //Script
831     } else if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType) {
832         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
833     }
834 
835     info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
836 
837     info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
838                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
839                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
840                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
841     return info;
842 }
843 
844 class StreamFontFileLoader : public IDWriteFontFileLoader {
845 public:
846     // IUnknown methods
847     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
848     SK_STDMETHODIMP_(ULONG) AddRef() override;
849     SK_STDMETHODIMP_(ULONG) Release() override;
850 
851     // IDWriteFontFileLoader methods
852     SK_STDMETHODIMP CreateStreamFromKey(
853         void const* fontFileReferenceKey,
854         UINT32 fontFileReferenceKeySize,
855         IDWriteFontFileStream** fontFileStream) override;
856 
857     // Takes ownership of stream.
Create(std::unique_ptr<SkStreamAsset> stream,StreamFontFileLoader ** streamFontFileLoader)858     static HRESULT Create(std::unique_ptr<SkStreamAsset> stream,
859         StreamFontFileLoader** streamFontFileLoader) {
860         *streamFontFileLoader = new StreamFontFileLoader(std::move(stream));
861         if (nullptr == *streamFontFileLoader) {
862             return E_OUTOFMEMORY;
863         }
864         return S_OK;
865     }
866 
867 private:
StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)868     StreamFontFileLoader(std::unique_ptr<SkStreamAsset> stream)
869         : fStream(std::move(stream)), fRefCount(1)
870     {}
~StreamFontFileLoader()871     virtual ~StreamFontFileLoader() { }
872 
873     std::unique_ptr<SkStreamAsset> fStream;
874     ULONG fRefCount;
875 };
876 
QueryInterface(REFIID iid,void ** ppvObject)877 SK_STDMETHODIMP StreamFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) {
878     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
879         *ppvObject = this;
880         AddRef();
881         return S_OK;
882     } else {
883         *ppvObject = nullptr;
884         return E_NOINTERFACE;
885     }
886 }
887 
SK_STDMETHODIMP_(ULONG)888 SK_STDMETHODIMP_(ULONG) StreamFontFileLoader::AddRef() {
889     return InterlockedIncrement(&fRefCount);
890 }
891 
SK_STDMETHODIMP_(ULONG)892 SK_STDMETHODIMP_(ULONG) StreamFontFileLoader::Release() {
893     ULONG newCount = InterlockedDecrement(&fRefCount);
894     if (0 == newCount) {
895         delete this;
896     }
897     return newCount;
898 }
899 
CreateStreamFromKey(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize,IDWriteFontFileStream ** fontFileStream)900 SK_STDMETHODIMP StreamFontFileLoader::CreateStreamFromKey(
901     void const* fontFileReferenceKey,
902     UINT32 fontFileReferenceKeySize,
903     IDWriteFontFileStream** fontFileStream)
904 {
905     SkTScopedComPtr<SkDWriteFontFileStreamWrapper> stream;
906     HR(SkDWriteFontFileStreamWrapper::Create(fStream->duplicate().release(), &stream));
907     *fontFileStream = stream.release();
908     return S_OK;
909 }
910 
911 class StreamFontFileEnumerator : public IDWriteFontFileEnumerator {
912 public:
913     // IUnknown methods
914     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
915     SK_STDMETHODIMP_(ULONG) AddRef() override;
916     SK_STDMETHODIMP_(ULONG) Release() override;
917 
918     // IDWriteFontFileEnumerator methods
919     SK_STDMETHODIMP MoveNext(BOOL* hasCurrentFile) override;
920     SK_STDMETHODIMP GetCurrentFontFile(IDWriteFontFile** fontFile) override;
921 
Create(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader,StreamFontFileEnumerator ** streamFontFileEnumerator)922     static HRESULT Create(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader,
923         StreamFontFileEnumerator** streamFontFileEnumerator) {
924         *streamFontFileEnumerator = new StreamFontFileEnumerator(factory, fontFileLoader);
925         if (nullptr == *streamFontFileEnumerator) {
926             return E_OUTOFMEMORY;
927         }
928         return S_OK;
929     }
930 private:
931     StreamFontFileEnumerator(IDWriteFactory* factory, IDWriteFontFileLoader* fontFileLoader);
~StreamFontFileEnumerator()932     virtual ~StreamFontFileEnumerator() { }
933 
934     ULONG fRefCount;
935 
936     SkTScopedComPtr<IDWriteFactory> fFactory;
937     SkTScopedComPtr<IDWriteFontFile> fCurrentFile;
938     SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
939     bool fHasNext;
940 };
941 
StreamFontFileEnumerator(IDWriteFactory * factory,IDWriteFontFileLoader * fontFileLoader)942 StreamFontFileEnumerator::StreamFontFileEnumerator(IDWriteFactory* factory,
943     IDWriteFontFileLoader* fontFileLoader)
944     : fRefCount(1)
945     , fFactory(SkRefComPtr(factory))
946     , fCurrentFile()
947     , fFontFileLoader(SkRefComPtr(fontFileLoader))
948     , fHasNext(true)
949 { }
950 
QueryInterface(REFIID iid,void ** ppvObject)951 SK_STDMETHODIMP StreamFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject) {
952     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator)) {
953         *ppvObject = this;
954         AddRef();
955         return S_OK;
956     } else {
957         *ppvObject = nullptr;
958         return E_NOINTERFACE;
959     }
960 }
961 
SK_STDMETHODIMP_(ULONG)962 SK_STDMETHODIMP_(ULONG) StreamFontFileEnumerator::AddRef() {
963     return InterlockedIncrement(&fRefCount);
964 }
965 
SK_STDMETHODIMP_(ULONG)966 SK_STDMETHODIMP_(ULONG) StreamFontFileEnumerator::Release() {
967     ULONG newCount = InterlockedDecrement(&fRefCount);
968     if (0 == newCount) {
969         delete this;
970     }
971     return newCount;
972 }
973 
MoveNext(BOOL * hasCurrentFile)974 SK_STDMETHODIMP StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
975     *hasCurrentFile = FALSE;
976 
977     if (!fHasNext) {
978         return S_OK;
979     }
980     fHasNext = false;
981 
982     UINT32 fontFileReferenceKey = 0;
983     HR(fFactory->CreateCustomFontFileReference(
984         &fontFileReferenceKey, //cannot be nullptr
985         sizeof(fontFileReferenceKey), //even if this is 0
986         fFontFileLoader.get(),
987         &fCurrentFile));
988 
989     *hasCurrentFile = TRUE;
990     return S_OK;
991 }
992 
GetCurrentFontFile(IDWriteFontFile ** fontFile)993 SK_STDMETHODIMP StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) {
994     if (fCurrentFile.get() == nullptr) {
995         *fontFile = nullptr;
996         return E_FAIL;
997     }
998 
999     *fontFile = SkRefComPtr(fCurrentFile.get());
1000     return  S_OK;
1001 }
1002 
1003 class StreamFontCollectionLoader : public IDWriteFontCollectionLoader {
1004 public:
1005     // IUnknown methods
1006     SK_STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override;
1007     SK_STDMETHODIMP_(ULONG) AddRef() override;
1008     SK_STDMETHODIMP_(ULONG) Release() override;
1009 
1010     // IDWriteFontCollectionLoader methods
1011     SK_STDMETHODIMP CreateEnumeratorFromKey(
1012         IDWriteFactory* factory,
1013         void const* collectionKey,
1014         UINT32 collectionKeySize,
1015         IDWriteFontFileEnumerator** fontFileEnumerator) override;
1016 
Create(IDWriteFontFileLoader * fontFileLoader,StreamFontCollectionLoader ** streamFontCollectionLoader)1017     static HRESULT Create(IDWriteFontFileLoader* fontFileLoader,
1018         StreamFontCollectionLoader** streamFontCollectionLoader) {
1019         *streamFontCollectionLoader = new StreamFontCollectionLoader(fontFileLoader);
1020         if (nullptr == *streamFontCollectionLoader) {
1021             return E_OUTOFMEMORY;
1022         }
1023         return S_OK;
1024     }
1025 private:
StreamFontCollectionLoader(IDWriteFontFileLoader * fontFileLoader)1026     StreamFontCollectionLoader(IDWriteFontFileLoader* fontFileLoader)
1027         : fRefCount(1)
1028         , fFontFileLoader(SkRefComPtr(fontFileLoader))
1029     { }
~StreamFontCollectionLoader()1030     virtual ~StreamFontCollectionLoader() { }
1031 
1032     ULONG fRefCount;
1033     SkTScopedComPtr<IDWriteFontFileLoader> fFontFileLoader;
1034 };
1035 
QueryInterface(REFIID iid,void ** ppvObject)1036 SK_STDMETHODIMP StreamFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject) {
1037     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader)) {
1038         *ppvObject = this;
1039         AddRef();
1040         return S_OK;
1041     } else {
1042         *ppvObject = nullptr;
1043         return E_NOINTERFACE;
1044     }
1045 }
1046 
SK_STDMETHODIMP_(ULONG)1047 SK_STDMETHODIMP_(ULONG) StreamFontCollectionLoader::AddRef() {
1048     return InterlockedIncrement(&fRefCount);
1049 }
1050 
SK_STDMETHODIMP_(ULONG)1051 SK_STDMETHODIMP_(ULONG) StreamFontCollectionLoader::Release() {
1052     ULONG newCount = InterlockedDecrement(&fRefCount);
1053     if (0 == newCount) {
1054         delete this;
1055     }
1056     return newCount;
1057 }
1058 
1059 template <typename T> class SkAutoIDWriteUnregister {
1060 public:
SkAutoIDWriteUnregister(IDWriteFactory * factory,T * unregister)1061     SkAutoIDWriteUnregister(IDWriteFactory* factory, T* unregister)
1062         : fFactory(factory), fUnregister(unregister)
1063     { }
1064     SkAutoIDWriteUnregister(const SkAutoIDWriteUnregister&) = delete;
1065     SkAutoIDWriteUnregister& operator=(const SkAutoIDWriteUnregister&) = delete;
1066     SkAutoIDWriteUnregister(SkAutoIDWriteUnregister&&) = delete;
1067     SkAutoIDWriteUnregister& operator=(SkAutoIDWriteUnregister&&) = delete;
1068 
~SkAutoIDWriteUnregister()1069     ~SkAutoIDWriteUnregister() {
1070         if (fUnregister) {
1071             unregister(fFactory, fUnregister);
1072         }
1073     }
1074 
detatch()1075     T* detatch() {
1076         T* old = fUnregister;
1077         fUnregister = nullptr;
1078         return old;
1079     }
1080 
1081 private:
unregister(IDWriteFactory * factory,IDWriteFontFileLoader * unregister)1082     HRESULT unregister(IDWriteFactory* factory, IDWriteFontFileLoader* unregister) {
1083         return factory->UnregisterFontFileLoader(unregister);
1084     }
1085 
unregister(IDWriteFactory * factory,IDWriteFontCollectionLoader * unregister)1086     HRESULT unregister(IDWriteFactory* factory, IDWriteFontCollectionLoader* unregister) {
1087         return factory->UnregisterFontCollectionLoader(unregister);
1088     }
1089 
1090     IDWriteFactory* fFactory;
1091     T* fUnregister;
1092 };
1093 
CreateEnumeratorFromKey(IDWriteFactory * factory,void const * collectionKey,UINT32 collectionKeySize,IDWriteFontFileEnumerator ** fontFileEnumerator)1094 SK_STDMETHODIMP StreamFontCollectionLoader::CreateEnumeratorFromKey(
1095     IDWriteFactory* factory,
1096     void const* collectionKey,
1097     UINT32 collectionKeySize,
1098     IDWriteFontFileEnumerator** fontFileEnumerator)
1099 {
1100     SkTScopedComPtr<StreamFontFileEnumerator> enumerator;
1101     HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator));
1102     *fontFileEnumerator = enumerator.release();
1103     return S_OK;
1104 }
1105 
apply_fontargument_variation(SkTScopedComPtr<IDWriteFontFace> & fontFace,const SkFontArguments & args)1106 static HRESULT apply_fontargument_variation(SkTScopedComPtr<IDWriteFontFace>& fontFace,
1107     const SkFontArguments& args)
1108 {
1109 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
1110 
1111     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
1112     if (FAILED(fontFace->QueryInterface(&fontFace5)) || !fontFace5->HasVariations()) {
1113         return S_OK;
1114     }
1115 
1116     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
1117     UINT32 argsCoordCount = args.getVariationDesignPosition().coordinateCount;
1118     AutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> variation(fontAxisCount);
1119     SkTScopedComPtr<IDWriteFontResource> fontResource;
1120     HR(fontFace5->GetFontResource(&fontResource));
1121     HR(fontResource->GetDefaultFontAxisValues(variation, fontAxisCount));
1122 
1123     for (UINT32 fontAxisIndex = 0; fontAxisIndex < fontAxisCount; ++fontAxisIndex) {
1124         DWRITE_FONT_AXIS_VALUE& fontCoordinate = variation[fontAxisIndex];
1125 
1126         for (UINT32 argsCoordIndex = argsCoordCount; argsCoordIndex --> 0;) {
1127             const SkFontArguments::VariationPosition::Coordinate& argsCoordinate =
1128                 args.getVariationDesignPosition().coordinates[argsCoordIndex];
1129             if (SkEndian_SwapBE32(fontCoordinate.axisTag) == argsCoordinate.axis) {
1130                 fontCoordinate.value = argsCoordinate.value;
1131                 break;
1132             }
1133         }
1134     }
1135 
1136     SkTScopedComPtr<IDWriteFontFace5> fontFace5_Out;
1137     HR(fontResource->CreateFontFace(DWRITE_FONT_SIMULATIONS_NONE,
1138         variation.get(), fontAxisCount,
1139         &fontFace5_Out));
1140     fontFace.reset();
1141     HR(fontFace5_Out->QueryInterface(&fontFace));
1142 #endif
1143     return S_OK;
1144 }
1145 
MakeFromStream(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args)1146 sk_sp<SkTypeface> DWriteFontTypeface::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
1147                                                      const SkFontArguments& args) {
1148     // TODO: do we need to use some user provided factory?
1149     IDWriteFactory* factory = sk_get_dwrite_factory();
1150     if (nullptr == factory) {
1151         return nullptr;
1152     }
1153 
1154     SkTScopedComPtr<StreamFontFileLoader> fontFileLoader;
1155     HRN(StreamFontFileLoader::Create(std::move(stream), &fontFileLoader));
1156     HRN(factory->RegisterFontFileLoader(fontFileLoader.get()));
1157     SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader(
1158         factory, fontFileLoader.get());
1159 
1160     SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader;
1161     HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader));
1162     HRN(factory->RegisterFontCollectionLoader(fontCollectionLoader.get()));
1163     SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader(
1164         factory, fontCollectionLoader.get());
1165 
1166     SkTScopedComPtr<IDWriteFontCollection> fontCollection;
1167     HRN(factory->CreateCustomFontCollection(fontCollectionLoader.get(), nullptr, 0,
1168         &fontCollection));
1169 
1170     // Find the first non-simulated font which has the given ttc index.
1171     UINT32 familyCount = fontCollection->GetFontFamilyCount();
1172     for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) {
1173         SkTScopedComPtr<IDWriteFontFamily> fontFamily;
1174         HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily));
1175 
1176         UINT32 fontCount = fontFamily->GetFontCount();
1177         for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
1178             SkTScopedComPtr<IDWriteFont> font;
1179             HRN(fontFamily->GetFont(fontIndex, &font));
1180 
1181             // Skip if the current font is simulated
1182             if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
1183                 continue;
1184             }
1185             SkTScopedComPtr<IDWriteFontFace> fontFace;
1186             HRN(font->CreateFontFace(&fontFace));
1187             int faceIndex = fontFace->GetIndex();
1188             int ttcIndex = args.getCollectionIndex();
1189 
1190             // Skip if the current face index does not match the ttcIndex
1191             if (faceIndex != ttcIndex) {
1192                 continue;
1193             }
1194 
1195             apply_fontargument_variation(fontFace, args);
1196 
1197             return DWriteFontTypeface::Make(
1198                 factory, fontFace.get(), font.get(), fontFamily.get(),
1199                 sk_make_sp<DWriteFontTypeface::Loaders>(
1200                     factory,
1201                     autoUnregisterFontFileLoader.detatch(),
1202                     autoUnregisterFontCollectionLoader.detatch()),
1203                 args.getPalette());
1204         }
1205     }
1206 
1207     return nullptr;
1208 }
1209 
1210 #endif//defined(SK_BUILD_FOR_WIN)
1211