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