Bug 1872545 - Hoist color-font palette cache out of TextRunDrawParams to the nsPresContext or CanvasRenderingContext2D, for greater effectiveness. r=gfx-reviewers,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D197463
This commit is contained in:
Jonathan Kew 2024-01-02 13:12:29 +00:00
Родитель a8db6f508c
Коммит 5f8f825e05
15 изменённых файлов: 123 добавлений и 86 удалений

Просмотреть файл

@ -4251,7 +4251,8 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
: public nsBidiPresUtils::BidiProcessor {
using Style = CanvasRenderingContext2D::Style;
CanvasBidiProcessor() : nsBidiPresUtils::BidiProcessor() {
explicit CanvasBidiProcessor(gfx::COLRFonts::PaletteCache& aPaletteCache)
: mPaletteCache(aPaletteCache) {
if (StaticPrefs::gfx_missing_fonts_notify()) {
mMissingFonts = MakeUnique<gfxMissingFontRecorder>();
}
@ -4496,7 +4497,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
}
gfxContext thebes(target, /* aPreserveTransform */ true);
gfxTextRun::DrawParams params(&thebes);
gfxTextRun::DrawParams params(&thebes, mPaletteCache);
params.allowGDI = false;
@ -4566,6 +4567,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
// current font
gfxFontGroup* mFontgrp = nullptr;
// palette cache for COLR font rendering
gfx::COLRFonts::PaletteCache& mPaletteCache;
// spacing adjustments to be applied
gfx::Float mLetterSpacing = 0.0f;
gfx::Float mWordSpacing = 0.0f;
@ -4687,7 +4691,7 @@ UniquePtr<TextMetrics> CanvasRenderingContext2D::DrawOrMeasureText(
return nullptr;
}
CanvasBidiProcessor processor;
CanvasBidiProcessor processor(mPaletteCache);
// If we don't have a ComputedStyle, we can't set up vertical-text flags
// (for now, at least; perhaps we need new Canvas API to control this).

Просмотреть файл

@ -1119,6 +1119,8 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
ColorStyleCacheEntry ParseColorSlow(const nsACString&);
mozilla::gfx::COLRFonts::PaletteCache mPaletteCache;
friend class CanvasGeneralPattern;
friend class AdjustedTarget;
friend class AdjustedTargetForShadow;

Просмотреть файл

@ -334,7 +334,8 @@ void nsFontMetrics::DrawString(const char* aString, uint32_t aLength,
pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
gfxTextRun::DrawParams params(aContext);
gfx::COLRFonts::PaletteCache paletteCache;
gfxTextRun::DrawParams params(aContext, paletteCache);
params.provider = &provider;
textRun->Draw(range, pt, params);
}
@ -359,7 +360,8 @@ void nsFontMetrics::DrawString(
pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
gfxTextRun::DrawParams params(aContext);
gfx::COLRFonts::PaletteCache paletteCache;
gfxTextRun::DrawParams params(aContext, paletteCache);
params.provider = &provider;
textRun->Draw(range, pt, params);
}

Просмотреть файл

@ -2670,4 +2670,20 @@ FontPaletteValueSet::PaletteValues* FontPaletteValueSet::Insert(
return &entry->mValue;
}
nsTArray<sRGBColor>* COLRFonts::PaletteCache::GetPaletteFor(
gfxFontEntry* aFontEntry, nsAtom* aPaletteName) {
auto entry = Lookup(std::pair(aFontEntry, aPaletteName));
if (!entry) {
CacheData newData;
newData.mKey = std::pair(aFontEntry, aPaletteName);
gfxFontEntry::AutoHBFace face = aFontEntry->GetHBFace();
newData.mPalette = COLRFonts::SetupColorPalette(
face, mPaletteValueSet, aPaletteName, aFontEntry->FamilyName());
entry.Set(std::move(newData));
}
return entry.Data().mPalette.get();
}
} // end namespace mozilla::gfx

Просмотреть файл

@ -6,7 +6,9 @@
#ifndef COLR_FONTS_H
#define COLR_FONTS_H
#include "gfxFontEntry.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/MruCache.h"
#include "mozilla/UniquePtr.h"
#include "nsAtom.h"
#include "nsTArray.h"
@ -90,6 +92,37 @@ class FontPaletteValueSet {
class COLRFonts {
public:
// MRU cache used for resolved color-font palettes, to avoid reconstructing
// the palette for each glyph rendered with a given font.
using CacheKey = std::pair<RefPtr<gfxFontEntry>, RefPtr<nsAtom>>;
struct CacheData {
CacheKey mKey;
mozilla::UniquePtr<nsTArray<sRGBColor>> mPalette;
};
class PaletteCache : public MruCache<CacheKey, CacheData, PaletteCache> {
public:
PaletteCache() = default;
void SetPaletteValueSet(const FontPaletteValueSet* aSet) {
mPaletteValueSet = aSet;
Clear();
}
nsTArray<sRGBColor>* GetPaletteFor(gfxFontEntry* aFontEntry,
nsAtom* aPaletteName);
static HashNumber Hash(const CacheKey& aKey) {
return HashGeneric(aKey.first.get(), aKey.second.get());
}
static bool Match(const CacheKey& aKey, const CacheData& aVal) {
return aVal.mKey == aKey;
}
protected:
const FontPaletteValueSet* mPaletteValueSet = nullptr;
};
static bool ValidateColorGlyphs(hb_blob_t* aCOLR, hb_blob_t* aCPAL);
// COLRv0: color glyph is represented as a simple list of colored layers.

Просмотреть файл

@ -1715,7 +1715,8 @@ bool gfxFont::HasFeatureSet(uint32_t aFeature, bool& aFeatureOn) {
already_AddRefed<mozilla::gfx::ScaledFont> gfxFont::GetScaledFont(
mozilla::gfx::DrawTarget* aDrawTarget) {
TextRunDrawParams params;
gfx::COLRFonts::PaletteCache dummy;
TextRunDrawParams params(dummy);
return GetScaledFont(params);
}
@ -2233,7 +2234,7 @@ void gfxFont::DrawEmphasisMarks(const gfxTextRun* aShapedText, gfx::Point* aPt,
const EmphasisMarkDrawParams& aParams) {
float& inlineCoord = aParams.isVertical ? aPt->y.value : aPt->x.value;
gfxTextRun::Range markRange(aParams.mark);
gfxTextRun::DrawParams params(aParams.context);
gfxTextRun::DrawParams params(aParams.context, aParams.paletteCache);
float clusterStart = -std::numeric_limits<float>::infinity();
bool shouldDrawEmphasisMark = false;
@ -2265,23 +2266,6 @@ void gfxFont::DrawEmphasisMarks(const gfxTextRun* aShapedText, gfx::Point* aPt,
}
}
nsTArray<mozilla::gfx::sRGBColor>* TextRunDrawParams::GetPaletteFor(
const gfxFont* aFont) {
auto entry = mPaletteCache.Lookup(aFont);
if (!entry) {
CacheData newData;
newData.mKey = aFont;
gfxFontEntry* fe = aFont->GetFontEntry();
gfxFontEntry::AutoHBFace face = fe->GetHBFace();
newData.mPalette = COLRFonts::SetupColorPalette(
face, paletteValueSet, fontPalette, fe->FamilyName());
entry.Set(std::move(newData));
}
return entry.Data().mPalette.get();
}
void gfxFont::Draw(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
gfx::Point* aPt, TextRunDrawParams& aRunParams,
gfx::ShapedTextFlags aOrientation) {
@ -2317,7 +2301,8 @@ void gfxFont::Draw(const gfxTextRun* aTextRun, uint32_t aStart, uint32_t aEnd,
fontParams.currentColor = aRunParams.context->GetDeviceColor(ctxColor)
? sRGBColor::FromABGR(ctxColor.ToABGR())
: sRGBColor::OpaqueBlack();
fontParams.palette = aRunParams.GetPaletteFor(this);
fontParams.palette = aRunParams.paletteCache.GetPaletteFor(
GetFontEntry(), aRunParams.fontPalette);
}
if (textDrawer) {

Просмотреть файл

@ -10,6 +10,7 @@
#include <new>
#include <utility>
#include <functional>
#include "COLRFonts.h"
#include "PLDHashTable.h"
#include "ThebesRLBoxTypes.h"
#include "gfxFontVariations.h"
@ -2299,6 +2300,11 @@ class gfxFont {
// are dependent on the specific font, so they are set per GlyphRun.
struct MOZ_STACK_CLASS TextRunDrawParams {
explicit TextRunDrawParams(
mozilla::gfx::COLRFonts::PaletteCache& aPaletteCache)
: paletteCache(aPaletteCache) {}
mozilla::gfx::COLRFonts::PaletteCache& paletteCache;
RefPtr<mozilla::gfx::DrawTarget> dt;
gfxContext* context = nullptr;
gfxFont::Spacing* spacing = nullptr;
@ -2312,7 +2318,6 @@ struct MOZ_STACK_CLASS TextRunDrawParams {
gfxPattern* textStrokePattern = nullptr;
const mozilla::gfx::StrokeOptions* strokeOpts = nullptr;
const mozilla::gfx::DrawOptions* drawOpts = nullptr;
const mozilla::gfx::FontPaletteValueSet* paletteValueSet = nullptr;
nsAtom* fontPalette = nullptr;
DrawMode drawMode = DrawMode::GLYPH_FILL;
bool isVerticalRun = false;
@ -2320,34 +2325,6 @@ struct MOZ_STACK_CLASS TextRunDrawParams {
bool paintSVGGlyphs = true;
bool allowGDI = true;
bool hasTextShadow = false;
// MRU cache of color-font palettes being used by fonts in the run. We cache
// these in the TextRunDrawParams so that we can avoid re-creating a new
// palette (which can be quite expensive) for each individual glyph run.
using CacheKey = const gfxFont*;
struct CacheData {
CacheKey mKey;
mozilla::UniquePtr<nsTArray<mozilla::gfx::sRGBColor>> mPalette;
};
class PaletteCache
: public mozilla::MruCache<CacheKey, CacheData, PaletteCache> {
public:
static mozilla::HashNumber Hash(const CacheKey& aKey) {
return mozilla::HashGeneric(aKey);
}
static bool Match(const CacheKey& aKey, const CacheData& aVal) {
return aVal.mKey == aKey;
}
};
PaletteCache mPaletteCache;
// Returns a pointer to a palette owned by the PaletteCache. This is only
// valid until the next call to GetPaletteFor (which might evict it) or
// until the TextRunDrawParams goes out of scope.
nsTArray<mozilla::gfx::sRGBColor>* GetPaletteFor(const gfxFont* aFont);
};
struct MOZ_STACK_CLASS FontDrawParams {
@ -2368,7 +2345,11 @@ struct MOZ_STACK_CLASS FontDrawParams {
};
struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
EmphasisMarkDrawParams(gfxContext* aContext,
mozilla::gfx::COLRFonts::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
gfxContext* context;
mozilla::gfx::COLRFonts::PaletteCache& paletteCache;
gfxFont::Spacing* spacing;
gfxTextRun* mark;
gfxFloat advance;

Просмотреть файл

@ -10,7 +10,6 @@
#include <math.h>
#include <new>
#include <utility>
#include "COLRFonts.h"
#include "ThebesRLBoxTypes.h"
#include "gfxFontUtils.h"
#include "gfxFontVariations.h"

Просмотреть файл

@ -611,7 +611,7 @@ void gfxTextRun::Draw(const Range aRange, const gfx::Point aPt,
// Set up parameters that will be constant across all glyph runs we need
// to draw, regardless of the font used.
TextRunDrawParams params;
TextRunDrawParams params(aParams.paletteCache);
params.context = aParams.context;
params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit());
params.isVerticalRun = IsVertical();
@ -620,7 +620,6 @@ void gfxTextRun::Draw(const Range aRange, const gfx::Point aPt,
params.strokeOpts = aParams.strokeOpts;
params.textStrokeColor = aParams.textStrokeColor;
params.fontPalette = aParams.fontPalette;
params.paletteValueSet = aParams.paletteValueSet;
params.textStrokePattern = aParams.textStrokePattern;
params.drawOpts = aParams.drawOpts;
params.drawMode = aParams.drawMode;
@ -710,14 +709,13 @@ void gfxTextRun::Draw(const Range aRange, const gfx::Point aPt,
}
// This method is mostly parallel to Draw().
void gfxTextRun::DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, gfx::Point aPt,
Range aRange,
const PropertyProvider* aProvider) const {
void gfxTextRun::DrawEmphasisMarks(
gfxContext* aContext, gfxTextRun* aMark, gfxFloat aMarkAdvance,
gfx::Point aPt, Range aRange, const PropertyProvider* aProvider,
gfx::COLRFonts::PaletteCache& aPaletteCache) const {
MOZ_ASSERT(aRange.end <= GetLength());
EmphasisMarkDrawParams params;
params.context = aContext;
EmphasisMarkDrawParams params(aContext, aPaletteCache);
params.mark = aMark;
params.advance = aMarkAdvance;
params.direction = GetDirection();

Просмотреть файл

@ -251,10 +251,10 @@ class gfxTextRun : public gfxShapedText {
struct MOZ_STACK_CLASS DrawParams {
gfxContext* context;
mozilla::gfx::COLRFonts::PaletteCache& paletteCache;
DrawMode drawMode = DrawMode::GLYPH_FILL;
nscolor textStrokeColor = 0;
nsAtom* fontPalette = nullptr;
mozilla::gfx::FontPaletteValueSet* paletteValueSet = nullptr;
gfxPattern* textStrokePattern = nullptr;
const mozilla::gfx::StrokeOptions* strokeOpts = nullptr;
const mozilla::gfx::DrawOptions* drawOpts = nullptr;
@ -265,7 +265,9 @@ class gfxTextRun : public gfxShapedText {
gfxTextRunDrawCallbacks* callbacks = nullptr;
bool allowGDI = true;
bool hasTextShadow = false;
explicit DrawParams(gfxContext* aContext) : context(aContext) {}
DrawParams(gfxContext* aContext,
mozilla::gfx::COLRFonts::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
};
/**
@ -296,9 +298,10 @@ class gfxTextRun : public gfxShapedText {
* from aProvider. The provided point is the baseline origin of the
* line of emphasis marks.
*/
void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, mozilla::gfx::Point aPt,
Range aRange, const PropertyProvider* aProvider) const;
void DrawEmphasisMarks(
gfxContext* aContext, gfxTextRun* aMark, gfxFloat aMarkAdvance,
mozilla::gfx::Point aPt, Range aRange, const PropertyProvider* aProvider,
mozilla::gfx::COLRFonts::PaletteCache& aPaletteCache) const;
/**
* Computes the ReflowMetrics for a substring.

Просмотреть файл

@ -2948,6 +2948,8 @@ void nsPresContext::FlushFontPaletteValues() {
mFontPaletteValueSet = styleSet->BuildFontPaletteValueSet();
mFontPaletteValuesDirty = false;
mFontPaletteCache.SetPaletteValueSet(mFontPaletteValueSet);
// Even if we're not reflowing anything, a change to the palette means we
// need to repaint in order to show the new colors.
InvalidatePaintedLayers();

Просмотреть файл

@ -39,7 +39,7 @@
#include "nsGkAtoms.h"
#include "nsCycleCollectionParticipant.h"
#include "nsChangeHint.h"
#include "gfxTypes.h"
#include "gfxFont.h"
#include "gfxRect.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
@ -932,6 +932,10 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
void FlushFontPaletteValues();
void MarkFontPaletteValuesDirty() { mFontPaletteValuesDirty = true; }
mozilla::gfx::COLRFonts::PaletteCache& FontPaletteCache() {
return mFontPaletteCache;
}
// Ensure that it is safe to hand out CSS rules outside the layout
// engine by ensuring that all CSS style sheets have unique inners
// and, if necessary, synchronously rebuilding all style data.
@ -1200,6 +1204,8 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
RefPtr<gfxFontFeatureValueSet> mFontFeatureValuesLookup;
RefPtr<mozilla::gfx::FontPaletteValueSet> mFontPaletteValueSet;
mozilla::gfx::COLRFonts::PaletteCache mFontPaletteCache;
// TODO(emilio): Maybe lazily create and put under a UniquePtr if this grows a
// lot?
MediaEmulationData mMediaEmulationData;

Просмотреть файл

@ -244,8 +244,9 @@ void nsDisplayTextOverflowMarker::PaintTextToContext(gfxContext* aCtx,
NS_ASSERTION(!textRun->IsRightToLeft(),
"Ellipsis textruns should always be LTR!");
gfx::Point gfxPt(pt.x, pt.y);
auto& paletteCache = mFrame->PresContext()->FontPaletteCache();
textRun->Draw(gfxTextRun::Range(textRun), gfxPt,
gfxTextRun::DrawParams(aCtx));
gfxTextRun::DrawParams(aCtx, paletteCache));
}
} else {
RefPtr<nsFontMetrics> fm =

Просмотреть файл

@ -215,6 +215,7 @@ struct nsTextFrame::PaintTextSelectionParams : nsTextFrame::PaintTextParams {
struct nsTextFrame::DrawTextRunParams {
gfxContext* context;
gfx::COLRFonts::PaletteCache& paletteCache;
PropertyProvider* provider = nullptr;
gfxFloat* advanceWidth = nullptr;
mozilla::SVGContextPaint* contextPaint = nullptr;
@ -222,11 +223,12 @@ struct nsTextFrame::DrawTextRunParams {
nscolor textColor = NS_RGBA(0, 0, 0, 0);
nscolor textStrokeColor = NS_RGBA(0, 0, 0, 0);
nsAtom* fontPalette = nullptr;
gfx::FontPaletteValueSet* paletteValueSet = nullptr;
float textStrokeWidth = 0.0f;
bool drawSoftHyphen = false;
bool hasTextShadow = false;
explicit DrawTextRunParams(gfxContext* aContext) : context(aContext) {}
DrawTextRunParams(gfxContext* aContext,
gfx::COLRFonts::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
};
struct nsTextFrame::ClipEdges {
@ -263,7 +265,9 @@ struct nsTextFrame::DrawTextParams : nsTextFrame::DrawTextRunParams {
const ClipEdges* clipEdges = nullptr;
const nscolor* decorationOverrideColor = nullptr;
Range glyphRange;
explicit DrawTextParams(gfxContext* aContext) : DrawTextRunParams(aContext) {}
DrawTextParams(gfxContext* aContext,
gfx::COLRFonts::PaletteCache& aPaletteCache)
: DrawTextRunParams(aContext, aPaletteCache) {}
};
struct nsTextFrame::PaintShadowParams {
@ -5949,7 +5953,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
// need to translate any coordinates to fit on the surface.
gfxFloat advanceWidth;
nsTextPaintStyle textPaintStyle(this);
DrawTextParams params(shadowContext);
DrawTextParams params(shadowContext, PresContext()->FontPaletteCache());
params.advanceWidth = &advanceWidth;
params.dirtyRect = aParams.dirtyRect;
params.framePt = aParams.framePt + shadowGfxOffset;
@ -5963,7 +5967,6 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
// color.
params.decorationOverrideColor = &params.textColor;
params.fontPalette = StyleFont()->GetFontPaletteAtom();
params.paletteValueSet = PresContext()->GetFontPaletteValueSet();
DrawText(aParams.range, aParams.textBaselinePt + shadowGfxOffset, params);
@ -6252,7 +6255,7 @@ bool nsTextFrame::PaintTextWithSelectionColors(
}
gfxFloat advance;
DrawTextParams params(aParams.context);
DrawTextParams params(aParams.context, PresContext()->FontPaletteCache());
params.dirtyRect = aParams.dirtyRect;
params.framePt = aParams.framePt;
params.provider = aParams.provider;
@ -6262,7 +6265,6 @@ bool nsTextFrame::PaintTextWithSelectionColors(
params.callbacks = aParams.callbacks;
params.glyphRange = aParams.glyphRange;
params.fontPalette = StyleFont()->GetFontPaletteAtom();
params.paletteValueSet = PresContext()->GetFontPaletteValueSet();
params.hasTextShadow = !StyleText()->mTextShadow.IsEmpty();
PaintShadowParams shadowParams(aParams);
@ -6498,10 +6500,11 @@ void nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
}
if (!isTextCombined) {
mTextRun->DrawEmphasisMarks(aContext, info->textRun.get(), info->advance,
pt, aRange, aProvider);
pt, aRange, aProvider,
PresContext()->FontPaletteCache());
} else {
pt.y += (GetSize().height - info->advance) / 2;
gfxTextRun::DrawParams params(aContext);
gfxTextRun::DrawParams params(aContext, PresContext()->FontPaletteCache());
info->textRun->Draw(Range(info->textRun.get()), pt, params);
}
}
@ -6834,7 +6837,7 @@ void nsTextFrame::PaintText(const PaintTextParams& aParams,
}
gfxFloat advanceWidth;
DrawTextParams params(aParams.context);
DrawTextParams params(aParams.context, PresContext()->FontPaletteCache());
params.dirtyRect = aParams.dirtyRect;
params.framePt = aParams.framePt;
params.provider = &provider;
@ -6849,7 +6852,6 @@ void nsTextFrame::PaintText(const PaintTextParams& aParams,
params.callbacks = aParams.callbacks;
params.glyphRange = range;
params.fontPalette = StyleFont()->GetFontPaletteAtom();
params.paletteValueSet = PresContext()->GetFontPaletteValueSet();
params.hasTextShadow = !StyleText()->mTextShadow.IsEmpty();
DrawText(range, textBaselinePt, params);
@ -6860,12 +6862,11 @@ static void DrawTextRun(const gfxTextRun* aTextRun,
gfxTextRun::Range aRange,
const nsTextFrame::DrawTextRunParams& aParams,
nsTextFrame* aFrame) {
gfxTextRun::DrawParams params(aParams.context);
gfxTextRun::DrawParams params(aParams.context, aParams.paletteCache);
params.provider = aParams.provider;
params.advanceWidth = aParams.advanceWidth;
params.contextPaint = aParams.contextPaint;
params.fontPalette = aParams.fontPalette;
params.paletteValueSet = aParams.paletteValueSet;
params.callbacks = aParams.callbacks;
params.hasTextShadow = aParams.hasTextShadow;
if (aParams.callbacks) {

Просмотреть файл

@ -1881,7 +1881,9 @@ void nsMathMLChar::PaintForeground(nsIFrame* aForFrame,
if (mGlyphs[0]) {
mGlyphs[0]->Draw(Range(mGlyphs[0].get()),
gfx::Point(0.0, mUnscaledAscent),
gfxTextRun::DrawParams(&aRenderingContext));
gfxTextRun::DrawParams(
&aRenderingContext,
aForFrame->PresContext()->FontPaletteCache()));
}
break;
case DRAW_PARTS: {
@ -1995,7 +1997,8 @@ nsresult nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
unionRect.Inflate(oneDevPixel);
gfxTextRun::DrawParams params(aThebesContext);
gfxTextRun::DrawParams params(aThebesContext,
aPresContext->FontPaletteCache());
/////////////////////////////////////
// draw top, middle, bottom
@ -2157,7 +2160,8 @@ nsresult nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
nsRect unionRect = aRect;
unionRect.Inflate(oneDevPixel);
gfxTextRun::DrawParams params(aThebesContext);
gfxTextRun::DrawParams params(aThebesContext,
aPresContext->FontPaletteCache());
///////////////////////////
// draw left, middle, right