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