From 85aa2442221119caffdd124b98e4ee2bf3919d01 Mon Sep 17 00:00:00 2001 From: Rik Cabanier Date: Wed, 22 Oct 2014 14:24:00 +0200 Subject: [PATCH] Bug 1074056 - Part 1 - Add support for interpolation hints to CSS gradients. r=dbaron --- layout/style/nsCSSParser.cpp | 19 ++++++++++++++++++- layout/style/nsCSSValue.cpp | 17 ++++++++++++----- layout/style/nsCSSValue.h | 6 +++++- layout/style/nsComputedDOMStyle.cpp | 18 ++++++++++++------ layout/style/nsRuleNode.cpp | 12 ++++++++++-- layout/style/nsStyleStruct.cpp | 7 +++++-- layout/style/nsStyleStruct.h | 5 +++++ layout/style/test/property_database.js | 19 +++++++++++++++++++ 8 files changed, 86 insertions(+), 17 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index c7dbfb7b619e..3d43bd8d2f24 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -8804,12 +8804,15 @@ CSSParserImpl::ParseColorStop(nsCSSValueGradient* aGradient) { nsCSSValueGradientStop* stop = aGradient->mStops.AppendElement(); if (!ParseVariant(stop->mColor, VARIANT_COLOR, nullptr)) { - return false; + stop->mIsInterpolationHint = true; } // Stop positions do not have to fall between the starting-point and // ending-point, so we don't use ParseNonNegativeVariant. if (!ParseVariant(stop->mLocation, VARIANT_LP | VARIANT_CALC, nullptr)) { + if (stop->mIsInterpolationHint) { + return false; + } stop->mLocation.SetNoneValue(); } return true; @@ -9157,6 +9160,20 @@ CSSParserImpl::ParseGradientColorStops(nsCSSValueGradient* aGradient, return false; } + // Check if interpolation hints are in the correct location + bool previousPointWasInterpolationHint = true; + for (size_t x = 0; x < aGradient->mStops.Length(); x++) { + bool isInterpolationHint = aGradient->mStops[x].mIsInterpolationHint; + if (isInterpolationHint && previousPointWasInterpolationHint) { + return false; + } + previousPointWasInterpolationHint = isInterpolationHint; + } + + if (previousPointWasInterpolationHint) { + return false; + } + aValue.SetGradientValue(aGradient); return true; } diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index 6b6773a1dbc6..404306aa8ec2 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -1414,10 +1414,15 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult, } for (uint32_t i = 0 ;;) { - gradient->mStops[i].mColor.AppendToString(aProperty, aResult, - aSerialization); + bool isInterpolationHint = gradient->mStops[i].mIsInterpolationHint; + if (!isInterpolationHint) { + gradient->mStops[i].mColor.AppendToString(aProperty, aResult, + aSerialization); + } if (gradient->mStops[i].mLocation.GetUnit() != eCSSUnit_None) { - aResult.Append(' '); + if (!isInterpolationHint) { + aResult.Append(' '); + } gradient->mStops[i].mLocation.AppendToString(aProperty, aResult, aSerialization); } @@ -2351,14 +2356,16 @@ css::ImageValue::~ImageValue() nsCSSValueGradientStop::nsCSSValueGradientStop() : mLocation(eCSSUnit_None), - mColor(eCSSUnit_Null) + mColor(eCSSUnit_Null), + mIsInterpolationHint(false) { MOZ_COUNT_CTOR(nsCSSValueGradientStop); } nsCSSValueGradientStop::nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther) : mLocation(aOther.mLocation), - mColor(aOther.mColor) + mColor(aOther.mColor), + mIsInterpolationHint(aOther.mIsInterpolationHint) { MOZ_COUNT_CTOR(nsCSSValueGradientStop); } diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index f0c4e631c410..85a420938171 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -1341,11 +1341,15 @@ public: nsCSSValue mLocation; nsCSSValue mColor; + // If mIsInterpolationHint is true, there is no color, just + // a location. + bool mIsInterpolationHint; bool operator==(const nsCSSValueGradientStop& aOther) const { return (mLocation == aOther.mLocation && - mColor == aOther.mColor); + mIsInterpolationHint == aOther.mIsInterpolationHint && + (mIsInterpolationHint || mColor == aOther.mColor)); } bool operator!=(const nsCSSValueGradientStop& aOther) const diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index ea9005e727c1..a49fb4fbea84 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1928,13 +1928,19 @@ nsComputedDOMStyle::GetCSSGradientString(const nsStyleGradient* aGradient, if (needSep) { aString.AppendLiteral(", "); } - SetToRGBAColor(tmpVal, aGradient->mStops[i].mColor); - tmpVal->GetCssText(tokenString); - aString.Append(tokenString); - if (aGradient->mStops[i].mLocation.GetUnit() != eStyleUnit_None) { - aString.Append(' '); - AppendCSSGradientLength(aGradient->mStops[i].mLocation, tmpVal, aString); + const auto& stop = aGradient->mStops[i]; + if (!stop.mIsInterpolationHint) { + SetToRGBAColor(tmpVal, stop.mColor); + tmpVal->GetCssText(tokenString); + aString.Append(tokenString); + } + + if (stop.mLocation.GetUnit() != eStyleUnit_None) { + if (!stop.mIsInterpolationHint) { + aString.Append(' '); + } + AppendCSSGradientLength(stop.mLocation, tmpVal, aString); } needSep = true; } diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 31023503e554..1e32560f9a97 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -1107,12 +1107,20 @@ static void SetGradient(const nsCSSValue& aValue, nsPresContext* aPresContext, NS_NOTREACHED("unexpected unit for gradient stop location"); } + stop.mIsInterpolationHint = valueStop.mIsInterpolationHint; + // inherit is not a valid color for stops, so we pass in a dummy // parent color NS_ASSERTION(valueStop.mColor.GetUnit() != eCSSUnit_Inherit, "inherit is not a valid color for gradient stops"); - SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext, - aContext, stop.mColor, aCanStoreInRuleTree); + if (!valueStop.mIsInterpolationHint) { + SetColor(valueStop.mColor, NS_RGB(0, 0, 0), aPresContext, + aContext, stop.mColor, aCanStoreInRuleTree); + } else { + // Always initialize to the same color so we don't need to worry + // about comparisons. + stop.mColor = NS_RGB(0, 0, 0); + } aResult.mStops.AppendElement(stop); } diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index e65e33ac8e4e..94084fa725e8 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1766,8 +1766,11 @@ nsStyleGradient::operator==(const nsStyleGradient& aOther) const return false; for (uint32_t i = 0; i < mStops.Length(); i++) { - if (mStops[i].mLocation != aOther.mStops[i].mLocation || - mStops[i].mColor != aOther.mStops[i].mColor) + const auto& stop1 = mStops[i]; + const auto& stop2 = aOther.mStops[i]; + if (stop1.mLocation != stop2.mLocation || + stop1.mIsInterpolationHint != stop2.mIsInterpolationHint || + (!stop1.mIsInterpolationHint && stop1.mColor != stop2.mColor)) return false; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 93757fa4fcdb..291645414fe2 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -138,6 +138,11 @@ public: struct nsStyleGradientStop { nsStyleCoord mLocation; // percent, coord, calc, none nscolor mColor; + bool mIsInterpolationHint; + + // Use ==/!= on nsStyleGradient instead of on the gradient stop. + bool operator==(const nsStyleGradientStop&) const MOZ_DELETE; + bool operator!=(const nsStyleGradientStop&) const MOZ_DELETE; }; class nsStyleGradient MOZ_FINAL { diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 15b476fa59e8..206c83f09b25 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -86,6 +86,18 @@ var validGradientAndElementValues = [ "linear-gradient(1turn, red, blue)", "linear-gradient(.414rad, red, blue)", + "linear-gradient(.414rad, red, 50%, blue)", + "linear-gradient(.414rad, red, 0%, blue)", + "linear-gradient(.414rad, red, 100%, blue)", + + "linear-gradient(.414rad, red 50%, 50%, blue 50%)", + "linear-gradient(.414rad, red 50%, 20%, blue 50%)", + "linear-gradient(.414rad, red 50%, 30%, blue 10%)", + "linear-gradient(to right bottom, red, 20%, green 50%, 65%, blue)", + "linear-gradient(to right bottom, red, 20%, green 10%, blue)", + "linear-gradient(to right bottom, red, 50%, green 50%, 50%, blue)", + "linear-gradient(to right bottom, red, 0%, green 50%, 100%, blue)", + "-moz-linear-gradient(red, blue)", "-moz-linear-gradient(red, yellow, blue)", "-moz-linear-gradient(red 1px, yellow 20%, blue 24em, green)", @@ -504,6 +516,13 @@ var invalidGradientAndElementValues = [ "linear-gradient(1turn 20px, red, blue)", "linear-gradient(.414rad bottom, red, blue)", + "linear-gradient(to top, 0%, blue)", + "linear-gradient(to top, red, 100%)", + "linear-gradient(to top, red, 45%, 56%, blue)", + "linear-gradient(to top, red,, blue)", + "linear-gradient(to top, red, green 35%, 15%, 54%, blue)", + + "radial-gradient(top left 45deg, red, blue)", "radial-gradient(20% bottom -300deg, red, blue)", "radial-gradient(center 20% 1.95929rad, red, blue)",