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