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