diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/2d/ScaledFontDWrite.cpp | |
parent | Initial commit. (diff) | |
download | firefox-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.cpp | 758 |
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 |