Bug 1815396 - Add an MruCache for ParseColor, just like we have for fonts. r=gfx-reviewers,lsalzman

Since currentColor usage is expected to be ~0, don't make the restyle
generation etc part of the cache.

Differential Revision: https://phabricator.services.mozilla.com/D171654
This commit is contained in:
Emilio Cobos Álvarez 2023-03-06 10:43:28 +00:00
parent 58dfff38db
commit 588855a7db
2 changed files with 73 additions and 41 deletions

View File

@ -839,20 +839,20 @@ void CanvasGradient::AddColorStop(float aOffset, const nsACString& aColorstr,
return aRv.ThrowIndexSizeError("Offset out of 0-1.0 range");
}
PresShell* presShell = mContext ? mContext->GetPresShell() : nullptr;
ServoStyleSet* styleSet = presShell ? presShell->StyleSet() : nullptr;
if (!mContext) {
return aRv.ThrowSyntaxError("No canvas context");
}
nscolor color;
bool ok = ServoCSSParser::ComputeColor(styleSet, NS_RGB(0, 0, 0), aColorstr,
&color);
if (!ok) {
auto color = mContext->ParseColor(
aColorstr, CanvasRenderingContext2D::ResolveCurrentColor::No);
if (!color) {
return aRv.ThrowSyntaxError("Invalid color");
}
GradientStop newStop;
newStop.offset = aOffset;
newStop.color = ToDeviceColor(color);
newStop.color = ToDeviceColor(*color);
mRawStops.AppendElement(newStop);
}
@ -1083,32 +1083,44 @@ JSObject* CanvasRenderingContext2D::WrapObject(
return CanvasRenderingContext2D_Binding::Wrap(aCx, this, aGivenProto);
}
bool CanvasRenderingContext2D::ParseColor(const nsACString& aString,
nscolor* aColor) {
CanvasRenderingContext2D::ColorStyleCacheEntry
CanvasRenderingContext2D::ParseColorSlow(const nsACString& aString) {
ColorStyleCacheEntry result{nsCString(aString)};
Document* document = mCanvasElement ? mCanvasElement->OwnerDoc() : nullptr;
css::Loader* loader = document ? document->CSSLoader() : nullptr;
PresShell* presShell = GetPresShell();
ServoStyleSet* set = presShell ? presShell->StyleSet() : nullptr;
// First, try computing the color without handling currentcolor.
bool wasCurrentColor = false;
if (!ServoCSSParser::ComputeColor(set, NS_RGB(0, 0, 0), aString, aColor,
&wasCurrentColor, loader)) {
return false;
nscolor color;
if (ServoCSSParser::ComputeColor(set, NS_RGB(0, 0, 0), aString, &color,
&wasCurrentColor, loader)) {
result.mWasCurrentColor = wasCurrentColor;
result.mColor.emplace(color);
}
if (wasCurrentColor && mCanvasElement) {
// Otherwise, get the value of the color property, flushing style
// if necessary.
return result;
}
Maybe<nscolor> CanvasRenderingContext2D::ParseColor(
const nsACString& aString, ResolveCurrentColor aResolveCurrentColor) {
auto entry = mColorStyleCache.Lookup(aString);
if (!entry) {
entry.Set(ParseColorSlow(aString));
}
const auto& data = entry.Data();
if (data.mWasCurrentColor && mCanvasElement &&
aResolveCurrentColor == ResolveCurrentColor::Yes) {
// If it was currentColor, get the value of the color property, flushing
// style if necessary.
RefPtr<const ComputedStyle> canvasStyle =
nsComputedDOMStyle::GetComputedStyle(mCanvasElement);
if (canvasStyle) {
*aColor = canvasStyle->StyleText()->mColor.ToColor();
return Some(canvasStyle->StyleText()->mColor.ToColor());
}
// Beware that the presShell could be gone here.
}
return true;
return data.mColor;
}
void CanvasRenderingContext2D::ResetBitmap(bool aFreeBuffer) {
@ -1171,12 +1183,12 @@ void CanvasRenderingContext2D::SetStyleFromString(const nsACString& aStr,
Style aWhichStyle) {
MOZ_ASSERT(!aStr.IsVoid());
nscolor color;
if (!ParseColor(aStr, &color)) {
Maybe<nscolor> color = ParseColor(aStr);
if (!color) {
return;
}
CurrentState().SetColorStyle(aWhichStyle, color);
CurrentState().SetColorStyle(aWhichStyle, *color);
}
void CanvasRenderingContext2D::GetStyleAsUnion(
@ -2325,12 +2337,12 @@ already_AddRefed<CanvasPattern> CanvasRenderingContext2D::CreatePattern(
// shadows
//
void CanvasRenderingContext2D::SetShadowColor(const nsACString& aShadowColor) {
nscolor color;
if (!ParseColor(aShadowColor, &color)) {
Maybe<nscolor> color = ParseColor(aShadowColor);
if (!color) {
return;
}
CurrentState().shadowColor = color;
CurrentState().shadowColor = *color;
}
//
@ -3514,7 +3526,7 @@ bool CanvasRenderingContext2D::SetFontInternal(const nsACString& aFont,
}
nsPresContext* c = presShell->GetPresContext();
CacheKey key{aFont, c->RestyleManager()->GetRestyleGeneration()};
FontStyleCacheKey key{aFont, c->RestyleManager()->GetRestyleGeneration()};
auto entry = mFontStyleCache.Lookup(key);
if (!entry) {
FontStyleData newData;
@ -5372,8 +5384,8 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
return;
}
nscolor backgroundColor;
if (!ParseColor(aBgColor, &backgroundColor)) {
Maybe<nscolor> backgroundColor = ParseColor(aBgColor);
if (!backgroundColor) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
@ -5459,7 +5471,7 @@ void CanvasRenderingContext2D::DrawWindow(nsGlobalWindowInner& aWindow,
RefPtr<PresShell> presShell = presContext->PresShell();
Unused << presShell->RenderDocument(r, renderDocFlags, backgroundColor,
Unused << presShell->RenderDocument(r, renderDocFlags, *backgroundColor,
&thebes.ref());
// If this canvas was contained in the drawn window, the pre-transaction
// callback may have returned its DT. If so, we must reacquire it here.

View File

@ -133,6 +133,10 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
}
}
enum class ResolveCurrentColor : bool { No, Yes };
Maybe<nscolor> ParseColor(const nsACString&,
ResolveCurrentColor = ResolveCurrentColor::Yes);
void GetGlobalCompositeOperation(nsAString& aOp,
mozilla::ErrorResult& aError) override;
void SetGlobalCompositeOperation(const nsAString& aOp,
@ -572,9 +576,6 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
void GetStyleAsUnion(OwningUTF8StringOrCanvasGradientOrCanvasPattern& aValue,
Style aWhichStyle);
// Returns whether a color was successfully parsed.
bool ParseColor(const nsACString& aString, nscolor* aColor);
static void StyleColorToString(const nscolor& aColor, nsACString& aStr);
// Returns whether a filter was successfully parsed.
@ -1010,28 +1011,29 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
return mStyleStack[mStyleStack.Length() - 1];
}
struct CacheKey {
CacheKey() : mFont(), mGeneration(0) {}
CacheKey(const nsACString& aFont, uint64_t aGeneration)
struct FontStyleCacheKey {
FontStyleCacheKey() = default;
FontStyleCacheKey(const nsACString& aFont, uint64_t aGeneration)
: mFont(aFont), mGeneration(aGeneration) {}
nsCString mFont;
uint64_t mGeneration;
uint64_t mGeneration = 0;
};
struct FontStyleData {
CacheKey mKey;
FontStyleCacheKey mKey;
nsCString mUsedFont;
RefPtr<const ComputedStyle> mStyle;
};
class FontStyleCache
: public MruCache<CacheKey, FontStyleData, FontStyleCache> {
: public MruCache<FontStyleCacheKey, FontStyleData, FontStyleCache> {
public:
static HashNumber Hash(const CacheKey& aKey) {
static HashNumber Hash(const FontStyleCacheKey& aKey) {
HashNumber hash = HashString(aKey.mFont);
return AddToHash(hash, aKey.mGeneration);
}
static bool Match(const CacheKey& aKey, const FontStyleData& aVal) {
static bool Match(const FontStyleCacheKey& aKey,
const FontStyleData& aVal) {
return aVal.mKey.mGeneration == aKey.mGeneration &&
aVal.mKey.mFont == aKey.mFont;
}
@ -1039,6 +1041,24 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
FontStyleCache mFontStyleCache;
struct ColorStyleCacheEntry {
nsCString mKey;
Maybe<nscolor> mColor;
bool mWasCurrentColor = false;
};
class ColorStyleCache
: public MruCache<nsACString, ColorStyleCacheEntry, ColorStyleCache> {
public:
static HashNumber Hash(const nsACString& aKey) { return HashString(aKey); }
static bool Match(const nsACString& aKey,
const ColorStyleCacheEntry& aVal) {
return aVal.mKey == aKey;
}
};
ColorStyleCache mColorStyleCache;
ColorStyleCacheEntry ParseColorSlow(const nsACString&);
friend class CanvasGeneralPattern;
friend class AdjustedTarget;
friend class AdjustedTargetForShadow;