Skip to content

Commit

Permalink
Bug 1872545 - Hoist color-font palette cache out of TextRunDrawParams…
Browse files Browse the repository at this point in the history
… to the nsPresContext or CanvasRenderingContext2D, for greater effectiveness. r=gfx-reviewers,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D197463
  • Loading branch information
jfkthame committed Jan 4, 2024
1 parent c1aac4f commit 7d379bc
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 82 deletions.
10 changes: 7 additions & 3 deletions dom/canvas/CanvasRenderingContext2D.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4251,7 +4251,8 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
: public nsBidiPresUtils::BidiProcessor {
using Style = CanvasRenderingContext2D::Style;

CanvasBidiProcessor() : nsBidiPresUtils::BidiProcessor() {
explicit CanvasBidiProcessor(mozilla::gfx::PaletteCache& aPaletteCache)
: mPaletteCache(aPaletteCache) {
if (StaticPrefs::gfx_missing_fonts_notify()) {
mMissingFonts = MakeUnique<gfxMissingFontRecorder>();
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -4566,6 +4567,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor final
// current font
gfxFontGroup* mFontgrp = nullptr;

// palette cache for COLR font rendering
mozilla::gfx::PaletteCache& mPaletteCache;

// spacing adjustments to be applied
gfx::Float mLetterSpacing = 0.0f;
gfx::Float mWordSpacing = 0.0f;
Expand Down Expand Up @@ -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).
Expand Down
2 changes: 2 additions & 0 deletions dom/canvas/CanvasRenderingContext2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,8 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,

ColorStyleCacheEntry ParseColorSlow(const nsACString&);

mozilla::gfx::PaletteCache mPaletteCache;

friend class CanvasGeneralPattern;
friend class AdjustedTarget;
friend class AdjustedTargetForShadow;
Expand Down
6 changes: 4 additions & 2 deletions gfx/src/nsFontMetrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ void nsFontMetrics::DrawString(const char* aString, uint32_t aLength,
pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
gfxTextRun::DrawParams params(aContext);
mozilla::gfx::PaletteCache paletteCache;
gfxTextRun::DrawParams params(aContext, paletteCache);
params.provider = &provider;
textRun->Draw(range, pt, params);
}
Expand All @@ -359,7 +360,8 @@ void nsFontMetrics::DrawString(
pt.x += textRun->GetAdvanceWidth(range, &provider);
}
}
gfxTextRun::DrawParams params(aContext);
mozilla::gfx::PaletteCache paletteCache;
gfxTextRun::DrawParams params(aContext, paletteCache);
params.provider = &provider;
textRun->Draw(range, pt, params);
}
Expand Down
31 changes: 31 additions & 0 deletions gfx/thebes/FontPaletteCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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 "FontPaletteCache.h"
#include "COLRFonts.h"

using namespace mozilla;

void gfx::PaletteCache::SetPaletteValueSet(
const gfx::FontPaletteValueSet* aSet) {
mPaletteValueSet = aSet;
Clear();
}

nsTArray<gfx::sRGBColor>* gfx::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 = gfx::COLRFonts::SetupColorPalette(
face, mPaletteValueSet, aPaletteName, aFontEntry->FamilyName());

entry.Set(std::move(newData));
}
return entry.Data().mPalette.get();
}
52 changes: 52 additions & 0 deletions gfx/thebes/FontPaletteCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */

#ifndef FONT_PALETTE_CACHE_H
#define FONT_PALETTE_CACHE_H

#include "gfxFontEntry.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/MruCache.h"
#include "mozilla/HashFunctions.h"
#include "nsAtom.h"
#include <utility>

namespace mozilla::gfx {

class FontPaletteValueSet;

// 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<mozilla::gfx::sRGBColor>> mPalette;
};

class PaletteCache
: public mozilla::MruCache<CacheKey, CacheData, PaletteCache> {
public:
explicit PaletteCache(const FontPaletteValueSet* aPaletteValueSet = nullptr)
: mPaletteValueSet(aPaletteValueSet) {}

void SetPaletteValueSet(const FontPaletteValueSet* aSet);

nsTArray<mozilla::gfx::sRGBColor>* GetPaletteFor(gfxFontEntry* aFontEntry,
nsAtom* aPaletteName);

static mozilla::HashNumber Hash(const CacheKey& aKey) {
return mozilla::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;
};

} // namespace mozilla::gfx

