diff options
Diffstat (limited to 'layout')
-rw-r--r-- | layout/base/nsCSSRendering.cpp | 126 | ||||
-rw-r--r-- | layout/reftests/css-gradients/linear-premul-ref.html | 1 | ||||
-rw-r--r-- | layout/reftests/css-gradients/linear-premul.html | 1 | ||||
-rw-r--r-- | layout/reftests/css-gradients/radial-premul-ref.html | 1 | ||||
-rw-r--r-- | layout/reftests/css-gradients/radial-premul.html | 1 | ||||
-rw-r--r-- | layout/reftests/css-gradients/reftest.list | 2 | ||||
-rw-r--r-- | layout/style/nsCSSPseudoElements.h | 3 | ||||
-rw-r--r-- | layout/svg/nsSVGOuterSVGFrame.cpp | 44 | ||||
-rw-r--r-- | layout/svg/nsSVGOuterSVGFrame.h | 5 |
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 |