diff options
Diffstat (limited to 'gfx/thebes/gfxDWriteFonts.cpp')
-rw-r--r-- | gfx/thebes/gfxDWriteFonts.cpp | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp new file mode 100644 index 000000000..96a935245 --- /dev/null +++ b/gfx/thebes/gfxDWriteFonts.cpp @@ -0,0 +1,709 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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 "gfxDWriteFonts.h" + +#include "mozilla/MemoryReporting.h" + +#include <algorithm> +#include "gfxDWriteFontList.h" +#include "gfxContext.h" +#include "gfxTextRun.h" +#include <dwrite.h> + +#include "harfbuzz/hb.h" + +using namespace mozilla; +using namespace mozilla::gfx; + +// This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common, +// but we can't declare it in the gfxFont.h or gfxFontUtils.h headers +// because those are exported, and the cairo headers aren't. +static inline cairo_antialias_t +GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption) +{ + switch (anAntialiasOption) { + default: + case gfxFont::kAntialiasDefault: + return CAIRO_ANTIALIAS_DEFAULT; + case gfxFont::kAntialiasNone: + return CAIRO_ANTIALIAS_NONE; + case gfxFont::kAntialiasGrayscale: + return CAIRO_ANTIALIAS_GRAY; + case gfxFont::kAntialiasSubpixel: + return CAIRO_ANTIALIAS_SUBPIXEL; + } +} + +// Code to determine whether Windows is set to use ClearType font smoothing; +// based on private functions in cairo-win32-font.c + +#ifndef SPI_GETFONTSMOOTHINGTYPE +#define SPI_GETFONTSMOOTHINGTYPE 0x200a +#endif +#ifndef FE_FONTSMOOTHINGCLEARTYPE +#define FE_FONTSMOOTHINGCLEARTYPE 2 +#endif + +static bool +UsingClearType() +{ + BOOL fontSmoothing; + if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0) || + !fontSmoothing) + { + return false; + } + + UINT type; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0) && + type == FE_FONTSMOOTHINGCLEARTYPE) + { + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// gfxDWriteFont +gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry, + const gfxFontStyle *aFontStyle, + bool aNeedsBold, + AntialiasOption anAAOption) + : gfxFont(aFontEntry, aFontStyle, anAAOption) + , mCairoFontFace(nullptr) + , mMetrics(nullptr) + , mSpaceGlyph(0) + , mNeedsOblique(false) + , mNeedsBold(aNeedsBold) + , mUseSubpixelPositions(false) + , mAllowManualShowGlyphs(true) +{ + gfxDWriteFontEntry *fe = + static_cast<gfxDWriteFontEntry*>(aFontEntry); + nsresult rv; + DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE; + if ((GetStyle()->style != NS_FONT_STYLE_NORMAL) && + fe->IsUpright() && + GetStyle()->allowSyntheticStyle) { + // For this we always use the font_matrix for uniformity. Not the + // DWrite simulation. + mNeedsOblique = true; + } + if (aNeedsBold) { + sims |= DWRITE_FONT_SIMULATIONS_BOLD; + } + + rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims); + + if (NS_FAILED(rv)) { + mIsValid = false; + return; + } + + ComputeMetrics(anAAOption); +} + +gfxDWriteFont::~gfxDWriteFont() +{ + if (mCairoFontFace) { + cairo_font_face_destroy(mCairoFontFace); + } + if (mScaledFont) { + cairo_scaled_font_destroy(mScaledFont); + } + delete mMetrics; +} + +gfxFont* +gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption) +{ + return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()), + &mStyle, mNeedsBold, anAAOption); +} + +const gfxFont::Metrics& +gfxDWriteFont::GetHorizontalMetrics() +{ + return *mMetrics; +} + +bool +gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics) +{ + gfxFontStyle style(mStyle); + style.weight = 700; + bool needsBold; + + gfxFontEntry* fe = + gfxPlatformFontList::PlatformFontList()-> + FindFontForFamily(NS_LITERAL_STRING("Arial"), &style, needsBold); + if (!fe || fe == mFontEntry) { + return false; + } + + RefPtr<gfxFont> font = fe->FindOrMakeFont(&style, needsBold); + gfxDWriteFont *dwFont = static_cast<gfxDWriteFont*>(font.get()); + dwFont->mFontFace->GetMetrics(aFontMetrics); + + return true; +} + +void +gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) +{ + DWRITE_FONT_METRICS fontMetrics; + if (!(mFontEntry->Weight() == 900 && + !mFontEntry->IsUserFont() && + mFontEntry->Name().EqualsLiteral("Arial Black") && + GetFakeMetricsForArialBlack(&fontMetrics))) + { + mFontFace->GetMetrics(&fontMetrics); + } + + if (mStyle.sizeAdjust >= 0.0) { + gfxFloat aspect = (gfxFloat)fontMetrics.xHeight / + fontMetrics.designUnitsPerEm; + mAdjustedSize = mStyle.GetAdjustedSize(aspect); + } else { + mAdjustedSize = mStyle.size; + } + + // Note that GetMeasuringMode depends on mAdjustedSize + if ((anAAOption == gfxFont::kAntialiasDefault && + UsingClearType() && + GetMeasuringMode() == DWRITE_MEASURING_MODE_NATURAL) || + anAAOption == gfxFont::kAntialiasSubpixel) + { + mUseSubpixelPositions = true; + // note that this may be reset to FALSE if we determine that a bitmap + // strike is going to be used + } + + gfxDWriteFontEntry *fe = + static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); + if (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) { + mAdjustedSize = NS_lround(mAdjustedSize); + mUseSubpixelPositions = false; + // if we have bitmaps, we need to tell Cairo NOT to use subpixel AA, + // to avoid the manual-subpixel codepath in cairo-d2d-surface.cpp + // which fails to render bitmap glyphs (see bug 626299). + // This option will be passed to the cairo_dwrite_scaled_font_t + // after creation. + mAllowManualShowGlyphs = false; + } + + mMetrics = new gfxFont::Metrics; + ::memset(mMetrics, 0, sizeof(*mMetrics)); + + mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm); + + mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor; + mMetrics->capHeight = fontMetrics.capHeight * mFUnitsConvFactor; + + mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor); + mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor); + mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent; + + mMetrics->emHeight = mAdjustedSize; + mMetrics->emAscent = mMetrics->emHeight * + mMetrics->maxAscent / mMetrics->maxHeight; + mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; + + mMetrics->maxAdvance = mAdjustedSize; + + // try to get the true maxAdvance value from 'hhea' + gfxFontEntry::AutoTable hheaTable(GetFontEntry(), + TRUETYPE_TAG('h','h','e','a')); + if (hheaTable) { + uint32_t len; + const MetricsHeader* hhea = + reinterpret_cast<const MetricsHeader*> + (hb_blob_get_data(hheaTable, &len)); + if (len >= sizeof(MetricsHeader)) { + mMetrics->maxAdvance = + uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor; + } + } + + mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0); + mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor); + + UINT32 ucs = L' '; + UINT16 glyph; + HRESULT hr = mFontFace->GetGlyphIndicesW(&ucs, 1, &glyph); + if (FAILED(hr)) { + mMetrics->spaceWidth = 0; + } else { + mSpaceGlyph = glyph; + mMetrics->spaceWidth = MeasureGlyphWidth(glyph); + } + + // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x' + // if the table is not available or if using hinted/pixel-snapped widths + if (mUseSubpixelPositions) { + mMetrics->aveCharWidth = 0; + gfxFontEntry::AutoTable os2Table(GetFontEntry(), + TRUETYPE_TAG('O','S','/','2')); + if (os2Table) { + uint32_t len; + const OS2Table* os2 = + reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len)); + if (len >= 4) { + // Not checking against sizeof(mozilla::OS2Table) here because older + // versions of the table have different sizes; we only need the first + // two 16-bit fields here. + mMetrics->aveCharWidth = + int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor; + } + } + } + + if (mMetrics->aveCharWidth < 1) { + ucs = L'x'; + if (SUCCEEDED(mFontFace->GetGlyphIndicesW(&ucs, 1, &glyph))) { + mMetrics->aveCharWidth = MeasureGlyphWidth(glyph); + } + if (mMetrics->aveCharWidth < 1) { + // Let's just assume the X is square. + mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor; + } + } + + ucs = L'0'; + if (SUCCEEDED(mFontFace->GetGlyphIndicesW(&ucs, 1, &glyph))) { + mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph); + } + if (mMetrics->zeroOrAveCharWidth < 1) { + mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; + } + + mMetrics->underlineOffset = + fontMetrics.underlinePosition * mFUnitsConvFactor; + mMetrics->underlineSize = + fontMetrics.underlineThickness * mFUnitsConvFactor; + mMetrics->strikeoutOffset = + fontMetrics.strikethroughPosition * mFUnitsConvFactor; + mMetrics->strikeoutSize = + fontMetrics.strikethroughThickness * mFUnitsConvFactor; + + SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); + +#if 0 + printf("Font: %p (%s) size: %f\n", this, + NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); + printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); + printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); + printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); + printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f\n", + mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth); + printf(" xHeight: %f capHeight: %f\n", mMetrics->xHeight, mMetrics->capHeight); + printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n", + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize); +#endif +} + +using namespace mozilla; // for AutoSwap_* types + +struct EBLCHeader { + AutoSwap_PRUint32 version; + AutoSwap_PRUint32 numSizes; +}; + +struct SbitLineMetrics { + int8_t ascender; + int8_t descender; + uint8_t widthMax; + int8_t caretSlopeNumerator; + int8_t caretSlopeDenominator; + int8_t caretOffset; + int8_t minOriginSB; + int8_t minAdvanceSB; + int8_t maxBeforeBL; + int8_t minAfterBL; + int8_t pad1; + int8_t pad2; +}; + +struct BitmapSizeTable { + AutoSwap_PRUint32 indexSubTableArrayOffset; + AutoSwap_PRUint32 indexTablesSize; + AutoSwap_PRUint32 numberOfIndexSubTables; + AutoSwap_PRUint32 colorRef; + SbitLineMetrics hori; + SbitLineMetrics vert; + AutoSwap_PRUint16 startGlyphIndex; + AutoSwap_PRUint16 endGlyphIndex; + uint8_t ppemX; + uint8_t ppemY; + uint8_t bitDepth; + uint8_t flags; +}; + +typedef EBLCHeader EBSCHeader; + +struct BitmapScaleTable { + SbitLineMetrics hori; + SbitLineMetrics vert; + uint8_t ppemX; + uint8_t ppemY; + uint8_t substitutePpemX; + uint8_t substitutePpemY; +}; + +bool +gfxDWriteFont::HasBitmapStrikeForSize(uint32_t aSize) +{ + uint8_t *tableData; + uint32_t len; + void *tableContext; + BOOL exists; + HRESULT hr = + mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'L', 'C'), + (const void**)&tableData, &len, + &tableContext, &exists); + if (FAILED(hr)) { + return false; + } + + bool hasStrike = false; + // not really a loop, but this lets us use 'break' to skip out of the block + // as soon as we know the answer, and skips it altogether if the table is + // not present + while (exists) { + if (len < sizeof(EBLCHeader)) { + break; + } + const EBLCHeader *hdr = reinterpret_cast<const EBLCHeader*>(tableData); + if (hdr->version != 0x00020000) { + break; + } + uint32_t numSizes = hdr->numSizes; + if (numSizes > 0xffff) { // sanity-check, prevent overflow below + break; + } + if (len < sizeof(EBLCHeader) + numSizes * sizeof(BitmapSizeTable)) { + break; + } + const BitmapSizeTable *sizeTable = + reinterpret_cast<const BitmapSizeTable*>(hdr + 1); + for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { + if (sizeTable->ppemX == aSize && sizeTable->ppemY == aSize) { + // we ignore a strike that contains fewer than 4 glyphs, + // as that probably indicates a font such as Courier New + // that provides bitmaps ONLY for the "shading" characters + // U+2591..2593 + hasStrike = (uint16_t(sizeTable->endGlyphIndex) >= + uint16_t(sizeTable->startGlyphIndex) + 3); + break; + } + } + // if we reach here, we didn't find a strike; unconditionally break + // out of the while-loop block + break; + } + mFontFace->ReleaseFontTable(tableContext); + + if (hasStrike) { + return true; + } + + // if we didn't find a real strike, check if the font calls for scaling + // another bitmap to this size + hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'S', 'C'), + (const void**)&tableData, &len, + &tableContext, &exists); + if (FAILED(hr)) { + return false; + } + + while (exists) { + if (len < sizeof(EBSCHeader)) { + break; + } + const EBSCHeader *hdr = reinterpret_cast<const EBSCHeader*>(tableData); + if (hdr->version != 0x00020000) { + break; + } + uint32_t numSizes = hdr->numSizes; + if (numSizes > 0xffff) { + break; + } + if (len < sizeof(EBSCHeader) + numSizes * sizeof(BitmapScaleTable)) { + break; + } + const BitmapScaleTable *scaleTable = + reinterpret_cast<const BitmapScaleTable*>(hdr + 1); + for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { + if (scaleTable->ppemX == aSize && scaleTable->ppemY == aSize) { + hasStrike = true; + break; + } + } + break; + } + mFontFace->ReleaseFontTable(tableContext); + + return hasStrike; +} + +uint32_t +gfxDWriteFont::GetSpaceGlyph() +{ + return mSpaceGlyph; +} + +bool +gfxDWriteFont::SetupCairoFont(DrawTarget* aDrawTarget) +{ + cairo_scaled_font_t *scaledFont = GetCairoScaledFont(); + if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) { + // Don't cairo_set_scaled_font as that would propagate the error to + // the cairo_t, precluding any further drawing. + return false; + } + cairo_set_scaled_font(gfxFont::RefCairo(aDrawTarget), scaledFont); + return true; +} + +bool +gfxDWriteFont::IsValid() const +{ + return mFontFace != nullptr; +} + +IDWriteFontFace* +gfxDWriteFont::GetFontFace() +{ + return mFontFace.get(); +} + +cairo_font_face_t * +gfxDWriteFont::CairoFontFace() +{ + if (!mCairoFontFace) { +#ifdef CAIRO_HAS_DWRITE_FONT + mCairoFontFace = + cairo_dwrite_font_face_create_for_dwrite_fontface( + ((gfxDWriteFontEntry*)mFontEntry.get())->mFont, mFontFace); +#endif + } + return mCairoFontFace; +} + + +cairo_scaled_font_t * +gfxDWriteFont::GetCairoScaledFont() +{ + if (!mScaledFont) { + cairo_matrix_t sizeMatrix; + cairo_matrix_t identityMatrix; + + cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); + cairo_matrix_init_identity(&identityMatrix); + + cairo_font_options_t *fontOptions = cairo_font_options_create(); + if (mNeedsOblique) { + double skewfactor = OBLIQUE_SKEW_FACTOR; + + cairo_matrix_t style; + cairo_matrix_init(&style, + 1, //xx + 0, //yx + -1 * skewfactor, //xy + 1, //yy + 0, //x0 + 0); //y0 + cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); + } + + if (mAntialiasOption != kAntialiasDefault) { + cairo_font_options_set_antialias(fontOptions, + GetCairoAntialiasOption(mAntialiasOption)); + } + + mScaledFont = cairo_scaled_font_create(CairoFontFace(), + &sizeMatrix, + &identityMatrix, + fontOptions); + cairo_font_options_destroy(fontOptions); + + cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont, + mAllowManualShowGlyphs); + + cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont, + GetForceGDIClassic()); + } + + NS_ASSERTION(mAdjustedSize == 0.0 || + cairo_scaled_font_status(mScaledFont) + == CAIRO_STATUS_SUCCESS, + "Failed to make scaled font"); + + return mScaledFont; +} + +gfxFont::RunMetrics +gfxDWriteFont::Measure(const gfxTextRun* aTextRun, + uint32_t aStart, uint32_t aEnd, + BoundingBoxType aBoundingBoxType, + DrawTarget* aRefDrawTarget, + Spacing* aSpacing, + uint16_t aOrientation) +{ + gfxFont::RunMetrics metrics = + gfxFont::Measure(aTextRun, aStart, aEnd, aBoundingBoxType, + aRefDrawTarget, aSpacing, aOrientation); + + // if aBoundingBoxType is LOOSE_INK_EXTENTS + // and the underlying cairo font may be antialiased, + // we can't trust Windows to have considered all the pixels + // so we need to add "padding" to the bounds. + // (see bugs 475968, 439831, compare also bug 445087) + if (aBoundingBoxType == LOOSE_INK_EXTENTS && + mAntialiasOption != kAntialiasNone && + GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_CLASSIC && + metrics.mBoundingBox.width > 0) { + metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); + metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3; + } + + return metrics; +} + +bool +gfxDWriteFont::ProvidesGlyphWidths() const +{ + return !mUseSubpixelPositions || + (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD); +} + +int32_t +gfxDWriteFont::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID) +{ + if (!mGlyphWidths) { + mGlyphWidths = MakeUnique<nsDataHashtable<nsUint32HashKey,int32_t>>(128); + } + + int32_t width = -1; + if (mGlyphWidths->Get(aGID, &width)) { + return width; + } + + width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0); + mGlyphWidths->Put(aGID, width); + return width; +} + +already_AddRefed<GlyphRenderingOptions> +gfxDWriteFont::GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams) +{ + if (UsingClearType()) { + return Factory::CreateDWriteGlyphRenderingOptions( + gfxWindowsPlatform::GetPlatform()->GetRenderingParams(GetForceGDIClassic() ? + gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : gfxWindowsPlatform::TEXT_RENDERING_NORMAL)); + } else { + return Factory::CreateDWriteGlyphRenderingOptions(gfxWindowsPlatform::GetPlatform()-> + GetRenderingParams(gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE)); + } +} + +bool +gfxDWriteFont::GetForceGDIClassic() +{ + return static_cast<gfxDWriteFontEntry*>(mFontEntry.get())->GetForceGDIClassic() && + cairo_dwrite_get_cleartype_rendering_mode() < 0 && + GetAdjustedSize() <= + gfxDWriteFontList::PlatformFontList()->GetForceGDIClassicMaxFontSize(); +} + +DWRITE_MEASURING_MODE +gfxDWriteFont::GetMeasuringMode() +{ + return GetForceGDIClassic() + ? DWRITE_MEASURING_MODE_GDI_CLASSIC + : gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode(); +} + +gfxFloat +gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph) +{ + DWRITE_GLYPH_METRICS metrics; + HRESULT hr; + if (mUseSubpixelPositions) { + hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE); + if (SUCCEEDED(hr)) { + return metrics.advanceWidth * mFUnitsConvFactor; + } + } else { + hr = mFontFace->GetGdiCompatibleGlyphMetrics( + FLOAT(mAdjustedSize), 1.0f, nullptr, + GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL, + &aGlyph, 1, &metrics, FALSE); + if (SUCCEEDED(hr)) { + return NS_lround(metrics.advanceWidth * mFUnitsConvFactor); + } + } + return 0; +} + +void +gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, + FontCacheSizes* aSizes) const +{ + gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); + aSizes->mFontInstances += aMallocSizeOf(mMetrics); + if (mGlyphWidths) { + aSizes->mFontInstances += + mGlyphWidths->ShallowSizeOfIncludingThis(aMallocSizeOf); + } +} + +void +gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, + FontCacheSizes* aSizes) const +{ + aSizes->mFontInstances += aMallocSizeOf(this); + AddSizeOfExcludingThis(aMallocSizeOf, aSizes); +} + +already_AddRefed<ScaledFont> +gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget) +{ + bool wantCairo = aTarget->GetBackendType() == BackendType::CAIRO; + if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) { + RefPtr<ScaledFont> scaledFont(mAzureScaledFont); + return scaledFont.forget(); + } + + NativeFont nativeFont; + nativeFont.mType = NativeFontType::DWRITE_FONT_FACE; + nativeFont.mFont = GetFontFace(); + + if (wantCairo) { + mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont, + GetAdjustedSize(), + GetCairoScaledFont()); + } else if (aTarget->GetBackendType() == BackendType::SKIA) { + gfxDWriteFontEntry *fe = + static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); + bool useEmbeddedBitmap = (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))); + + const gfxFontStyle* fontStyle = GetStyle(); + mAzureScaledFont = + Factory::CreateScaledFontForDWriteFont(mFontFace, fontStyle, + GetAdjustedSize(), + useEmbeddedBitmap, + GetForceGDIClassic()); + } else { + mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont, + GetAdjustedSize()); + } + + mAzureScaledFontIsCairo = wantCairo; + + RefPtr<ScaledFont> scaledFont(mAzureScaledFont); + return scaledFont.forget(); +} |