#endif
25 changes: 5 additions & 20 deletions gfx/thebes/gfxFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
mozilla::gfx::PaletteCache dummy;
TextRunDrawParams params(dummy);
return GetScaledFont(params);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
38 changes: 9 additions & 29 deletions gfx/thebes/gfxFont.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <new>
#include <utility>
#include <functional>
#include "FontPaletteCache.h"
#include "PLDHashTable.h"
#include "ThebesRLBoxTypes.h"
#include "gfxFontVariations.h"
Expand Down Expand Up @@ -2299,6 +2300,10 @@ class gfxFont {
// are dependent on the specific font, so they are set per GlyphRun.
struct MOZ_STACK_CLASS TextRunDrawParams {
explicit TextRunDrawParams(mozilla::gfx::PaletteCache& aPaletteCache)
: paletteCache(aPaletteCache) {}
mozilla::gfx::PaletteCache& paletteCache;
RefPtr<mozilla::gfx::DrawTarget> dt;
gfxContext* context = nullptr;
gfxFont::Spacing* spacing = nullptr;
Expand All @@ -2312,42 +2317,13 @@ 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;
bool isRTL = false;
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 {
Expand All @@ -2368,7 +2344,11 @@ struct MOZ_STACK_CLASS FontDrawParams {
};
struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
EmphasisMarkDrawParams(gfxContext* aContext,
mozilla::gfx::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
gfxContext* context;
mozilla::gfx::PaletteCache& paletteCache;
gfxFont::Spacing* spacing;
gfxTextRun* mark;
gfxFloat advance;
Expand Down
14 changes: 6 additions & 8 deletions gfx/thebes/gfxTextRun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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,
mozilla::gfx::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();
Expand Down
8 changes: 5 additions & 3 deletions gfx/thebes/gfxTextRun.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,10 @@ class gfxTextRun : public gfxShapedText {

struct MOZ_STACK_CLASS DrawParams {
gfxContext* context;
mozilla::gfx::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;
Expand All @@ -265,7 +265,8 @@ class gfxTextRun : public gfxShapedText {
gfxTextRunDrawCallbacks* callbacks = nullptr;
bool allowGDI = true;
bool hasTextShadow = false;
explicit DrawParams(gfxContext* aContext) : context(aContext) {}
DrawParams(gfxContext* aContext, mozilla::gfx::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
};

/**
Expand Down Expand Up @@ -298,7 +299,8 @@ class gfxTextRun : public gfxShapedText {
*/
void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark,
gfxFloat aMarkAdvance, mozilla::gfx::Point aPt,
Range aRange, const PropertyProvider* aProvider) const;
Range aRange, const PropertyProvider* aProvider,
mozilla::gfx::PaletteCache& aPaletteCache) const;

/**
* Computes the ReflowMetrics for a substring.
Expand Down
2 changes: 2 additions & 0 deletions gfx/thebes/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ XPIDL_MODULE = "gfx"
EXPORTS += [
"COLRFonts.h",
"DrawMode.h",
"FontPaletteCache.h",
"gfx2DGlue.h",
"gfxAlphaRecovery.h",
"gfxASurface.h",
Expand Down Expand Up @@ -198,6 +199,7 @@ SOURCES += [
UNIFIED_SOURCES += [
"CJKCompatSVS.cpp",
"COLRFonts.cpp",
"FontPaletteCache.cpp",
"gfxAlphaRecovery.cpp",
"gfxBaseSharedMemorySurface.cpp",
"gfxBlur.cpp",
Expand Down
12 changes: 12 additions & 0 deletions layout/base/nsPresContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "mozilla/Preferences.h"
#include "gfxTextRun.h"
#include "nsFontFaceUtils.h"
#include "COLRFonts.h"
#include "mozilla/ContentBlockingAllowList.h"
#include "mozilla/GlobalStyleSheetCache.h"
#include "mozilla/ServoBindings.h"
Expand Down Expand Up @@ -2948,11 +2949,22 @@ void nsPresContext::FlushFontPaletteValues() {
mFontPaletteValueSet = styleSet->BuildFontPaletteValueSet();
mFontPaletteValuesDirty = false;

if (mFontPaletteCache) {
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();
}

gfx::PaletteCache& nsPresContext::FontPaletteCache() {
if (!mFontPaletteCache) {
mFontPaletteCache = MakeUnique<gfx::PaletteCache>(mFontPaletteValueSet);
}
return *mFontPaletteCache.get();
}

void nsPresContext::SetVisibleArea(const nsRect& r) {
if (!r.IsEqualEdges(mVisibleArea)) {
mVisibleArea = r;
Expand Down
Loading

0 comments on commit 7d379bc

Please sign in to comment.