no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / gfx / 2d / ScaledFontDWrite.cpp
blobf6a0d97504c4d9bca36d8f0cfe25634553ce0396
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ScaledFontDWrite.h"
8 #include "gfxDWriteCommon.h"
9 #include "UnscaledFontDWrite.h"
10 #include "PathD2D.h"
11 #include "gfxFont.h"
12 #include "Logging.h"
13 #include "mozilla/FontPropertyTypes.h"
14 #include "mozilla/webrender/WebRenderTypes.h"
15 #include "HelpersD2D.h"
16 #include "StackArray.h"
18 #include "dwrite_3.h"
20 #include "PathSkia.h"
21 #include "skia/include/core/SkPaint.h"
22 #include "skia/include/core/SkPath.h"
23 #include "skia/include/ports/SkTypeface_win.h"
25 #include <vector>
27 #include "cairo-win32.h"
29 #include "HelpersWinFonts.h"
31 namespace mozilla {
32 namespace gfx {
34 #define GASP_TAG 0x70736167
35 #define GASP_DOGRAY 0x2
37 static inline unsigned short readShort(const char* aBuf) {
38 return (*aBuf << 8) | *(aBuf + 1);
41 static bool DoGrayscale(IDWriteFontFace* aDWFace, Float ppem) {
42 void* tableContext;
43 char* tableData;
44 UINT32 tableSize;
45 BOOL exists;
46 aDWFace->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize,
47 &tableContext, &exists);
49 if (exists) {
50 if (tableSize < 4) {
51 aDWFace->ReleaseFontTable(tableContext);
52 return true;
54 struct gaspRange {
55 unsigned short maxPPEM; // Stored big-endian
56 unsigned short behavior; // Stored big-endian
58 unsigned short numRanges = readShort(tableData + 2);
59 if (tableSize < (UINT)4 + numRanges * 4) {
60 aDWFace->ReleaseFontTable(tableContext);
61 return true;
63 gaspRange* ranges = (gaspRange*)(tableData + 4);
64 for (int i = 0; i < numRanges; i++) {
65 if (readShort((char*)&ranges[i].maxPPEM) >= ppem) {
66 if (!(readShort((char*)&ranges[i].behavior) & GASP_DOGRAY)) {
67 aDWFace->ReleaseFontTable(tableContext);
68 return false;
70 break;
73 aDWFace->ReleaseFontTable(tableContext);
75 return true;
78 ScaledFontDWrite::ScaledFontDWrite(IDWriteFontFace* aFontFace,
79 const RefPtr<UnscaledFont>& aUnscaledFont,
80 Float aSize, bool aUseEmbeddedBitmap,
81 bool aUseMultistrikeBold, bool aGDIForced,
82 const gfxFontStyle* aStyle)
83 : ScaledFontBase(aUnscaledFont, aSize),
84 mFontFace(aFontFace),
85 mUseEmbeddedBitmap(aUseEmbeddedBitmap),
86 mUseMultistrikeBold(aUseMultistrikeBold),
87 mGDIForced(aGDIForced) {
88 if (aStyle) {
89 mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
90 DWriteFontStretchFromStretch(aStyle->stretch),
91 // FIXME(jwatt): also use kOblique_Slant
92 aStyle->style == FontSlantStyle::NORMAL
93 ? SkFontStyle::kUpright_Slant
94 : SkFontStyle::kItalic_Slant);
98 already_AddRefed<Path> ScaledFontDWrite::GetPathForGlyphs(
99 const GlyphBuffer& aBuffer, const DrawTarget* aTarget) {
100 RefPtr<PathBuilder> pathBuilder = aTarget->CreatePathBuilder();
102 if (pathBuilder->GetBackendType() != BackendType::DIRECT2D &&
103 pathBuilder->GetBackendType() != BackendType::DIRECT2D1_1) {
104 return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
107 PathBuilderD2D* pathBuilderD2D =
108 static_cast<PathBuilderD2D*>(pathBuilder.get());
110 CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
112 return pathBuilder->Finish();
115 SkTypeface* ScaledFontDWrite::CreateSkTypeface() {
116 RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
117 if (!factory) {
118 return nullptr;
121 auto& settings = DWriteSettings();
122 Float gamma = settings.Gamma();
123 // Skia doesn't support a gamma value outside of 0-4, so default to 2.2
124 if (gamma < 0.0f || gamma > 4.0f) {
125 gamma = 2.2f;
128 Float contrast = settings.EnhancedContrast();
129 // Skia doesn't support a contrast value outside of 0-1, so default to 1.0
130 if (contrast < 0.0f || contrast > 1.0f) {
131 contrast = 1.0f;
134 Float clearTypeLevel = settings.ClearTypeLevel();
135 if (clearTypeLevel < 0.0f || clearTypeLevel > 1.0f) {
136 clearTypeLevel = 1.0f;
139 return SkCreateTypefaceFromDWriteFont(factory, mFontFace, mStyle,
140 (int)settings.RenderingMode(), gamma,
141 contrast, clearTypeLevel);
144 void ScaledFontDWrite::SetupSkFontDrawOptions(SkFont& aFont) {
145 if (ForceGDIMode()) {
146 aFont.setEmbeddedBitmaps(true);
147 aFont.setSubpixel(false);
148 } else {
149 aFont.setEmbeddedBitmaps(UseEmbeddedBitmaps());
150 aFont.setSubpixel(true);
154 bool ScaledFontDWrite::MayUseBitmaps() {
155 return ForceGDIMode() || UseEmbeddedBitmaps();
158 void ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
159 PathBuilder* aBuilder,
160 const Matrix* aTransformHint) {
161 BackendType backendType = aBuilder->GetBackendType();
162 if (backendType != BackendType::DIRECT2D &&
163 backendType != BackendType::DIRECT2D1_1) {
164 ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aTransformHint);
165 return;
168 PathBuilderD2D* pathBuilderD2D = static_cast<PathBuilderD2D*>(aBuilder);
170 if (pathBuilderD2D->IsFigureActive()) {
171 gfxCriticalNote
172 << "Attempting to copy glyphs to PathBuilderD2D with active figure.";
175 CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
178 void ScaledFontDWrite::CopyGlyphsToSink(const GlyphBuffer& aBuffer,
179 ID2D1SimplifiedGeometrySink* aSink) {
180 std::vector<UINT16> indices;
181 std::vector<FLOAT> advances;
182 std::vector<DWRITE_GLYPH_OFFSET> offsets;
183 indices.resize(aBuffer.mNumGlyphs);
184 advances.resize(aBuffer.mNumGlyphs);
185 offsets.resize(aBuffer.mNumGlyphs);
187 memset(&advances.front(), 0, sizeof(FLOAT) * aBuffer.mNumGlyphs);
188 for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
189 indices[i] = aBuffer.mGlyphs[i].mIndex;
190 offsets[i].advanceOffset = aBuffer.mGlyphs[i].mPosition.x;
191 offsets[i].ascenderOffset = -aBuffer.mGlyphs[i].mPosition.y;
194 HRESULT hr = mFontFace->GetGlyphRunOutline(
195 mSize, &indices.front(), &advances.front(), &offsets.front(),
196 aBuffer.mNumGlyphs, FALSE, FALSE, aSink);
197 if (FAILED(hr)) {
198 gfxCriticalNote << "Failed to copy glyphs to geometry sink. Code: "
199 << hexa(hr);
203 bool UnscaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback,
204 void* aBaton) {
205 UINT32 fileCount = 0;
206 HRESULT hr = mFontFace->GetFiles(&fileCount, nullptr);
208 if (FAILED(hr) || fileCount > 1) {
209 MOZ_ASSERT(false);
210 return false;
213 if (!aDataCallback) {
214 return true;
217 RefPtr<IDWriteFontFile> file;
218 hr = mFontFace->GetFiles(&fileCount, getter_AddRefs(file));
219 if (FAILED(hr)) {
220 return false;
223 const void* referenceKey;
224 UINT32 refKeySize;
225 // XXX - This can currently crash for webfonts, as when we get the reference
226 // key out of the file, that can be an invalid reference key for the loader
227 // we use it with. The fix to this is not obvious but it will probably
228 // have to happen inside thebes.
229 hr = file->GetReferenceKey(&referenceKey, &refKeySize);
230 if (FAILED(hr)) {
231 return false;
234 RefPtr<IDWriteFontFileLoader> loader;
235 hr = file->GetLoader(getter_AddRefs(loader));
236 if (FAILED(hr)) {
237 return false;
240 RefPtr<IDWriteFontFileStream> stream;
241 hr = loader->CreateStreamFromKey(referenceKey, refKeySize,
242 getter_AddRefs(stream));
243 if (FAILED(hr)) {
244 return false;
247 UINT64 fileSize64;
248 hr = stream->GetFileSize(&fileSize64);
249 if (FAILED(hr) || fileSize64 > UINT32_MAX) {
250 MOZ_ASSERT(false);
251 return false;
254 // Try to catch any device memory exceptions that may occur while attempting
255 // to read the file fragment.
256 void* context = nullptr;
257 hr = E_FAIL;
258 MOZ_SEH_TRY {
259 uint32_t fileSize = static_cast<uint32_t>(fileSize64);
260 const void* fragmentStart = nullptr;
261 hr = stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
262 if (SUCCEEDED(hr)) {
263 aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(),
264 aBaton);
267 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
268 gfxCriticalNote << "Exception occurred reading DWrite font file data";
270 if (FAILED(hr)) {
271 return false;
273 stream->ReleaseFileFragment(context);
274 return true;
277 static bool GetFontFileName(RefPtr<IDWriteFontFace> aFontFace,
278 std::vector<WCHAR>& aFileName) {
279 UINT32 numFiles;
280 HRESULT hr = aFontFace->GetFiles(&numFiles, nullptr);
281 if (FAILED(hr)) {
282 gfxDebug() << "Failed getting file count for WR font";
283 return false;
284 } else if (numFiles != 1) {
285 gfxDebug() << "Invalid file count " << numFiles << " for WR font";
286 return false;
289 RefPtr<IDWriteFontFile> file;
290 hr = aFontFace->GetFiles(&numFiles, getter_AddRefs(file));
291 if (FAILED(hr)) {
292 gfxDebug() << "Failed getting file for WR font";
293 return false;
296 const void* key;
297 UINT32 keySize;
298 hr = file->GetReferenceKey(&key, &keySize);
299 if (FAILED(hr)) {
300 gfxDebug() << "Failed getting file ref key for WR font";
301 return false;
303 RefPtr<IDWriteFontFileLoader> loader;
304 hr = file->GetLoader(getter_AddRefs(loader));
305 if (FAILED(hr)) {
306 gfxDebug() << "Failed getting file loader for WR font";
307 return false;
309 RefPtr<IDWriteLocalFontFileLoader> localLoader;
310 loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader),
311 (void**)getter_AddRefs(localLoader));
312 if (!localLoader) {
313 gfxDebug() << "Failed querying loader interface for WR font";
314 return false;
316 UINT32 pathLen;
317 hr = localLoader->GetFilePathLengthFromKey(key, keySize, &pathLen);
318 if (FAILED(hr)) {
319 gfxDebug() << "Failed getting path length for WR font";
320 return false;
322 aFileName.resize(pathLen + 1);
323 hr = localLoader->GetFilePathFromKey(key, keySize, aFileName.data(),
324 pathLen + 1);
325 if (FAILED(hr) || aFileName.back() != 0) {
326 gfxDebug() << "Failed getting path for WR font";
327 return false;
329 DWORD attribs = GetFileAttributesW(aFileName.data());
330 if (attribs == INVALID_FILE_ATTRIBUTES) {
331 gfxDebug() << "Invalid file \"" << aFileName.data() << "\" for WR font";
332 return false;
334 // We leave the null terminator at the end of the returned file name.
335 return true;
338 bool UnscaledFontDWrite::GetFontDescriptor(FontDescriptorOutput aCb,
339 void* aBaton) {
340 if (!mFont) {
341 return false;
344 std::vector<WCHAR> fileName;
345 if (!GetFontFileName(mFontFace, fileName)) {
346 return false;
348 uint32_t index = mFontFace->GetIndex();
350 aCb(reinterpret_cast<const uint8_t*>(fileName.data()),
351 fileName.size() * sizeof(WCHAR), index, aBaton);
352 return true;
355 ScaledFontDWrite::InstanceData::InstanceData(
356 const wr::FontInstanceOptions* aOptions,
357 const wr::FontInstancePlatformOptions* aPlatformOptions) {
358 if (aOptions) {
359 if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
360 mUseEmbeddedBitmap = true;
362 if (aOptions->flags & wr::FontInstanceFlags::SYNTHETIC_BOLD) {
363 mUseBoldSimulation = true;
365 if (aOptions->flags & wr::FontInstanceFlags::MULTISTRIKE_BOLD) {
366 mUseMultistrikeBold = true;
368 if (aOptions->flags & wr::FontInstanceFlags::FORCE_GDI) {
369 mGDIForced = true;
374 bool ScaledFontDWrite::HasVariationSettings() {
375 RefPtr<IDWriteFontFace5> ff5;
376 mFontFace->QueryInterface(__uuidof(IDWriteFontFace5),
377 (void**)getter_AddRefs(ff5));
378 if (!ff5 || !ff5->HasVariations()) {
379 return false;
382 uint32_t count = ff5->GetFontAxisValueCount();
383 if (!count) {
384 return false;
387 RefPtr<IDWriteFontResource> res;
388 if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
389 return false;
392 std::vector<DWRITE_FONT_AXIS_VALUE> defaults(count);
393 if (FAILED(res->GetDefaultFontAxisValues(defaults.data(), count))) {
394 return false;
397 std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
398 if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
399 return false;
402 for (uint32_t i = 0; i < count; i++) {
403 DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
404 if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
405 if (values[i].value != defaults[i].value) {
406 return true;
411 return false;
414 // Helper for ScaledFontDWrite::GetFontInstanceData: if the font has variation
415 // axes, get their current values into the aOutput vector.
416 static void GetVariationsFromFontFace(IDWriteFontFace* aFace,
417 std::vector<FontVariation>* aOutput) {
418 RefPtr<IDWriteFontFace5> ff5;
419 aFace->QueryInterface(__uuidof(IDWriteFontFace5),
420 (void**)getter_AddRefs(ff5));
421 if (!ff5 || !ff5->HasVariations()) {
422 return;
425 uint32_t count = ff5->GetFontAxisValueCount();
426 if (!count) {
427 return;
430 RefPtr<IDWriteFontResource> res;
431 if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
432 return;
435 std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
436 if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
437 return;
440 aOutput->reserve(count);
441 for (uint32_t i = 0; i < count; i++) {
442 DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
443 if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
444 float v = values[i].value;
445 uint32_t t = TRUETYPE_TAG(
446 uint8_t(values[i].axisTag), uint8_t(values[i].axisTag >> 8),
447 uint8_t(values[i].axisTag >> 16), uint8_t(values[i].axisTag >> 24));
448 aOutput->push_back(FontVariation{uint32_t(t), float(v)});
453 bool ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb,
454 void* aBaton) {
455 InstanceData instance(this);
457 // If the font has variations, get the list of axis values.
458 std::vector<FontVariation> variations;
459 GetVariationsFromFontFace(mFontFace, &variations);
461 aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
462 variations.data(), variations.size(), aBaton);
464 return true;
467 bool ScaledFontDWrite::GetWRFontInstanceOptions(
468 Maybe<wr::FontInstanceOptions>* aOutOptions,
469 Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
470 std::vector<FontVariation>* aOutVariations) {
471 wr::FontInstanceOptions options;
472 options.render_mode = wr::ToFontRenderMode(GetDefaultAAMode());
473 options.flags = wr::FontInstanceFlags{0};
474 if (HasBoldSimulation()) {
475 options.flags |= wr::FontInstanceFlags::SYNTHETIC_BOLD;
477 if (UseMultistrikeBold()) {
478 options.flags |= wr::FontInstanceFlags::MULTISTRIKE_BOLD;
480 if (UseEmbeddedBitmaps()) {
481 options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
483 if (ForceGDIMode()) {
484 options.flags |= wr::FontInstanceFlags::FORCE_GDI;
485 } else {
486 options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
488 auto& settings = DWriteSettings();
489 switch (settings.RenderingMode()) {
490 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
491 options.flags |= wr::FontInstanceFlags::FORCE_SYMMETRIC;
492 break;
493 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
494 options.flags |= wr::FontInstanceFlags::NO_SYMMETRIC;
495 break;
496 default:
497 break;
499 if (Factory::GetBGRSubpixelOrder()) {
500 options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
502 options.synthetic_italics =
503 wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
505 wr::FontInstancePlatformOptions platformOptions;
506 platformOptions.gamma = uint16_t(std::round(settings.Gamma() * 100.0f));
507 platformOptions.contrast =
508 uint8_t(std::round(std::min(settings.EnhancedContrast(), 1.0f) * 100.0f));
509 platformOptions.cleartype_level =
510 uint8_t(std::round(std::min(settings.ClearTypeLevel(), 1.0f) * 100.0f));
512 *aOutOptions = Some(options);
513 *aOutPlatformOptions = Some(platformOptions);
515 GetVariationsFromFontFace(mFontFace, aOutVariations);
517 return true;
520 DWriteSettings& ScaledFontDWrite::DWriteSettings() const {
521 return DWriteSettings::Get(mGDIForced);
524 // Helper for UnscaledFontDWrite::CreateScaledFont: create a clone of the
525 // given IDWriteFontFace, with specified variation-axis values applied.
526 // Returns nullptr in case of failure.
527 static already_AddRefed<IDWriteFontFace5> CreateFaceWithVariations(
528 IDWriteFontFace* aFace, DWRITE_FONT_SIMULATIONS aSimulations,
529 const FontVariation* aVariations = nullptr, uint32_t aNumVariations = 0) {
530 auto makeDWriteAxisTag = [](uint32_t aTag) {
531 return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
532 (aTag >> 8) & 0xff, aTag & 0xff);
535 MOZ_SEH_TRY {
536 RefPtr<IDWriteFontFace5> ff5;
537 aFace->QueryInterface(__uuidof(IDWriteFontFace5),
538 (void**)getter_AddRefs(ff5));
539 if (!ff5) {
540 return nullptr;
543 RefPtr<IDWriteFontResource> res;
544 if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
545 return nullptr;
548 std::vector<DWRITE_FONT_AXIS_VALUE> fontAxisValues;
549 if (aNumVariations) {
550 fontAxisValues.reserve(aNumVariations);
551 for (uint32_t i = 0; i < aNumVariations; i++) {
552 DWRITE_FONT_AXIS_VALUE axisValue = {
553 makeDWriteAxisTag(aVariations[i].mTag), aVariations[i].mValue};
554 fontAxisValues.push_back(axisValue);
556 } else {
557 uint32_t count = ff5->GetFontAxisValueCount();
558 if (count) {
559 fontAxisValues.resize(count);
560 if (FAILED(ff5->GetFontAxisValues(fontAxisValues.data(), count))) {
561 fontAxisValues.clear();
566 RefPtr<IDWriteFontFace5> newFace;
567 if (FAILED(res->CreateFontFace(aSimulations, fontAxisValues.data(),
568 fontAxisValues.size(),
569 getter_AddRefs(newFace)))) {
570 return nullptr;
572 return newFace.forget();
574 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
575 gfxCriticalNote << "Exception occurred initializing variation face";
576 return nullptr;
580 bool UnscaledFontDWrite::InitBold() {
581 if (mFontFaceBold) {
582 return true;
585 DWRITE_FONT_SIMULATIONS sims = mFontFace->GetSimulations();
586 if (sims & DWRITE_FONT_SIMULATIONS_BOLD) {
587 mFontFaceBold = mFontFace;
588 return true;
590 sims |= DWRITE_FONT_SIMULATIONS_BOLD;
592 RefPtr<IDWriteFontFace5> ff5 = CreateFaceWithVariations(mFontFace, sims);
593 if (ff5) {
594 mFontFaceBold = ff5;
595 } else {
596 MOZ_SEH_TRY {
597 UINT32 numFiles = 0;
598 if (FAILED(mFontFace->GetFiles(&numFiles, nullptr))) {
599 return false;
601 StackArray<IDWriteFontFile*, 1> files(numFiles);
602 if (FAILED(mFontFace->GetFiles(&numFiles, files.data()))) {
603 return false;
605 HRESULT hr = Factory::GetDWriteFactory()->CreateFontFace(
606 mFontFace->GetType(), numFiles, files.data(), mFontFace->GetIndex(),
607 sims, getter_AddRefs(mFontFaceBold));
608 for (UINT32 i = 0; i < numFiles; ++i) {
609 files[i]->Release();
611 if (FAILED(hr) || !mFontFaceBold) {
612 return false;
615 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
616 gfxCriticalNote << "Exception occurred initializing bold face";
617 return false;
620 return true;
623 already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFont(
624 Float aGlyphSize, const uint8_t* aInstanceData,
625 uint32_t aInstanceDataLength, const FontVariation* aVariations,
626 uint32_t aNumVariations) {
627 if (aInstanceDataLength < sizeof(ScaledFontDWrite::InstanceData)) {
628 gfxWarning() << "DWrite scaled font instance data is truncated.";
629 return nullptr;
631 const ScaledFontDWrite::InstanceData& instanceData =
632 *reinterpret_cast<const ScaledFontDWrite::InstanceData*>(aInstanceData);
634 IDWriteFontFace* face = mFontFace;
635 if (instanceData.mUseBoldSimulation) {
636 if (!InitBold()) {
637 gfxWarning() << "Failed creating bold IDWriteFontFace.";
638 return nullptr;
640 face = mFontFaceBold;
642 DWRITE_FONT_SIMULATIONS sims = face->GetSimulations();
644 // If variations are required, we create a separate IDWriteFontFace5 with
645 // the requested settings applied.
646 RefPtr<IDWriteFontFace5> ff5;
647 if (aNumVariations) {
648 ff5 =
649 CreateFaceWithVariations(mFontFace, sims, aVariations, aNumVariations);
650 if (ff5) {
651 face = ff5;
652 } else {
653 gfxWarning() << "Failed to create IDWriteFontFace5 with variations.";
657 return MakeAndAddRef<ScaledFontDWrite>(
658 face, this, aGlyphSize, instanceData.mUseEmbeddedBitmap,
659 instanceData.mUseMultistrikeBold, instanceData.mGDIForced, nullptr);
662 already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFontFromWRFont(
663 Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
664 const wr::FontInstancePlatformOptions* aPlatformOptions,
665 const FontVariation* aVariations, uint32_t aNumVariations) {
666 ScaledFontDWrite::InstanceData instanceData(aOptions, aPlatformOptions);
667 return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
668 sizeof(instanceData), aVariations, aNumVariations);
671 AntialiasMode ScaledFontDWrite::GetDefaultAAMode() {
672 AntialiasMode defaultMode = GetSystemDefaultAAMode();
674 switch (defaultMode) {
675 case AntialiasMode::SUBPIXEL:
676 case AntialiasMode::DEFAULT:
677 if (DWriteSettings().ClearTypeLevel() == 0.0f) {
678 defaultMode = AntialiasMode::GRAY;
680 break;
681 case AntialiasMode::GRAY:
682 if (!DoGrayscale(mFontFace, mSize)) {
683 defaultMode = AntialiasMode::NONE;
685 break;
686 case AntialiasMode::NONE:
687 break;
690 return defaultMode;
693 cairo_font_face_t* ScaledFontDWrite::CreateCairoFontFace(
694 cairo_font_options_t* aFontOptions) {
695 if (!mFontFace) {
696 return nullptr;
699 return cairo_dwrite_font_face_create_for_dwrite_fontface(nullptr, mFontFace);
702 void ScaledFontDWrite::PrepareCairoScaledFont(cairo_scaled_font_t* aFont) {
703 if (mGDIForced) {
704 cairo_dwrite_scaled_font_set_force_GDI_classic(aFont, true);
708 already_AddRefed<UnscaledFont> UnscaledFontDWrite::CreateFromFontDescriptor(
709 const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
710 // Note that despite the type of aData here, it actually points to a 16-bit
711 // Windows font file path (hence the cast to WCHAR* below).
712 if (aDataLength == 0) {
713 gfxWarning() << "DWrite font descriptor is truncated.";
714 return nullptr;
717 RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
718 if (!factory) {
719 return nullptr;
722 MOZ_SEH_TRY {
723 RefPtr<IDWriteFontFile> fontFile;
724 HRESULT hr = factory->CreateFontFileReference((const WCHAR*)aData, nullptr,
725 getter_AddRefs(fontFile));
726 if (FAILED(hr)) {
727 return nullptr;
729 BOOL isSupported;
730 DWRITE_FONT_FILE_TYPE fileType;
731 DWRITE_FONT_FACE_TYPE faceType;
732 UINT32 numFaces;
733 hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numFaces);
734 if (FAILED(hr) || !isSupported || aIndex >= numFaces) {
735 return nullptr;
737 IDWriteFontFile* fontFiles[1] = {fontFile.get()};
738 RefPtr<IDWriteFontFace> fontFace;
739 hr = factory->CreateFontFace(faceType, 1, fontFiles, aIndex,
740 DWRITE_FONT_SIMULATIONS_NONE,
741 getter_AddRefs(fontFace));
742 if (FAILED(hr)) {
743 return nullptr;
745 RefPtr unscaledFont = new UnscaledFontDWrite(fontFace, nullptr);
746 return unscaledFont.forget();
748 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
749 gfxCriticalNote << "Exception occurred creating unscaledFont for "
750 << NS_ConvertUTF16toUTF8((const char16_t*)aData).get();
751 return nullptr;
755 } // namespace gfx
756 } // namespace mozilla