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 // SkTypes will include Windows.h, which will pull in all of the GDI defines.
13 // GDI #defines GetGlyphIndices to GetGlyphIndicesA or GetGlyphIndicesW, but
14 // IDWriteFontFace has a method called GetGlyphIndices. Since this file does
15 // not use GDI, undefing GetGlyphIndices makes things less confusing.
16 #undef GetGlyphIndices
17 
18 #include "include/core/SkData.h"
19 #include "include/private/SkTo.h"
20 #include "src/core/SkFontDescriptor.h"
21 #include "src/core/SkFontStream.h"
22 #include "src/core/SkScalerContext.h"
23 #include "src/core/SkUtils.h"
24 #include "src/ports/SkScalerContext_win_dw.h"
25 #include "src/ports/SkTypeface_win_dw.h"
26 #include "src/sfnt/SkOTTable_OS_2.h"
27 #include "src/sfnt/SkOTTable_fvar.h"
28 #include "src/sfnt/SkOTTable_head.h"
29 #include "src/sfnt/SkOTTable_hhea.h"
30 #include "src/sfnt/SkOTTable_post.h"
31 #include "src/sfnt/SkOTUtils.h"
32 #include "src/utils/win/SkDWrite.h"
33 #include "src/utils/win/SkDWriteFontFileStream.h"
34 
onGetFamilyName(SkString * familyName) const35 void DWriteFontTypeface::onGetFamilyName(SkString* familyName) const {
36     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
37     HRV(fDWriteFontFamily->GetFamilyNames(&familyNames));
38 
39     sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, familyName);
40 }
41 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const42 void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
43                                              bool* isLocalStream) const {
44     // Get the family name.
45     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
46     HRV(fDWriteFontFamily->GetFamilyNames(&familyNames));
47 
48     SkString utf8FamilyName;
49     sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, &utf8FamilyName);
50 
51     desc->setFamilyName(utf8FamilyName.c_str());
52     desc->setStyle(this->fontStyle());
53     *isLocalStream = SkToBool(fDWriteFontFileLoader.get());
54 }
55 
onCharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const56 void DWriteFontTypeface::onCharsToGlyphs(const SkUnichar uni[], int count,
57                                          SkGlyphID glyphs[]) const {
58     fDWriteFontFace->GetGlyphIndices((const UINT32*)uni, count, glyphs);
59 }
60 
onCountGlyphs() const61 int DWriteFontTypeface::onCountGlyphs() const {
62     return fDWriteFontFace->GetGlyphCount();
63 }
64 
getPostScriptGlyphNames(SkString *) const65 void DWriteFontTypeface::getPostScriptGlyphNames(SkString*) const {}
66 
onGetUPEM() const67 int DWriteFontTypeface::onGetUPEM() const {
68     DWRITE_FONT_METRICS metrics;
69     fDWriteFontFace->GetMetrics(&metrics);
70     return metrics.designUnitsPerEm;
71 }
72 
73 class LocalizedStrings_IDWriteLocalizedStrings : public SkTypeface::LocalizedStrings {
74 public:
75     /** Takes ownership of the IDWriteLocalizedStrings. */
LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings * strings)76     explicit LocalizedStrings_IDWriteLocalizedStrings(IDWriteLocalizedStrings* strings)
77         : fIndex(0), fStrings(strings)
78     { }
79 
next(SkTypeface::LocalizedString * localizedString)80     bool next(SkTypeface::LocalizedString* localizedString) override {
81         if (fIndex >= fStrings->GetCount()) {
82             return false;
83         }
84 
85         // String
86         UINT32 stringLen;
87         HRBM(fStrings->GetStringLength(fIndex, &stringLen), "Could not get string length.");
88 
89         SkSMallocWCHAR wString(stringLen+1);
90         HRBM(fStrings->GetString(fIndex, wString.get(), stringLen+1), "Could not get string.");
91 
92         HRB(sk_wchar_to_skstring(wString.get(), stringLen, &localizedString->fString));
93 
94         // Locale
95         UINT32 localeLen;
96         HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLen), "Could not get locale length.");
97 
98         SkSMallocWCHAR wLocale(localeLen+1);
99         HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLen+1), "Could not get locale.");
100 
101         HRB(sk_wchar_to_skstring(wLocale.get(), localeLen, &localizedString->fLanguage));
102 
103         ++fIndex;
104         return true;
105     }
106 
107 private:
108     UINT32 fIndex;
109     SkTScopedComPtr<IDWriteLocalizedStrings> fStrings;
110 };
111 
onCreateFamilyNameIterator() const112 SkTypeface::LocalizedStrings* DWriteFontTypeface::onCreateFamilyNameIterator() const {
113     sk_sp<SkTypeface::LocalizedStrings> nameIter =
114         SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
115     if (!nameIter) {
116         SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
117         HRNM(fDWriteFontFamily->GetFamilyNames(&familyNames), "Could not obtain family names.");
118         nameIter = sk_make_sp<LocalizedStrings_IDWriteLocalizedStrings>(familyNames.release());
119     }
120     return nameIter.release();
121 }
122 
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const123 int DWriteFontTypeface::onGetVariationDesignPosition(
124     SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
125 {
126 
127 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
128 
129     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
130     if (FAILED(fDWriteFontFace->QueryInterface(&fontFace5))) {
131         return -1;
132     }
133 
134     // Return 0 if the font is not variable font.
135     if (!fontFace5->HasVariations()) {
136         return 0;
137     }
138 
139     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
140     SkTScopedComPtr<IDWriteFontResource> fontResource;
141     HR_GENERAL(fontFace5->GetFontResource(&fontResource), nullptr, -1);
142     UINT32 variableAxisCount = 0;
143     for (UINT32 i = 0; i < fontAxisCount; ++i) {
144         if (fontResource->GetFontAxisAttributes(i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
145             ++variableAxisCount;
146         }
147     }
148 
149     if (!coordinates || coordinateCount < 0 || (unsigned)coordinateCount < variableAxisCount) {
150         return SkTo<int>(variableAxisCount);
151     }
152 
153     SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
154     HR_GENERAL(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount), nullptr, -1);
155     UINT32 coordIndex = 0;
156     for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
157         if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
158             coordinates[coordIndex].axis = SkEndian_SwapBE32(fontAxisValue[axisIndex].axisTag);
159             coordinates[coordIndex].value = fontAxisValue[axisIndex].value;
160             ++coordIndex;
161         }
162     }
163 
164     SkASSERT(coordIndex == variableAxisCount);
165     return SkTo<int>(variableAxisCount);
166 
167 #endif
168 
169     return -1;
170 }
171 
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const172 int DWriteFontTypeface::onGetVariationDesignParameters(
173     SkFontParameters::Variation::Axis parameters[], int parameterCount) const
174 {
175 
176 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
177 
178     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
179     if (FAILED(fDWriteFontFace->QueryInterface(&fontFace5))) {
180         return -1;
181     }
182 
183     // Return 0 if the font is not variable font.
184     if (!fontFace5->HasVariations()) {
185         return 0;
186     }
187 
188     UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
189     SkTScopedComPtr<IDWriteFontResource> fontResource;
190     HR_GENERAL(fontFace5->GetFontResource(&fontResource), nullptr, -1);
191     int variableAxisCount = 0;
192     for (UINT32 i = 0; i < fontAxisCount; ++i) {
193         if (fontResource->GetFontAxisAttributes(i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
194             variableAxisCount++;
195         }
196     }
197 
198     if (!parameters || parameterCount < variableAxisCount) {
199         return variableAxisCount;
200     }
201 
202     SkAutoSTMalloc<8, DWRITE_FONT_AXIS_RANGE> fontAxisRange(fontAxisCount);
203     HR_GENERAL(fontResource->GetFontAxisRanges(fontAxisRange.get(), fontAxisCount), nullptr, -1);
204     SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisDefaultValue(fontAxisCount);
205     HR_GENERAL(fontResource->GetDefaultFontAxisValues(fontAxisDefaultValue.get(), fontAxisCount),
206                nullptr, -1);
207     UINT32 coordIndex = 0;
208 
209     for (UINT32 axisIndex = 0; axisIndex < fontAxisCount; ++axisIndex) {
210         if (fontResource->GetFontAxisAttributes(axisIndex) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
211             parameters[coordIndex].tag = SkEndian_SwapBE32(fontAxisDefaultValue[axisIndex].axisTag);
212             parameters[coordIndex].min = fontAxisRange[axisIndex].minValue;
213             parameters[coordIndex].def = fontAxisDefaultValue[axisIndex].value;
214             parameters[coordIndex].max = fontAxisRange[axisIndex].maxValue;
215             parameters[coordIndex].setHidden(fontResource->GetFontAxisAttributes(axisIndex) &
216                                              DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN);
217         }
218     }
219 
220     return variableAxisCount;
221 
222 #endif
223 
224     return -1;
225 }
226 
onGetTableTags(SkFontTableTag tags[]) const227 int DWriteFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
228     DWRITE_FONT_FACE_TYPE type = fDWriteFontFace->GetType();
229     if (type != DWRITE_FONT_FACE_TYPE_CFF &&
230         type != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
231         type != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
232     {
233         return 0;
234     }
235 
236     int ttcIndex;
237     std::unique_ptr<SkStreamAsset> stream = this->openStream(&ttcIndex);
238     return stream.get() ? SkFontStream::GetTableTags(stream.get(), ttcIndex, tags) : 0;
239 }
240 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const241 size_t DWriteFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
242                                           size_t length, void* data) const
243 {
244     AutoDWriteTable table(fDWriteFontFace.get(), SkEndian_SwapBE32(tag));
245     if (!table.fExists) {
246         return 0;
247     }
248 
249     if (offset > table.fSize) {
250         return 0;
251     }
252     size_t size = SkTMin(length, table.fSize - offset);
253     if (data) {
254         memcpy(data, table.fData + offset, size);
255     }
256 
257     return size;
258 }
259 
onCopyTableData(SkFontTableTag tag) const260 sk_sp<SkData> DWriteFontTypeface::onCopyTableData(SkFontTableTag tag) const {
261     const uint8_t* data;
262     UINT32 size;
263     void* lock;
264     BOOL exists;
265     fDWriteFontFace->TryGetFontTable(SkEndian_SwapBE32(tag),
266             reinterpret_cast<const void **>(&data), &size, &lock, &exists);
267     if (!exists) {
268         return nullptr;
269     }
270     struct Context {
271         Context(void* lock, IDWriteFontFace* face) : fLock(lock), fFontFace(SkRefComPtr(face)) {}
272         ~Context() { fFontFace->ReleaseFontTable(fLock); }
273         void* fLock;
274         SkTScopedComPtr<IDWriteFontFace> fFontFace;
275     };
276     return SkData::MakeWithProc(data, size,
277                                 [](const void*, void* ctx) { delete (Context*)ctx; },
278                                 new Context(lock, fDWriteFontFace.get()));
279 }
280 
onMakeClone(const SkFontArguments & args) const281 sk_sp<SkTypeface> DWriteFontTypeface::onMakeClone(const SkFontArguments& args) const {
282     // Skip if the current face index does not match the ttcIndex
283     if (fDWriteFontFace->GetIndex() != SkTo<UINT32>(args.getCollectionIndex())) {
284         return sk_ref_sp(this);
285     }
286 
287 #if defined(NTDDI_WIN10_RS3) && NTDDI_VERSION >= NTDDI_WIN10_RS3
288 
289     SkTScopedComPtr<IDWriteFontFace5> fontFace5;
290 
291     if (SUCCEEDED(fDWriteFontFace->QueryInterface(&fontFace5)) && fontFace5->HasVariations()) {
292         UINT32 fontAxisCount = fontFace5->GetFontAxisValueCount();
293         UINT32 argsCoordCount = args.getVariationDesignPosition().coordinateCount;
294         SkAutoSTMalloc<8, DWRITE_FONT_AXIS_VALUE> fontAxisValue(fontAxisCount);
295         HRN(fontFace5->GetFontAxisValues(fontAxisValue.get(), fontAxisCount));
296 
297         for (UINT32 fontIndex = 0; fontIndex < fontAxisCount; ++fontIndex) {
298             for (UINT32 argsIndex = 0; argsIndex < argsCoordCount; ++argsIndex) {
299                 if (SkEndian_SwapBE32(fontAxisValue[fontIndex].axisTag) ==
300                     args.getVariationDesignPosition().coordinates[argsIndex].axis) {
301                     fontAxisValue[fontIndex].value =
302                         args.getVariationDesignPosition().coordinates[argsIndex].value;
303                 }
304             }
305         }
306         SkTScopedComPtr<IDWriteFontResource> fontResource;
307         HRN(fontFace5->GetFontResource(&fontResource));
308         SkTScopedComPtr<IDWriteFontFace5> newFontFace5;
309         HRN(fontResource->CreateFontFace(fDWriteFont->GetSimulations(),
310                                          fontAxisValue.get(),
311                                          fontAxisCount,
312                                          &newFontFace5));
313 
314         SkTScopedComPtr<IDWriteFontFace> newFontFace;
315         HRN(newFontFace5->QueryInterface(&newFontFace));
316         return DWriteFontTypeface::Make(fFactory.get(),
317                                         newFontFace.get(),
318                                         fDWriteFont.get(),
319                                         fDWriteFontFamily.get(),
320                                         fDWriteFontFileLoader.get(),
321                                         fDWriteFontCollectionLoader.get());
322     }
323 
324 #endif
325 
326     return sk_ref_sp(this);
327 }
328 
onOpenStream(int * ttcIndex) const329 std::unique_ptr<SkStreamAsset> DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
330     *ttcIndex = fDWriteFontFace->GetIndex();
331 
332     UINT32 numFiles;
333     HRNM(fDWriteFontFace->GetFiles(&numFiles, nullptr),
334          "Could not get number of font files.");
335     if (numFiles != 1) {
336         return nullptr;
337     }
338 
339     SkTScopedComPtr<IDWriteFontFile> fontFile;
340     HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files.");
341 
342     const void* fontFileKey;
343     UINT32 fontFileKeySize;
344     HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize),
345          "Could not get font file reference key.");
346 
347     SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader;
348     HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader.");
349 
350     SkTScopedComPtr<IDWriteFontFileStream> fontFileStream;
351     HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize,
352                                              &fontFileStream),
353          "Could not create font file stream.");
354 
355     return std::unique_ptr<SkStreamAsset>(new SkDWriteFontFileStream(fontFileStream.get()));
356 }
357 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const358 SkScalerContext* DWriteFontTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
359                                                            const SkDescriptor* desc) const {
360     return new SkScalerContext_DW(sk_ref_sp(const_cast<DWriteFontTypeface*>(this)), effects, desc);
361 }
362 
onFilterRec(SkScalerContextRec * rec) const363 void DWriteFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
364     if (rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) {
365         rec->fMaskFormat = SkMask::kA8_Format;
366         rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
367     }
368 
369     unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
370                                   SkScalerContext::kEmbolden_Flag |
371                                   SkScalerContext::kLCD_Vertical_Flag;
372     rec->fFlags &= ~flagsWeDontSupport;
373 
374     SkFontHinting h = rec->getHinting();
375     // DirectWrite2 allows for hinting to be turned off. Force everything else to normal.
376     if (h != SkFontHinting::kNone || !fFactory2 || !fDWriteFontFace2) {
377         h = SkFontHinting::kNormal;
378     }
379     rec->setHinting(h);
380 
381 #if defined(SK_FONT_HOST_USE_SYSTEM_SETTINGS)
382     IDWriteFactory* factory = sk_get_dwrite_factory();
383     if (factory != nullptr) {
384         SkTScopedComPtr<IDWriteRenderingParams> defaultRenderingParams;
385         if (SUCCEEDED(factory->CreateRenderingParams(&defaultRenderingParams))) {
386             float gamma = defaultRenderingParams->GetGamma();
387             rec->setDeviceGamma(gamma);
388             rec->setPaintGamma(gamma);
389 
390             rec->setContrast(defaultRenderingParams->GetEnhancedContrast());
391         }
392     }
393 #elif defined(MOZ_SKIA)
394     rec->setContrast(fContrast);
395 
396     rec->setDeviceGamma(fGamma);
397     rec->setPaintGamma(fGamma);
398 #endif
399 }
400 
401 ///////////////////////////////////////////////////////////////////////////////
402 //PDF Support
403 
getGlyphToUnicodeMap(SkUnichar * glyphToUnicode) const404 void DWriteFontTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
405     unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
406     sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
407     IDWriteFontFace* fontFace = fDWriteFontFace.get();
408     int maxGlyph = -1;
409     unsigned remainingGlyphCount = glyphCount;
410     for (UINT32 c = 0; c < 0x10FFFF && remainingGlyphCount != 0; ++c) {
411         UINT16 glyph = 0;
412         HRVM(fontFace->GetGlyphIndices(&c, 1, &glyph), "Failed to get glyph index.");
413         // Intermittent DW bug on Windows 10. See crbug.com/470146.
414         if (glyph >= glyphCount) {
415             return;
416         }
417         if (0 < glyph && glyphToUnicode[glyph] == 0) {
418             maxGlyph = SkTMax(static_cast<int>(glyph), maxGlyph);
419             glyphToUnicode[glyph] = c;  // Always use lowest-index unichar.
420             --remainingGlyphCount;
421         }
422     }
423 }
424 
onGetAdvancedMetrics() const425 std::unique_ptr<SkAdvancedTypefaceMetrics> DWriteFontTypeface::onGetAdvancedMetrics() const {
426 
427     std::unique_ptr<SkAdvancedTypefaceMetrics> info(nullptr);
428 
429     DWRITE_FONT_METRICS dwfm;
430     fDWriteFontFace->GetMetrics(&dwfm);
431 
432     info.reset(new SkAdvancedTypefaceMetrics);
433 
434     info->fAscent = SkToS16(dwfm.ascent);
435     info->fDescent = SkToS16(dwfm.descent);
436     info->fCapHeight = SkToS16(dwfm.capHeight);
437 
438     {
439         SkTScopedComPtr<IDWriteLocalizedStrings> postScriptNames;
440         BOOL exists = FALSE;
441         if (FAILED(fDWriteFont->GetInformationalStrings(
442                         DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
443                         &postScriptNames,
444                         &exists)) ||
445             !exists ||
446             FAILED(sk_get_locale_string(postScriptNames.get(), nullptr, &info->fPostScriptName)))
447         {
448             SkDEBUGF("Unable to get postscript name for typeface %p\n", this);
449         }
450     }
451 
452     // SkAdvancedTypefaceMetrics::fFontName must actually be a family name.
453     SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
454     if (FAILED(fDWriteFontFamily->GetFamilyNames(&familyNames)) ||
455         FAILED(sk_get_locale_string(familyNames.get(), nullptr, &info->fFontName)))
456     {
457         SkDEBUGF("Unable to get family name for typeface 0x%p\n", this);
458     }
459     if (info->fPostScriptName.isEmpty()) {
460         info->fPostScriptName = info->fFontName;
461     }
462 
463     DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
464     if (fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
465         fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
466     {
467         return info;
468     }
469 
470     // Simulated fonts aren't really TrueType fonts.
471     if (fDWriteFontFace->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE) {
472         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
473     }
474 
475     AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
476     AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
477     AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
478     AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
479     if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
480         return info;
481     }
482 
483     SkOTUtils::SetAdvancedTypefaceFlags(os2Table->version.v4.fsType, info.get());
484 
485     // There are versions of DirectWrite which support named instances for system variation fonts,
486     // but no means to indicate that such a typeface is a variation.
487     AutoTDWriteTable<SkOTTableFontVariations> fvarTable(fDWriteFontFace.get());
488     if (fvarTable.fExists) {
489         info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag;
490     }
491 
492     //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
493     //but have full width, latin half-width, and half-width kana.
494     bool fixedWidth = (postTable->isFixedPitch &&
495                       (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
496     //Monospace
497     if (fixedWidth) {
498         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
499     }
500     //Italic
501     if (os2Table->version.v0.fsSelection.field.Italic) {
502         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
503     }
504     //Serif
505     using SerifStyle = SkPanose::Data::TextAndDisplay::SerifStyle;
506     SerifStyle serifStyle = os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle;
507     if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType) {
508         if (SerifStyle::Cove == serifStyle ||
509             SerifStyle::ObtuseCove == serifStyle ||
510             SerifStyle::SquareCove == serifStyle ||
511             SerifStyle::ObtuseSquareCove == serifStyle ||
512             SerifStyle::Square == serifStyle ||
513             SerifStyle::Thin == serifStyle ||
514             SerifStyle::Bone == serifStyle ||
515             SerifStyle::Exaggerated == serifStyle ||
516             SerifStyle::Triangle == serifStyle)
517         {
518             info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
519         }
520     //Script
521     } else if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType) {
522         info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
523     }
524 
525     info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;
526 
527     info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
528                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
529                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
530                                     (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
531     return info;
532 }
533 #endif//defined(SK_BUILD_FOR_WIN)
534