|
|
|
@ -37,6 +37,8 @@
|
|
|
|
|
#include "mozilla/webrender/WebRenderAPI.h"
|
|
|
|
|
#include "Units.h"
|
|
|
|
|
|
|
|
|
|
#include "mozilla/StaticPrefs_layout.h"
|
|
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
|
|
|
|
|
@ -1195,11 +1197,75 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
|
|
|
|
|
aMode =
|
|
|
|
|
mGradient->Repeating() ? wr::ExtendMode::Repeat : wr::ExtendMode::Clamp;
|
|
|
|
|
|
|
|
|
|
aStops.SetLength(mStops.Length());
|
|
|
|
|
for (uint32_t i = 0; i < mStops.Length(); i++) {
|
|
|
|
|
aStops[i].color = wr::ToColorF(ToDeviceColor(mStops[i].mColor));
|
|
|
|
|
aStops[i].color.a *= aOpacity;
|
|
|
|
|
aStops[i].offset = mStops[i].mPosition;
|
|
|
|
|
// If the interpolation space is not sRGB, or if color management is active,
|
|
|
|
|
// we need to add additional stops so that the sRGB interpolation in WebRender
|
|
|
|
|
// still closely approximates the correct curves. We prefer avoiding this if
|
|
|
|
|
// the gradient is simple because WebRender has fast rendering of linear
|
|
|
|
|
// gradients with 2 stops (which represent >99% of all gradients on the web).
|
|
|
|
|
//
|
|
|
|
|
// WebRender doesn't have easy access to StyleAbsoluteColor and CMS display
|
|
|
|
|
// color correction, so we just expand the gradient stop table significantly
|
|
|
|
|
// so that gamma and hue interpolation errors become imperceptible.
|
|
|
|
|
//
|
|
|
|
|
// This always turns into 128 pairs of stops inside WebRender as an
|
|
|
|
|
// implementation detail, so the number of stops we generate here should have
|
|
|
|
|
// very little impact on performance as the texture upload is always the same,
|
|
|
|
|
// except for the special linear gradient 2-stop case, and it is gpucache so
|
|
|
|
|
// if it does not change it is not re-uploaded.
|
|
|
|
|
//
|
|
|
|
|
// Color management bugs that this addresses:
|
|
|
|
|
// * https://bugzilla.mozilla.org/show_bug.cgi?id=939387
|
|
|
|
|
// * https://bugzilla.mozilla.org/show_bug.cgi?id=1248178
|
|
|
|
|
StyleColorInterpolationMethod styleColorInterpolationMethod =
|
|
|
|
|
mGradient->ColorInterpolationMethod();
|
|
|
|
|
if (mStops.Length() >= 2 &&
|
|
|
|
|
(styleColorInterpolationMethod.space != StyleColorSpace::Srgb ||
|
|
|
|
|
gfxPlatform::GetCMSMode() == CMSMode::All)) {
|
|
|
|
|
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++) {
|
|
|
|
|
aStops[i].color = wr::ToColorF(ToDeviceColor(mStops[i].mColor));
|
|
|
|
|
aStops[i].color.a *= aOpacity;
|
|
|
|
|
aStops[i].offset = (float)mStops[i].mPosition;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aLineStart = LayoutDevicePoint(mLineStart.x, mLineStart.y);
|
|
|
|
|