summaryrefslogtreecommitdiffstats
path: root/gfx/2d/ScaledFontDWrite.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/2d/ScaledFontDWrite.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--gfx/2d/ScaledFontDWrite.cpp758
1 files changed, 758 insertions, 0 deletions
diff --git a/gfx/2d/ScaledFontDWrite.cpp b/gfx/2d/ScaledFontDWrite.cpp
new file mode 100644
index 0000000000..8b79c67a70
--- /dev/null
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -0,0 +1,758 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ScaledFontDWrite.h"
+#include "UnscaledFontDWrite.h"
+#include "PathD2D.h"
+#include "gfxFont.h"
+#include "Logging.h"
+#include "mozilla/FontPropertyTypes.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "HelpersD2D.h"
+#include "StackArray.h"
+
+#include "dwrite_3.h"
+
+// Currently, we build with WINVER=0x601 (Win7), which means newer
+// declarations in dwrite_3.h will not be visible. Also, we don't
+// yet have the Fall Creators Update SDK available on build machines,
+// so even with updated WINVER, some of the interfaces we need would
+// not be present.
+// To work around this, until the build environment is updated,
+// we #include an extra header that contains copies of the relevant
+// classes/interfaces we need.
+#if !defined(__MINGW32__) && WINVER < 0x0A00
+# include "dw-extra.h"
+#endif
+
+#ifdef USE_SKIA
+# include "PathSkia.h"
+# include "skia/include/core/SkPaint.h"
+# include "skia/include/core/SkPath.h"
+# include "skia/include/ports/SkTypeface_win.h"
+#endif
+
+#include <vector>
+
+#ifdef USE_CAIRO_SCALED_FONT
+# include "cairo-win32.h"
+#endif
+
+#include "HelpersWinFonts.h"
+
+namespace mozilla {
+namespace gfx {
+
+#define GASP_TAG 0x70736167
+#define GASP_DOGRAY 0x2
+
+static inline unsigned short readShort(const char* aBuf) {
+ return (*aBuf << 8) | *(aBuf + 1);
+}
+
+static bool DoGrayscale(IDWriteFontFace* aDWFace, Float ppem) {
+ void* tableContext;
+ char* tableData;
+ UINT32 tableSize;
+ BOOL exists;
+ aDWFace->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize,
+ &tableContext, &exists);
+
+ if (exists) {
+ if (tableSize < 4) {
+ aDWFace->ReleaseFontTable(tableContext);
+ return true;
+ }
+ struct gaspRange {
+ unsigned short maxPPEM; // Stored big-endian
+ unsigned short behavior; // Stored big-endian
+ };
+ unsigned short numRanges = readShort(tableData + 2);
+ if (tableSize < (UINT)4 + numRanges * 4) {
+ aDWFace->ReleaseFontTable(tableContext);
+ return true;
+ }
+ gaspRange* ranges = (gaspRange*)(tableData + 4);
+ for (int i = 0; i < numRanges; i++) {
+ if (readShort((char*)&ranges[i].maxPPEM) > ppem) {
+ if (!(readShort((char*)&ranges[i].behavior) & GASP_DOGRAY)) {
+ aDWFace->ReleaseFontTable(tableContext);
+ return false;
+ }
+ break;
+ }
+ }
+ aDWFace->ReleaseFontTable(tableContext);
+ }
+ return true;
+}
+
+static inline DWRITE_FONT_STRETCH DWriteFontStretchFromStretch(
+ FontStretch aStretch) {
+ if (aStretch == FontStretch::UltraCondensed()) {
+ return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
+ }
+ if (aStretch == FontStretch::ExtraCondensed()) {
+ return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
+ }
+ if (aStretch == FontStretch::Condensed()) {
+ return DWRITE_FONT_STRETCH_CONDENSED;
+ }
+ if (aStretch == FontStretch::SemiCondensed()) {
+ return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
+ }
+ if (aStretch == FontStretch::Normal()) {
+ return DWRITE_FONT_STRETCH_NORMAL;
+ }
+ if (aStretch == FontStretch::SemiExpanded()) {
+ return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
+ }
+ if (aStretch == FontStretch::Expanded()) {
+ return DWRITE_FONT_STRETCH_EXPANDED;
+ }
+ if (aStretch == FontStretch::ExtraExpanded()) {
+ return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
+ }
+ if (aStretch == FontStretch::UltraExpanded()) {
+ return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
+ }
+ return DWRITE_FONT_STRETCH_UNDEFINED;
+}
+
+ScaledFontDWrite::ScaledFontDWrite(
+ IDWriteFontFace* aFontFace, const RefPtr<UnscaledFont>& aUnscaledFont,
+ Float aSize, bool aUseEmbeddedBitmap, DWRITE_RENDERING_MODE aRenderingMode,
+ IDWriteRenderingParams* aParams, Float aGamma, Float aContrast,
+ Float aClearTypeLevel, const gfxFontStyle* aStyle)
+ : ScaledFontBase(aUnscaledFont, aSize),
+ mFontFace(aFontFace),
+ mUseEmbeddedBitmap(aUseEmbeddedBitmap),
+ mRenderingMode(aRenderingMode),
+ mParams(aParams),
+ mGamma(aGamma),
+ mContrast(aContrast),
+ mClearTypeLevel(aClearTypeLevel) {
+ if (aStyle) {
+ mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
+ DWriteFontStretchFromStretch(aStyle->stretch),
+ // FIXME(jwatt): also use kOblique_Slant
+ aStyle->style == FontSlantStyle::Normal()
+ ? SkFontStyle::kUpright_Slant
+ : SkFontStyle::kItalic_Slant);
+ }
+}
+
+already_AddRefed<Path> ScaledFontDWrite::GetPathForGlyphs(
+ const GlyphBuffer& aBuffer, const DrawTarget* aTarget) {
+ RefPtr<PathBuilder> pathBuilder = aTarget->CreatePathBuilder();
+
+ if (pathBuilder->GetBackendType() != BackendType::DIRECT2D &&
+ pathBuilder->GetBackendType() != BackendType::DIRECT2D1_1) {
+ return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
+ }
+
+ PathBuilderD2D* pathBuilderD2D =
+ static_cast<PathBuilderD2D*>(pathBuilder.get());
+
+ CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
+
+ return pathBuilder->Finish();
+}
+
+#ifdef USE_SKIA
+SkTypeface* ScaledFontDWrite::CreateSkTypeface() {
+ RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
+ if (!factory) {
+ return nullptr;
+ }
+
+ Float gamma = mGamma;
+ // Skia doesn't support a gamma value outside of 0-4, so default to 2.2
+ if (gamma < 0.0f || gamma > 4.0f) {
+ gamma = 2.2f;
+ }
+
+ Float contrast = mContrast;
+ // Skia doesn't support a contrast value outside of 0-1, so default to 1.0
+ if (contrast < 0.0f || contrast > 1.0f) {
+ contrast = 1.0f;
+ }
+
+ Float clearTypeLevel = mClearTypeLevel;
+ if (clearTypeLevel < 0.0f || clearTypeLevel > 1.0f) {
+ clearTypeLevel = 1.0f;
+ }
+
+ return SkCreateTypefaceFromDWriteFont(factory, mFontFace, mStyle,
+ (int)mRenderingMode, gamma, contrast,
+ clearTypeLevel);
+}
+
+void ScaledFontDWrite::SetupSkFontDrawOptions(SkFont& aFont) {
+ if (ForceGDIMode()) {
+ aFont.setEmbeddedBitmaps(true);
+ aFont.setSubpixel(false);
+ } else {
+ aFont.setEmbeddedBitmaps(UseEmbeddedBitmaps());
+ aFont.setSubpixel(true);
+ }
+}
+#endif
+
+void ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
+ PathBuilder* aBuilder,
+ const Matrix* aTransformHint) {
+ BackendType backendType = aBuilder->GetBackendType();
+ if (backendType == BackendType::CAPTURE) {
+ StreamingGeometrySink sink(aBuilder);
+ CopyGlyphsToSink(aBuffer, &sink);
+ return;
+ }
+
+ if (backendType != BackendType::DIRECT2D &&
+ backendType != BackendType::DIRECT2D1_1) {
+ ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aTransformHint);
+ return;
+ }
+
+ PathBuilderD2D* pathBuilderD2D = static_cast<PathBuilderD2D*>(aBuilder);
+
+ if (pathBuilderD2D->IsFigureActive()) {
+ gfxCriticalNote
+ << "Attempting to copy glyphs to PathBuilderD2D with active figure.";
+ }
+
+ CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
+}
+
+void ScaledFontDWrite::CopyGlyphsToSink(const GlyphBuffer& aBuffer,
+ ID2D1SimplifiedGeometrySink* aSink) {
+ std::vector<UINT16> indices;
+ std::vector<FLOAT> advances;
+ std::vector<DWRITE_GLYPH_OFFSET> offsets;
+ indices.resize(aBuffer.mNumGlyphs);
+ advances.resize(aBuffer.mNumGlyphs);
+ offsets.resize(aBuffer.mNumGlyphs);
+
+ memset(&advances.front(), 0, sizeof(FLOAT) * aBuffer.mNumGlyphs);
+ for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
+ indices[i] = aBuffer.mGlyphs[i].mIndex;
+ offsets[i].advanceOffset = aBuffer.mGlyphs[i].mPosition.x;
+ offsets[i].ascenderOffset = -aBuffer.mGlyphs[i].mPosition.y;
+ }
+
+ HRESULT hr = mFontFace->GetGlyphRunOutline(
+ mSize, &indices.front(), &advances.front(), &offsets.front(),
+ aBuffer.mNumGlyphs, FALSE, FALSE, aSink);
+ if (FAILED(hr)) {
+ gfxCriticalNote << "Failed to copy glyphs to geometry sink. Code: "
+ << hexa(hr);
+ }
+}
+
+bool UnscaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback,
+ void* aBaton) {
+ UINT32 fileCount = 0;
+ HRESULT hr = mFontFace->GetFiles(&fileCount, nullptr);
+
+ if (FAILED(hr) || fileCount > 1) {
+ MOZ_ASSERT(false);
+ return false;
+ }
+
+ if (!aDataCallback) {
+ return true;
+ }
+
+ RefPtr<IDWriteFontFile> file;
+ hr = mFontFace->GetFiles(&fileCount, getter_AddRefs(file));
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ const void* referenceKey;
+ UINT32 refKeySize;
+ // XXX - This can currently crash for webfonts, as when we get the reference
+ // key out of the file, that can be an invalid reference key for the loader
+ // we use it with. The fix to this is not obvious but it will probably
+ // have to happen inside thebes.
+ hr = file->GetReferenceKey(&referenceKey, &refKeySize);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ RefPtr<IDWriteFontFileLoader> loader;
+ hr = file->GetLoader(getter_AddRefs(loader));
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ RefPtr<IDWriteFontFileStream> stream;
+ hr = loader->CreateStreamFromKey(referenceKey, refKeySize,
+ getter_AddRefs(stream));
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ UINT64 fileSize64;
+ hr = stream->GetFileSize(&fileSize64);
+ if (FAILED(hr) || fileSize64 > UINT32_MAX) {
+ MOZ_ASSERT(false);
+ return false;
+ }
+
+ // Try to catch any device memory exceptions that may occur while attempting
+ // to read the file fragment.
+ void* context = nullptr;
+ hr = E_FAIL;
+ MOZ_SEH_TRY {
+ uint32_t fileSize = static_cast<uint32_t>(fileSize64);
+ const void* fragmentStart = nullptr;
+ hr = stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
+ if (SUCCEEDED(hr)) {
+ aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(),
+ aBaton);
+ }
+ }
+ MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
+ gfxCriticalNote << "Exception occurred reading DWrite font file data";
+ }
+ if (FAILED(hr)) {
+ return false;
+ }
+ stream->ReleaseFileFragment(context);
+ return true;
+}
+
+static bool GetFontFileName(RefPtr<IDWriteFontFace> aFontFace,
+ std::vector<WCHAR>& aFileName) {
+ UINT32 numFiles;
+ HRESULT hr = aFontFace->GetFiles(&numFiles, nullptr);
+ if (FAILED(hr)) {
+ gfxDebug() << "Failed getting file count for WR font";
+ return false;
+ } else if (numFiles != 1) {
+ gfxDebug() << "Invalid file count " << numFiles << " for WR font";
+ return false;
+ }
+
+ RefPtr<IDWriteFontFile> file;
+ hr = aFontFace->GetFiles(&numFiles, getter_AddRefs(file));
+ if (FAILED(hr)) {
+ gfxDebug() << "Failed getting file for WR font";
+ return false;
+ }
+
+ const void* key;
+ UINT32 keySize;
+ hr = file->GetReferenceKey(&key, &keySize);
+ if (FAILED(hr)) {
+ gfxDebug() << "Failed getting file ref key for WR font";
+ return false;
+ }
+ RefPtr<IDWriteFontFileLoader> loader;
+ hr = file->GetLoader(getter_AddRefs(loader));
+ if (FAILED(hr)) {
+ gfxDebug() << "Failed getting file loader for WR font";
+ return false;
+ }
+ RefPtr<IDWriteLocalFontFileLoader> localLoader;
+ loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader),
+ (void**)getter_AddRefs(localLoader));
+ if (!localLoader) {
+ gfxDebug() << "Failed querying loader interface for WR font";
+ return false;
+ }
+ UINT32 pathLen;
+ hr = localLoader->GetFilePathLengthFromKey(key, keySize, &pathLen);
+ if (FAILED(hr)) {
+ gfxDebug() << "Failed getting path length for WR font";
+ return false;
+ }
+ aFileName.resize(pathLen + 1);
+ hr = localLoader->GetFilePathFromKey(key, keySize, aFileName.data(),
+ pathLen + 1);
+ if (FAILED(hr) || aFileName.back() != 0) {
+ gfxDebug() << "Failed getting path for WR font";
+ return false;
+ }
+ DWORD attribs = GetFileAttributesW(aFileName.data());
+ if (attribs == INVALID_FILE_ATTRIBUTES) {
+ gfxDebug() << "Invalid file \"" << aFileName.data() << "\" for WR font";
+ return false;
+ }
+ // We leave the null terminator at the end of the returned file name.
+ return true;
+}
+
+bool UnscaledFontDWrite::GetFontDescriptor(FontDescriptorOutput aCb,
+ void* aBaton) {
+ if (!mFont) {
+ return false;
+ }
+
+ std::vector<WCHAR> fileName;
+ if (!GetFontFileName(mFontFace, fileName)) {
+ return false;
+ }
+ uint32_t index = mFontFace->GetIndex();
+
+ aCb(reinterpret_cast<const uint8_t*>(fileName.data()),
+ fileName.size() * sizeof(WCHAR), index, aBaton);
+ return true;
+}
+
+ScaledFontDWrite::InstanceData::InstanceData(
+ const wr::FontInstanceOptions* aOptions,
+ const wr::FontInstancePlatformOptions* aPlatformOptions)
+ : mUseEmbeddedBitmap(false),
+ mApplySyntheticBold(false),
+ mRenderingMode(DWRITE_RENDERING_MODE_DEFAULT),
+ mGamma(2.2f),
+ mContrast(1.0f),
+ mClearTypeLevel(1.0f) {
+ if (aOptions) {
+ if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
+ mUseEmbeddedBitmap = true;
+ }
+ if (aOptions->flags & wr::FontInstanceFlags::SYNTHETIC_BOLD) {
+ mApplySyntheticBold = true;
+ }
+ if (aOptions->flags & wr::FontInstanceFlags::FORCE_GDI) {
+ mRenderingMode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
+ } else if (aOptions->flags & wr::FontInstanceFlags::FORCE_SYMMETRIC) {
+ mRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
+ } else if (aOptions->flags & wr::FontInstanceFlags::NO_SYMMETRIC) {
+ mRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
+ }
+ }
+ if (aPlatformOptions) {
+ mGamma = aPlatformOptions->gamma / 100.0f;
+ mContrast = aPlatformOptions->contrast / 100.0f;
+ mClearTypeLevel = aPlatformOptions->cleartype_level / 100.0f;
+ }
+}
+
+// Helper for ScaledFontDWrite::GetFontInstanceData: if the font has variation
+// axes, get their current values into the aOutput vector.
+static void GetVariationsFromFontFace(IDWriteFontFace* aFace,
+ std::vector<FontVariation>* aOutput) {
+ RefPtr<IDWriteFontFace5> ff5;
+ aFace->QueryInterface(__uuidof(IDWriteFontFace5),
+ (void**)getter_AddRefs(ff5));
+ if (!ff5 || !ff5->HasVariations()) {
+ return;
+ }
+
+ uint32_t count = ff5->GetFontAxisValueCount();
+ if (!count) {
+ return;
+ }
+
+ RefPtr<IDWriteFontResource> res;
+ if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
+ return;
+ }
+
+ std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
+ if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
+ return;
+ }
+
+ aOutput->reserve(count);
+ for (uint32_t i = 0; i < count; i++) {
+ DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
+ if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
+ float v = values[i].value;
+ uint32_t t = TRUETYPE_TAG(
+ uint8_t(values[i].axisTag), uint8_t(values[i].axisTag >> 8),
+ uint8_t(values[i].axisTag >> 16), uint8_t(values[i].axisTag >> 24));
+ aOutput->push_back(FontVariation{uint32_t(t), float(v)});
+ }
+ }
+}
+
+bool ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb,
+ void* aBaton) {
+ InstanceData instance(this);
+
+ // If the font has variations, get the list of axis values.
+ std::vector<FontVariation> variations;
+ GetVariationsFromFontFace(mFontFace, &variations);
+
+ aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
+ variations.data(), variations.size(), aBaton);
+
+ return true;
+}
+
+bool ScaledFontDWrite::GetWRFontInstanceOptions(
+ Maybe<wr::FontInstanceOptions>* aOutOptions,
+ Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
+ std::vector<FontVariation>* aOutVariations) {
+ wr::FontInstanceOptions options;
+ options.render_mode = wr::ToFontRenderMode(GetDefaultAAMode());
+ options.flags = wr::FontInstanceFlags{0};
+ if (HasSyntheticBold()) {
+ options.flags |= wr::FontInstanceFlags::SYNTHETIC_BOLD;
+ }
+ if (UseEmbeddedBitmaps()) {
+ options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
+ }
+ if (ForceGDIMode()) {
+ options.flags |= wr::FontInstanceFlags::FORCE_GDI;
+ } else {
+ options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
+ }
+ switch (GetRenderingMode()) {
+ case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
+ options.flags |= wr::FontInstanceFlags::FORCE_SYMMETRIC;
+ break;
+ case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
+ options.flags |= wr::FontInstanceFlags::NO_SYMMETRIC;
+ break;
+ default:
+ break;
+ }
+ if (Factory::GetBGRSubpixelOrder()) {
+ options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
+ }
+ options.bg_color = wr::ToColorU(DeviceColor());
+ options.synthetic_italics =
+ wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
+
+ wr::FontInstancePlatformOptions platformOptions;
+ platformOptions.gamma = uint16_t(std::round(mGamma * 100.0f));
+ platformOptions.contrast =
+ uint8_t(std::round(std::min(mContrast, 1.0f) * 100.0f));
+ platformOptions.cleartype_level =
+ uint8_t(std::round(std::min(mClearTypeLevel, 1.0f) * 100.0f));
+
+ *aOutOptions = Some(options);
+ *aOutPlatformOptions = Some(platformOptions);
+
+ GetVariationsFromFontFace(mFontFace, aOutVariations);
+
+ return true;
+}
+
+// Helper for UnscaledFontDWrite::CreateScaledFont: create a clone of the
+// given IDWriteFontFace, with specified variation-axis values applied.
+// Returns nullptr in case of failure.
+static already_AddRefed<IDWriteFontFace5> CreateFaceWithVariations(
+ IDWriteFontFace* aFace, DWRITE_FONT_SIMULATIONS aSimulations,
+ const FontVariation* aVariations = nullptr, uint32_t aNumVariations = 0) {
+ auto makeDWriteAxisTag = [](uint32_t aTag) {
+ return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
+ (aTag >> 8) & 0xff, aTag & 0xff);
+ };
+
+ RefPtr<IDWriteFontFace5> ff5;
+ aFace->QueryInterface(__uuidof(IDWriteFontFace5),
+ (void**)getter_AddRefs(ff5));
+ if (!ff5) {
+ return nullptr;
+ }
+
+ RefPtr<IDWriteFontResource> res;
+ if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
+ return nullptr;
+ }
+
+ std::vector<DWRITE_FONT_AXIS_VALUE> fontAxisValues;
+ if (aNumVariations) {
+ fontAxisValues.reserve(aNumVariations);
+ for (uint32_t i = 0; i < aNumVariations; i++) {
+ DWRITE_FONT_AXIS_VALUE axisValue = {
+ makeDWriteAxisTag(aVariations[i].mTag), aVariations[i].mValue};
+ fontAxisValues.push_back(axisValue);
+ }
+ } else {
+ uint32_t count = ff5->GetFontAxisValueCount();
+ if (count) {
+ fontAxisValues.resize(count);
+ if (FAILED(ff5->GetFontAxisValues(fontAxisValues.data(), count))) {
+ fontAxisValues.clear();
+ }
+ }
+ }
+
+ RefPtr<IDWriteFontFace5> newFace;
+ if (FAILED(res->CreateFontFace(aSimulations, fontAxisValues.data(),
+ fontAxisValues.size(),
+ getter_AddRefs(newFace)))) {
+ return nullptr;
+ }
+
+ return newFace.forget();
+}
+
+bool UnscaledFontDWrite::InitBold() {
+ if (mFontFaceBold) {
+ return true;
+ }
+
+ DWRITE_FONT_SIMULATIONS sims = mFontFace->GetSimulations();
+ if (sims & DWRITE_FONT_SIMULATIONS_BOLD) {
+ mFontFaceBold = mFontFace;
+ return true;
+ }
+ sims |= DWRITE_FONT_SIMULATIONS_BOLD;
+
+ RefPtr<IDWriteFontFace5> ff5 = CreateFaceWithVariations(mFontFace, sims);
+ if (ff5) {
+ mFontFaceBold = ff5;
+ } else {
+ UINT32 numFiles = 0;
+ if (FAILED(mFontFace->GetFiles(&numFiles, nullptr))) {
+ return false;
+ }
+ StackArray<IDWriteFontFile*, 1> files(numFiles);
+ if (FAILED(mFontFace->GetFiles(&numFiles, files.data()))) {
+ return false;
+ }
+ HRESULT hr = Factory::GetDWriteFactory()->CreateFontFace(
+ mFontFace->GetType(), numFiles, files.data(), mFontFace->GetIndex(),
+ sims, getter_AddRefs(mFontFaceBold));
+ for (UINT32 i = 0; i < numFiles; ++i) {
+ files[i]->Release();
+ }
+ if (FAILED(hr) || !mFontFaceBold) {
+ return false;
+ }
+ }
+ return true;
+}
+
+already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFont(
+ Float aGlyphSize, const uint8_t* aInstanceData,
+ uint32_t aInstanceDataLength, const FontVariation* aVariations,
+ uint32_t aNumVariations) {
+ if (aInstanceDataLength < sizeof(ScaledFontDWrite::InstanceData)) {
+ gfxWarning() << "DWrite scaled font instance data is truncated.";
+ return nullptr;
+ }
+ const ScaledFontDWrite::InstanceData& instanceData =
+ *reinterpret_cast<const ScaledFontDWrite::InstanceData*>(aInstanceData);
+
+ IDWriteFontFace* face = mFontFace;
+ if (instanceData.mApplySyntheticBold) {
+ if (!InitBold()) {
+ gfxWarning() << "Failed creating bold IDWriteFontFace.";
+ return nullptr;
+ }
+ face = mFontFaceBold;
+ }
+ DWRITE_FONT_SIMULATIONS sims = face->GetSimulations();
+
+ // If variations are required, we create a separate IDWriteFontFace5 with
+ // the requested settings applied.
+ RefPtr<IDWriteFontFace5> ff5;
+ if (aNumVariations) {
+ ff5 =
+ CreateFaceWithVariations(mFontFace, sims, aVariations, aNumVariations);
+ if (ff5) {
+ face = ff5;
+ } else {
+ gfxWarning() << "Failed to create IDWriteFontFace5 with variations.";
+ }
+ }
+
+ RefPtr<ScaledFontBase> scaledFont = new ScaledFontDWrite(
+ face, this, aGlyphSize, instanceData.mUseEmbeddedBitmap,
+ instanceData.mRenderingMode, nullptr, instanceData.mGamma,
+ instanceData.mContrast, instanceData.mClearTypeLevel);
+
+ return scaledFont.forget();
+}
+
+already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFontFromWRFont(
+ Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
+ const wr::FontInstancePlatformOptions* aPlatformOptions,
+ const FontVariation* aVariations, uint32_t aNumVariations) {
+ ScaledFontDWrite::InstanceData instanceData(aOptions, aPlatformOptions);
+ return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
+ sizeof(instanceData), aVariations, aNumVariations);
+}
+
+AntialiasMode ScaledFontDWrite::GetDefaultAAMode() {
+ AntialiasMode defaultMode = GetSystemDefaultAAMode();
+
+ switch (defaultMode) {
+ case AntialiasMode::SUBPIXEL:
+ case AntialiasMode::DEFAULT:
+ if (mClearTypeLevel == 0.0f) {
+ defaultMode = AntialiasMode::GRAY;
+ }
+ break;
+ case AntialiasMode::GRAY:
+ if (!DoGrayscale(mFontFace, mSize)) {
+ defaultMode = AntialiasMode::NONE;
+ }
+ break;
+ case AntialiasMode::NONE:
+ break;
+ }
+
+ return defaultMode;
+}
+
+#ifdef USE_CAIRO_SCALED_FONT
+cairo_font_face_t* ScaledFontDWrite::CreateCairoFontFace(
+ cairo_font_options_t* aFontOptions) {
+ if (!mFontFace) {
+ return nullptr;
+ }
+
+ return cairo_dwrite_font_face_create_for_dwrite_fontface(nullptr, mFontFace);
+}
+
+void ScaledFontDWrite::PrepareCairoScaledFont(cairo_scaled_font_t* aFont) {
+ if (mRenderingMode == DWRITE_RENDERING_MODE_GDI_CLASSIC) {
+ cairo_dwrite_scaled_font_set_force_GDI_classic(aFont, true);
+ }
+}
+#endif
+
+already_AddRefed<UnscaledFont> UnscaledFontDWrite::CreateFromFontDescriptor(
+ const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
+ if (aDataLength == 0) {
+ gfxWarning() << "DWrite font descriptor is truncated.";
+ return nullptr;
+ }
+
+ RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
+ if (!factory) {
+ return nullptr;
+ }
+ RefPtr<IDWriteFontFile> fontFile;
+ HRESULT hr = factory->CreateFontFileReference((const WCHAR*)aData, nullptr,
+ getter_AddRefs(fontFile));
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+ BOOL isSupported;
+ DWRITE_FONT_FILE_TYPE fileType;
+ DWRITE_FONT_FACE_TYPE faceType;
+ UINT32 numFaces;
+ hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numFaces);
+ if (FAILED(hr) || !isSupported || aIndex >= numFaces) {
+ return nullptr;
+ }
+ IDWriteFontFile* fontFiles[1] = {fontFile.get()};
+ RefPtr<IDWriteFontFace> fontFace;
+ hr = factory->CreateFontFace(faceType, 1, fontFiles, aIndex,
+ DWRITE_FONT_SIMULATIONS_NONE,
+ getter_AddRefs(fontFace));
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+ RefPtr<UnscaledFont> unscaledFont = new UnscaledFontDWrite(fontFace, nullptr);
+ return unscaledFont.forget();
+}
+
+} // namespace gfx
+} // namespace mozilla