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