summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--layout/base/nsCSSRendering.cpp126
-rw-r--r--layout/reftests/css-gradients/linear-premul-ref.html1
-rw-r--r--layout/reftests/css-gradients/linear-premul.html1
-rw-r--r--layout/reftests/css-gradients/radial-premul-ref.html1
-rw-r--r--layout/reftests/css-gradients/radial-premul.html1
-rw-r--r--layout/reftests/css-gradients/reftest.list2
6 files changed, 42 insertions, 90 deletions
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp
index 1c6d97395a..054632ad79 100644
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2268,14 +2268,8 @@ ComputeRadialGradientLine(nsPresContext* aPresContext,
*aLineEnd = *aLineStart + gfxPoint(radiusX*cos(-angle), radiusY*sin(-angle));
}
-
-static float Interpolate(float aF1, float aF2, float aFrac)
-{
- return aF1 + aFrac * (aF2 - aF1);
-}
-
// Returns aFrac*aC2 + (1 - aFrac)*C1. The interpolation is done
-// in unpremultiplied space, which is what SVG gradients and cairo
+// in RGBA color space, which is what SVG gradients and cairo
// gradients expect.
static Color
InterpolateColor(const Color& aC1, const Color& aC2, float aFrac)
@@ -2435,79 +2429,6 @@ static void ResolveMidpoints(nsTArray<ColorStop>& stops)
}
}
-static Color
-Premultiply(const Color& aColor)
-{
- gfx::Float a = aColor.a;
- return Color(aColor.r * a, aColor.g * a, aColor.b * a, a);
-}
-
-static Color
-Unpremultiply(const Color& aColor)
-{
- gfx::Float a = aColor.a;
- return (a > 0.f)
- ? Color(aColor.r / a, aColor.g / a, aColor.b / a, a)
- : aColor;
-}
-
-static Color
-TransparentColor(Color aColor) {
- aColor.a = 0;
- return aColor;
-}
-
-// Adjusts and adds color stops in such a way that drawing the gradient with
-// unpremultiplied interpolation looks nearly the same as if it were drawn with
-// premultiplied interpolation.
-static const float kAlphaIncrementPerGradientStep = 0.1f;
-static void
-ResolvePremultipliedAlpha(nsTArray<ColorStop>& aStops)
-{
- for (size_t x = 1; x < aStops.Length(); x++) {
- const ColorStop leftStop = aStops[x - 1];
- const ColorStop rightStop = aStops[x];
-
- // if the left and right stop have the same alpha value, we don't need
- // to do anything
- if (leftStop.mColor.a == rightStop.mColor.a) {
- continue;
- }
-
- // Is the stop on the left 100% transparent? If so, have it adopt the color
- // of the right stop
- if (leftStop.mColor.a == 0) {
- aStops[x - 1].mColor = TransparentColor(rightStop.mColor);
- continue;
- }
-
- // Is the stop on the right completely transparent?
- // If so, duplicate it and assign it the color on the left.
- if (rightStop.mColor.a == 0) {
- ColorStop newStop = rightStop;
- newStop.mColor = TransparentColor(leftStop.mColor);
- aStops.InsertElementAt(x, newStop);
- x++;
- continue;
- }
-
- // Now handle cases where one or both of the stops are partially transparent.
- if (leftStop.mColor.a != 1.0f || rightStop.mColor.a != 1.0f) {
- Color premulLeftColor = Premultiply(leftStop.mColor);
- Color premulRightColor = Premultiply(rightStop.mColor);
- // Calculate how many extra steps. We do a step per 10% transparency.
- size_t stepCount = NSToIntFloor(fabsf(leftStop.mColor.a - rightStop.mColor.a) / kAlphaIncrementPerGradientStep);
- for (size_t y = 1; y < stepCount; y++) {
- float frac = static_cast<float>(y) / stepCount;
- ColorStop newStop(Interpolate(leftStop.mPosition, rightStop.mPosition, frac), false,
- Unpremultiply(InterpolateColor(premulLeftColor, premulRightColor, frac)));
- aStops.InsertElementAt(x, newStop);
- x++;
- }
- }
- }
-}
-
static ColorStop
InterpolateColorStop(const ColorStop& aFirst, const ColorStop& aSecond,
double aPosition, const Color& aDefault)
@@ -2522,9 +2443,9 @@ InterpolateColorStop(const ColorStop& aFirst, const ColorStop& aSecond,
}
return ColorStop(aPosition, false,
- Unpremultiply(InterpolateColor(Premultiply(aFirst.mColor),
- Premultiply(aSecond.mColor),
- (aPosition - aFirst.mPosition) / delta)));
+ InterpolateColor(aFirst.mColor,
+ aSecond.mColor,
+ (aPosition - aFirst.mPosition) / delta));
}
// Clamp and extend the given ColorStop array in-place to fit exactly into the
@@ -2749,6 +2670,44 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
lineLength = rectLen;
}
+ // Special case for 'transparent'
+ for (uint32_t i = 0; i < stops.Length(); ++i) {
+ Color color = stops[i].mColor;
+ if (color.r == 0 && color.g == 0 && color.b == 0 && color.a == 0) {
+ // We have (0,0,0,0) as a color stop - this means 'transparent'.
+ // In this case for the usually intended effect, we change the color
+ // of the transparent stop to the color of the adjacent stop with
+ // 0 opacity. If we are not on either edge, we add a stop on both
+ // sides of the transparent point with the adjacent color value.
+ // i.e.: c1 -> c1 (alpha 0) | c2 (alpha 0) -> c2
+ // XXX: We should probably track the use of the transparent keyword
+ // down from the CSS parsing level to here with a flag in mStops, if
+ // rgba(0,0,0,0) ever is an intended thing (very much a corner case).
+ if (i > 0) {
+ // Change stop color to adjacent-previous (color->T)
+ color = stops[i - 1].mColor;
+ color.a = 0;
+ stops[i].mColor = color;
+ if (i < stops.Length() - 1) {
+ // We're in the middle somewhere: insert stop adjacent-next (T->color)
+ Color color2 = stops[i + 1].mColor;
+ color2.a = 0;
+ if (color != color2) {
+ // Only insert an extra stop if c1 is different than c2 in c1->T->c2
+ // Note: A transparent stop is never considered an interpolation hint
+ stops.InsertElementAt(i + 1, ColorStop(stops[i].mPosition, false, color2));
+ i++;
+ }
+ }
+ } else if (i < stops.Length() - 1) {
+ // Change stop color to adjacent-next (T->color)
+ color = stops[i + 1].mColor;
+ color.a = 0;
+ stops[i].mColor = color;
+ }
+ }
+ }
+
// Eliminate negative-position stops if the gradient is radial.
double firstStop = stops[0].mPosition;
if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR && firstStop < 0.0) {
@@ -2924,7 +2883,6 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
}
ResolveMidpoints(stops);
- ResolvePremultipliedAlpha(stops);
bool isRepeat = aGradient->mRepeating || forceRepeatToCoverTiles;
diff --git a/layout/reftests/css-gradients/linear-premul-ref.html b/layout/reftests/css-gradients/linear-premul-ref.html
deleted file mode 100644
index bf0b12c33f..0000000000
--- a/layout/reftests/css-gradients/linear-premul-ref.html
+++ /dev/null
@@ -1 +0,0 @@
-<div style="background: linear-gradient(to right, rgba(255, 0, 0, .9) 0% , rgba(255, 0, 0, 0) 50%, rgba(0, 0, 255, 0) 50%, rgba(0, 0, 255, 1) 100%) no-repeat; width: 300px; height: 300px;"><br></div>
diff --git a/layout/reftests/css-gradients/linear-premul.html b/layout/reftests/css-gradients/linear-premul.html
deleted file mode 100644
index 20c7c276a2..0000000000
--- a/layout/reftests/css-gradients/linear-premul.html
+++ /dev/null
@@ -1 +0,0 @@
-<div style="background: linear-gradient(to right, rgba(255, 0, 0, .9) 0% , rgba(0, 255, 0, 0) 50%, rgba(0, 0, 255, 1) 100%) no-repeat; width: 300px; height: 300px;"><br></div>
diff --git a/layout/reftests/css-gradients/radial-premul-ref.html b/layout/reftests/css-gradients/radial-premul-ref.html
deleted file mode 100644
index 1424f4373c..0000000000
--- a/layout/reftests/css-gradients/radial-premul-ref.html
+++ /dev/null
@@ -1 +0,0 @@
-<div style="background: radial-gradient(rgba(255, 0, 0, .9) 0% , rgba(255, 0, 0, 0) 50%, rgba(0, 0, 255, 0) 50%, rgba(0, 0, 255, 1) 100%) no-repeat; width: 300px; height: 300px;"><br></div>
diff --git a/layout/reftests/css-gradients/radial-premul.html b/layout/reftests/css-gradients/radial-premul.html
deleted file mode 100644
index 33b89c72bc..0000000000
--- a/layout/reftests/css-gradients/radial-premul.html
+++ /dev/null
@@ -1 +0,0 @@
-<div style="background: radial-gradient(rgba(255, 0, 0, .9) 0% , rgba(0, 255, 0, 0) 50%, rgba(0, 0, 255, 1) 100%) no-repeat; width: 300px; height: 300px;"><br></div>
diff --git a/layout/reftests/css-gradients/reftest.list b/layout/reftests/css-gradients/reftest.list
index a93070752c..729bc60586 100644
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -16,7 +16,6 @@ fuzzy-if(!contentSameGfxBackendAsCanvas,4,92400) fuzzy-if(azureSkiaGL||skiaConte
== linear-diagonal-4a.html linear-diagonal-4-ref.html
== linear-diagonal-4b.html linear-diagonal-4-ref.html
== linear-diagonal-4c.html linear-diagonal-4-ref.html
-== linear-premul.html linear-premul-ref.html
# these tests uses a similar gradient over different bounds. It's perfectly
# reasonable to expect implementations to give slightly different results
@@ -92,7 +91,6 @@ fuzzy-if(Android,4,248) == radial-zero-length-1g.html radial-zero-length-1-ref.h
fuzzy-if(Android,4,248) == radial-zero-length-1h.html radial-zero-length-1-ref.html
fuzzy-if(Android,4,248) == radial-zero-length-1i.html radial-zero-length-1-ref.html
fuzzy-if(Android,4,248) == radial-zero-length-1j.html radial-zero-length-1-ref.html
-== radial-premul.html radial-premul-ref.html
== repeated-final-stop-1.html repeated-final-stop-1-ref.html
== repeating-linear-1a.html repeating-linear-1-ref.html
== repeating-linear-1b.html repeating-linear-1-ref.html