summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
Diffstat (limited to 'layout')
-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
-rw-r--r--layout/style/nsCSSPseudoElements.h3
-rw-r--r--layout/svg/nsSVGOuterSVGFrame.cpp44
-rw-r--r--layout/svg/nsSVGOuterSVGFrame.h5
9 files changed, 79 insertions, 105 deletions
diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp
index 1c6d97395..054632ad7 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 bf0b12c33..000000000
--- 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 20c7c276a..000000000
--- 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 1424f4373..000000000
--- 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 33b89c72b..000000000
--- 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 a93070752..729bc6058 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
diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h
index 657ef663e..eaf8d966b 100644
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -111,8 +111,7 @@ private:
// which is a general gcc bug that we seem to have hit only on Android/x86.
#if defined(ANDROID) && defined(__i386__) && defined(__GNUC__) && \
!defined(__clang__)
-#if (MOZ_GCC_VERSION_AT_LEAST(4,8,0) && MOZ_GCC_VERSION_AT_MOST(4,8,4)) || \
- (MOZ_GCC_VERSION_AT_LEAST(4,9,0) && MOZ_GCC_VERSION_AT_MOST(4,9,2))
+#if (MOZ_GCC_VERSION_AT_LEAST(4,9,0) && MOZ_GCC_VERSION_AT_MOST(4,9,2))
__attribute__((noinline))
#endif
#endif
diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp
index 683f10bc7..aeadccbc5 100644
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -979,21 +979,43 @@ nsSVGOuterSVGAnonChildFrame::GetType() const
}
bool
-nsSVGOuterSVGAnonChildFrame::HasChildrenOnlyTransform(gfx::Matrix *aTransform) const
+nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform,
+ Matrix* aFromParentTransform) const
{
- // We must claim our nsSVGOuterSVGFrame's children-only transforms as our own
- // so that the children we are used to wrap are transformed properly.
+ // Our elements 'transform' attribute is applied to our nsSVGOuterSVGFrame
+ // parent, and the element's children-only transforms are applied to us, the
+ // anonymous child frame. Since we are the child frame, we apply the
+ // children-only transforms as if they are our own transform.
- SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
+ SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent);
+
+ if (!content->HasChildrenOnlyTransform()) {
+ return false;
+ }
+
+ // Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
+ gfxMatrix ownMatrix =
+ content->PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace);
- bool hasTransform = content->HasChildrenOnlyTransform();
+ if (ownMatrix.IsIdentity()) {
+ return false;
+ }
+
+ if (aOwnTransform) {
+ if (ownMatrix.HasNonTranslation()) {
+ // Note: viewBox, currentScale and currentTranslate should only
+ // produce a rectilinear transform.
+ // The nsDisplayTransform code will apply this transform to our frame,
+ // including to our frame position. We don't want our frame position to
+ // be scaled though, so we need to correct for that in the transform.
+ CSSPoint pos = CSSPixel::FromAppUnits(GetPosition());
+ CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y);
+ CSSPoint deltaPos = scaledPos - pos;
+ ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y);
+ }
- if (hasTransform && aTransform) {
- // Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
- gfxMatrix identity;
- *aTransform = gfx::ToMatrix(
- content->PrependLocalTransformsTo(identity, eChildToUserSpace));
+ *aOwnTransform = gfx::ToMatrix(ownMatrix);
}
- return hasTransform;
+ return true;
}
diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h
index a08593678..6d29234ac 100644
--- a/layout/svg/nsSVGOuterSVGFrame.h
+++ b/layout/svg/nsSVGOuterSVGFrame.h
@@ -263,6 +263,9 @@ public:
*/
virtual nsIAtom* GetType() const override;
+ bool IsSVGTransformed(Matrix *aOwnTransform,
+ Matrix *aFromParentTransform) const override;
+
// nsSVGContainerFrame methods:
virtual gfxMatrix GetCanvasTM() override {
// GetCanvasTM returns the transform from an SVG frame to the frame's
@@ -270,8 +273,6 @@ public:
// set on us for any CSS border or padding on our nsSVGOuterSVGFrame.
return static_cast<nsSVGOuterSVGFrame*>(GetParent())->GetCanvasTM();
}
-
- virtual bool HasChildrenOnlyTransform(Matrix *aTransform) const override;
};
#endif