Backed out changeset 1cb2802bb09b (bug 298281) for causing build bustage at nsCSSRenderingGradients.h CLOSED TREE

This commit is contained in:
Cristina Horotan 2023-12-18 19:38:05 +02:00
parent 78b9b11c37
commit a249c3e2e4
6 changed files with 86 additions and 196 deletions

View File

@ -1189,45 +1189,6 @@ bool nsCSSGradientRenderer::TryPaintTilesWithExtendMode(
return true;
}
class MOZ_STACK_CLASS WrColorStopInterpolator
: public ColorStopInterpolator<WrColorStopInterpolator> {
public:
WrColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
float aOpacity, nsTArray<wr::GradientStop>& aResult)
: ColorStopInterpolator(aStops, aStyleColorInterpolationMethod),
mResult(aResult),
mOpacity(aOpacity),
mOutputStop(0) {}
void CreateStops() {
mResult.SetLengthAndRetainStorage(0);
// we always emit at least two stops (start and end) for each input stop,
// which avoids ambiguity with incomplete oklch/lch/hsv/hsb color stops for
// the last stop pair, where the last color stop can't be interpreted on its
// own because it actually depends on the previous stop.
mResult.SetLength(mStops.Length() * 2 + kFullRangeExtraStops);
mOutputStop = 0;
ColorStopInterpolator::CreateStops();
mResult.SetLength(mOutputStop);
}
void CreateStop(float aPosition, DeviceColor aColor) {
if (mOutputStop < mResult.Capacity()) {
mResult[mOutputStop].color = wr::ToColorF(aColor);
mResult[mOutputStop].color.a *= mOpacity;
mResult[mOutputStop].offset = aPosition;
mOutputStop++;
}
}
private:
nsTArray<wr::GradientStop>& mResult;
float mOpacity;
uint32_t mOutputStop;
};
void nsCSSGradientRenderer::BuildWebRenderParameters(
float aOpacity, wr::ExtendMode& aMode, nsTArray<wr::GradientStop>& aStops,
LayoutDevicePoint& aLineStart, LayoutDevicePoint& aLineEnd,
@ -1260,9 +1221,44 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
if (mStops.Length() >= 2 &&
(styleColorInterpolationMethod.space != StyleColorSpace::Srgb ||
gfxPlatform::GetCMSMode() == CMSMode::All)) {
WrColorStopInterpolator interpolator(mStops, styleColorInterpolationMethod,
aOpacity, aStops);
interpolator.CreateStops();
aStops.SetLengthAndRetainStorage(0);
// this could be made tunable, but at 1.0/128 the error is largely
// irrelevant, as WebRender re-encodes it to 128 pairs of stops.
//
// note that we don't attempt to place the positions of these stops
// precisely at intervals, we just add this many extra stops across the
// range where it is convenient.
const int fullRangeExtraStops = 128;
// we always emit at least two stops (start and end) for each input stop,
// which avoids ambiguity with incomplete oklch/lch/hsv/hsb color stops for
// the last stop pair, where the last color stop can't be interpreted on its
// own because it actually depends on the previous stop.
aStops.SetLength(mStops.Length() * 2 + fullRangeExtraStops);
uint32_t outputStop = 0;
for (uint32_t i = 0; i < mStops.Length() - 1; i++) {
auto& start = mStops[i];
auto& end = i + 1 < mStops.Length() ? mStops[i + 1] : mStops[i];
StyleAbsoluteColor startColor = start.mColor;
StyleAbsoluteColor endColor = end.mColor;
int extraStops = (int)(floor(end.mPosition * fullRangeExtraStops) -
floor(start.mPosition * fullRangeExtraStops));
extraStops = clamped(extraStops, 1, fullRangeExtraStops);
float step = 1.0f / (float)extraStops;
for (int extraStop = 0;
extraStop <= extraStops && outputStop < aStops.Capacity();
extraStop++) {
auto lerp = (float)extraStop * step;
auto position =
start.mPosition + lerp * (end.mPosition - start.mPosition);
StyleAbsoluteColor color = Servo_InterpolateColor(
styleColorInterpolationMethod, &endColor, &startColor, lerp);
aStops[outputStop].color = wr::ToColorF(ToDeviceColor(color));
aStops[outputStop].color.a *= aOpacity;
aStops[outputStop].offset = (float)position;
outputStop++;
}
}
aStops.SetLength(outputStop);
} else {
aStops.SetLength(mStops.Length());
for (uint32_t i = 0; i < mStops.Length(); i++) {

View File

@ -38,50 +38,6 @@ struct ColorStop {
StyleAbsoluteColor mColor;
};
template <class T>
class MOZ_STACK_CLASS ColorStopInterpolator {
public:
ColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod)
: mStyleColorInterpolationMethod(aStyleColorInterpolationMethod),
mStops(aStops) {}
void CreateStops() {
for (uint32_t i = 0; i < mStops.Length() - 1; i++) {
const auto& start = mStops[i];
const auto& end = mStops[i + 1];
uint32_t extraStops =
(uint32_t)(floor(end.mPosition * kFullRangeExtraStops) -
floor(start.mPosition * kFullRangeExtraStops));
extraStops = clamped(extraStops, 1U, kFullRangeExtraStops);
float step = 1.0f / (float)extraStops;
for (uint32_t extraStop = 0; extraStop <= extraStops; extraStop++) {
auto progress = (float)extraStop * step;
auto position =
start.mPosition + progress * (end.mPosition - start.mPosition);
StyleAbsoluteColor color =
Servo_InterpolateColor(mStyleColorInterpolationMethod, &end.mColor,
&start.mColor, progress);
static_cast<T*>(this)->CreateStop(float(position),
gfx::ToDeviceColor(color));
}
}
}
protected:
StyleColorInterpolationMethod mStyleColorInterpolationMethod;
const nsTArray<ColorStop>& mStops;
// this could be made tunable, but at 1.0/128 the error is largely
// irrelevant, as WebRender re-encodes it to 128 pairs of stops.
//
// note that we don't attempt to place the positions of these stops
// precisely at intervals, we just add this many extra stops across the
// range where it is convenient.
inline static const uint32_t kFullRangeExtraStops = 128;
};
class nsCSSGradientRenderer final {
public:
/**

View File

@ -22,6 +22,8 @@
#include "nsContentUtils.h"
#include "SVGAnimatedTransformList.h"
// XXX Tight coupling with content classes ahead!
using namespace mozilla::dom;
using namespace mozilla::dom::SVGGradientElement_Binding;
using namespace mozilla::dom::SVGUnitTypes_Binding;
@ -208,53 +210,21 @@ dom::SVGRadialGradientElement* SVGGradientFrame::GetRadialGradientWithLength(
//----------------------------------------------------------------------
// SVGPaintServerFrame methods:
// helpers
static ColorStop GetStopInformation(const nsIFrame* aStopFrame,
float aGraphicOpacity,
float& aLastPosition) {
// helper
static void GetStopInformation(nsIFrame* aStopFrame, float* aOffset,
nscolor* aStopColor, float* aStopOpacity) {
nsIContent* stopContent = aStopFrame->GetContent();
MOZ_ASSERT(stopContent && stopContent->IsSVGElement(nsGkAtoms::stop));
float position;
static_cast<SVGStopElement*>(stopContent)
->GetAnimatedNumberValues(&position, nullptr);
->GetAnimatedNumberValues(aOffset, nullptr);
position = clamped(position, 0.0f, 1.0f);
if (position < aLastPosition) {
position = aLastPosition;
} else {
aLastPosition = position;
}
const auto* svgReset = aStopFrame->StyleSVGReset();
sRGBColor stopColor =
sRGBColor::FromABGR(svgReset->mStopColor.CalcColor(aStopFrame));
stopColor.a *= svgReset->mStopOpacity * aGraphicOpacity;
return ColorStop(position, false,
StyleAbsoluteColor::FromColor(stopColor.ToABGR()));
const nsStyleSVGReset* styleSVGReset = aStopFrame->StyleSVGReset();
*aOffset = mozilla::clamped(*aOffset, 0.0f, 1.0f);
*aStopColor = styleSVGReset->mStopColor.CalcColor(aStopFrame);
*aStopOpacity = styleSVGReset->mStopOpacity;
}
class MOZ_STACK_CLASS SVGColorStopInterpolator
: public ColorStopInterpolator<SVGColorStopInterpolator> {
public:
SVGColorStopInterpolator(
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod)
: ColorStopInterpolator(aStops, aStyleColorInterpolationMethod),
mGradient(aGradient) {}
void CreateStop(float aPosition, DeviceColor aColor) {
mGradient->AddColorStop(aPosition, aColor);
}
private:
gfxPattern* mGradient;
};
already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
nsIFrame* aSource, const DrawTarget* aDrawTarget,
const gfxMatrix& aContextMatrix, StyleSVGPaint nsStyleSVG::*aFillOrStroke,
@ -270,21 +240,29 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
mSource = aSource->IsTextFrame() ? aSource->GetParent() : aSource;
}
AutoTArray<ColorStop, 8> stops;
GetStops(&stops, aGraphicOpacity);
AutoTArray<nsIFrame*, 8> stopFrames;
GetStopFrames(&stopFrames);
uint32_t nStops = stops.Length();
uint32_t nStops = stopFrames.Length();
// SVG specification says that no stops should be treated like
// the corresponding fill or stroke had "none" specified.
if (nStops == 0) {
RefPtr<gfxPattern> pattern = new gfxPattern(DeviceColor());
return do_AddRef(new gfxPattern(DeviceColor()));
}
if (nStops == 1 || GradientVectorLengthIsZero()) {
auto* lastStopFrame = stopFrames[nStops - 1];
const auto* svgReset = lastStopFrame->StyleSVGReset();
// The gradient paints a single colour, using the stop-color of the last
// gradient step if there are more than one.
return do_AddRef(new gfxPattern(ToDeviceColor(stops.LastElement().mColor)));
float stopOpacity = svgReset->mStopOpacity;
nscolor stopColor = svgReset->mStopColor.CalcColor(lastStopFrame);
sRGBColor stopColor2 = sRGBColor::FromABGR(stopColor);
stopColor2.a *= stopOpacity * aGraphicOpacity;
return do_AddRef(new gfxPattern(ToDeviceColor(stopColor2)));
}
// Get the transform list (if there is one). We do this after the returns
@ -323,16 +301,23 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
gradient->SetMatrix(patternMatrix);
if (StyleSVG()->mColorInterpolation == StyleColorInterpolation::Linearrgb) {
static constexpr auto interpolationMethod = StyleColorInterpolationMethod{
StyleColorSpace::SrgbLinear, StyleHueInterpolationMethod::Shorter};
SVGColorStopInterpolator interpolator(gradient, stops, interpolationMethod);
interpolator.CreateStops();
} else {
// setup standard sRGB stops
for (const auto& stop : stops) {
gradient->AddColorStop(stop.mPosition, ToDeviceColor(stop.mColor));
}
// setup stops
float lastOffset = 0.0f;
for (uint32_t i = 0; i < nStops; i++) {
float offset, stopOpacity;
nscolor stopColor;
GetStopInformation(stopFrames[i], &offset, &stopColor, &stopOpacity);
if (offset < lastOffset)
offset = lastOffset;
else
lastOffset = offset;
sRGBColor stopColor2 = sRGBColor::FromABGR(stopColor);
stopColor2.a *= stopOpacity * aGraphicOpacity;
gradient->AddColorStop(offset, ToDeviceColor(stopColor2));
}
return gradient.forget();
@ -366,16 +351,15 @@ SVGGradientFrame* SVGGradientFrame::GetReferencedGradient() {
return do_QueryFrame(SVGObserverUtils::GetAndObserveTemplate(this, GetHref));
}
void SVGGradientFrame::GetStops(nsTArray<ColorStop>* aStops,
float aGraphicOpacity) {
float lastPosition = 0.0f;
for (const auto* stopFrame : mFrames) {
void SVGGradientFrame::GetStopFrames(nsTArray<nsIFrame*>* aStopFrames) {
nsIFrame* stopFrame = nullptr;
for (stopFrame = mFrames.FirstChild(); stopFrame;
stopFrame = stopFrame->GetNextSibling()) {
if (stopFrame->IsSVGStopFrame()) {
aStops->AppendElement(
GetStopInformation(stopFrame, aGraphicOpacity, lastPosition));
aStopFrames->AppendElement(stopFrame);
}
}
if (aStops->Length() > 0) {
if (aStopFrames->Length() > 0) {
return;
}
@ -393,7 +377,7 @@ void SVGGradientFrame::GetStops(nsTArray<ColorStop>* aStops,
SVGGradientFrame* next = GetReferencedGradient();
if (next) {
next->GetStops(aStops, aGraphicOpacity);
next->GetStopFrames(aStopFrames);
}
}

View File

@ -12,7 +12,6 @@
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "nsCOMPtr.h"
#include "nsCSSRenderingGradients.h"
#include "nsIFrame.h"
#include "nsLiteralString.h"
@ -73,7 +72,8 @@ class SVGGradientFrame : public SVGPaintServerFrame {
*/
SVGGradientFrame* GetReferencedGradient();
void GetStops(nsTArray<ColorStop>* aStops, float aGraphicOpacity);
// Optionally get a stop frame (returns stop index/count)
void GetStopFrames(nsTArray<nsIFrame*>* aStopFrames);
const SVGAnimatedTransformList* GetGradientTransformList(
nsIContent* aDefault);

View File

@ -1,22 +0,0 @@
<svg width="100%" height="100%"
xmlns="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml">
<g id="testmeta">
<title>Gradient with color-interpolation: linearRGB</title>
<html:link rel="help"
href="https://www.w3.org/TR/SVG2/pservers.html#LinearGradients"/>
<html:link rel="match" href="reference/gradient-color-interpolation-ref.svg" />
<html:meta name="fuzzy" content="maxDifference=0-20;totalPixels=0-29200" />
</g>
<defs>
<linearGradient id="gradientLinearRGB" gradientUnits="objectBoundingBox" color-interpolation="linearRGB">
<stop offset="0" stop-color="white"/>
<stop offset=".33" stop-color="blue"/>
<stop offset=".66" stop-color="red"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
</defs>
<rect x="20" y="20" width="200" height="200" style="fill:url(#gradientLinearRGB)" />
</svg>

Before

Width:  |  Height:  |  Size: 896 B

View File

@ -1,24 +0,0 @@
<svg width="100%" height="100%"
xmlns="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml">
<style>
div {
border: none;
margin: 0;
padding: 0;
};
</style>
<defs>
<linearGradient id="gradientLinearRGB" gradientUnits="objectBoundingBox" color-interpolation="linearRGB">
<stop offset="0" stop-color="white"/>
<stop offset=".33" stop-color="blue"/>
<stop offset=".66" stop-color="red"/>
<stop offset="1" stop-color="yellow"/>
</linearGradient>
</defs>
<foreignObject x="20" y="20" width="200" height="200">
<html:div style="height:100%;width:100%;background: linear-gradient(90deg in srgb-linear, white 0%, blue 33%, red 66%, yellow 100%);"/>
</foreignObject>
</svg>

Before

Width:  |  Height:  |  Size: 761 B