summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/CSSGradientValue.cpp
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebCore/css/CSSGradientValue.cpp
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebCore/css/CSSGradientValue.cpp')
-rw-r--r--Source/WebCore/css/CSSGradientValue.cpp364
1 files changed, 277 insertions, 87 deletions
diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp
index 3b1beced3..500598bd9 100644
--- a/Source/WebCore/css/CSSGradientValue.cpp
+++ b/Source/WebCore/css/CSSGradientValue.cpp
@@ -36,8 +36,6 @@
#include "NodeRenderStyle.h"
#include "RenderObject.h"
#include "StyleResolver.h"
-#include "WebCoreMemoryInstrumentation.h"
-#include <wtf/MemoryInstrumentationVector.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/WTFString.h>
@@ -45,13 +43,6 @@ using namespace std;
namespace WebCore {
-void CSSGradientColorStop::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- info.addMember(m_position);
- info.addMember(m_color);
-}
-
PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize& size)
{
if (size.isEmpty())
@@ -62,13 +53,11 @@ PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize&
if (!clients().contains(renderer))
return 0;
- // Need to look up our size. Create a string of width*height to use as a hash key.
- Image* result = getImage(renderer, size);
+ Image* result = cachedImageForSize(size);
if (result)
return result;
}
- // We need to create an image.
RefPtr<Gradient> gradient;
if (isLinearGradient())
@@ -78,9 +67,9 @@ PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize&
gradient = static_cast<CSSRadialGradientValue*>(this)->createGradient(renderer, size);
}
- RefPtr<Image> newImage = GeneratorGeneratedImage::create(gradient, size);
+ RefPtr<GeneratorGeneratedImage> newImage = GeneratorGeneratedImage::create(gradient, size);
if (cacheable)
- putImage(size, newImage);
+ saveCachedImageForSize(size, newImage);
return newImage.release();
}
@@ -96,7 +85,7 @@ static inline bool compareStops(const CSSGradientColorStop& a, const CSSGradient
void CSSGradientValue::sortStopsIfNeeded()
{
- ASSERT(m_deprecatedType);
+ ASSERT(m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient);
if (!m_stopsSorted) {
if (m_stops.size())
std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
@@ -147,7 +136,7 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend
{
RenderStyle* style = renderer->style();
- if (m_deprecatedType) {
+ if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) {
sortStopsIfNeeded();
for (unsigned i = 0; i < m_stops.size(); i++) {
@@ -301,7 +290,7 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend
while (true) {
GradientStop newStop = stops[originalFirstStopIndex + srcStopOrdinal];
newStop.offset = currOffset;
- stops.prepend(newStop);
+ stops.insert(0, newStop);
++originalFirstStopIndex;
if (currOffset < 0)
break;
@@ -340,15 +329,21 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend
if (isLinearGradient()) {
float firstOffset = stops[0].offset;
float lastOffset = stops[numStops - 1].offset;
- float scale = lastOffset - firstOffset;
+ if (firstOffset != lastOffset) {
+ float scale = lastOffset - firstOffset;
- for (size_t i = 0; i < numStops; ++i)
- stops[i].offset = (stops[i].offset - firstOffset) / scale;
+ for (size_t i = 0; i < numStops; ++i)
+ stops[i].offset = (stops[i].offset - firstOffset) / scale;
- FloatPoint p0 = gradient->p0();
- FloatPoint p1 = gradient->p1();
- gradient->setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y())));
- gradient->setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y())));
+ FloatPoint p0 = gradient->p0();
+ FloatPoint p1 = gradient->p1();
+ gradient->setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y())));
+ gradient->setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y())));
+ } else {
+ // There's a single position that is outside the scale, clamp the positions to 1.
+ for (size_t i = 0; i < numStops; ++i)
+ stops[i].offset = 1;
+ }
} else if (isRadialGradient()) {
// Rather than scaling the points < 0, we truncate them, so only scale according to the largest point.
float firstOffset = 0;
@@ -413,7 +408,7 @@ static float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, Ren
if (value->isCalculatedPercentageWithLength())
return value->cssCalcValue()->toCalcValue(style, rootStyle, style->effectiveZoom())->evaluate(edgeDistance);
- switch (value->getIdent()) {
+ switch (value->getValueID()) {
case CSSValueTop:
ASSERT(!isHorizontal);
return 0;
@@ -426,20 +421,22 @@ static float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, Ren
case CSSValueRight:
ASSERT(isHorizontal);
return size.width();
+ default:
+ break;
}
return value->computeLength<float>(style, rootStyle, zoomFactor);
}
-FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size)
+FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* horizontal, CSSPrimitiveValue* vertical, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size)
{
FloatPoint result;
- if (first)
- result.setX(positionFromValue(first, style, rootStyle, size, true));
+ if (horizontal)
+ result.setX(positionFromValue(horizontal, style, rootStyle, size, true));
- if (second)
- result.setY(positionFromValue(second, style, rootStyle, size, false));
+ if (vertical)
+ result.setY(positionFromValue(vertical, style, rootStyle, size, false));
return result;
}
@@ -462,30 +459,19 @@ bool CSSGradientValue::isCacheable() const
return true;
}
-bool CSSGradientValue::hasAlpha(const RenderObject*) const
+bool CSSGradientValue::knownToBeOpaque(const RenderObject*) const
{
for (size_t i = 0; i < m_stops.size(); ++i) {
if (m_stops[i].m_resolvedColor.hasAlpha())
- return true;
+ return false;
}
- return false;
-}
-
-void CSSGradientValue::reportBaseClassMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
-{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- CSSImageGeneratorValue::reportBaseClassMemoryUsage(memoryObjectInfo);
- info.addMember(m_firstX);
- info.addMember(m_firstY);
- info.addMember(m_secondX);
- info.addMember(m_secondY);
- info.addMember(m_stops);
+ return true;
}
String CSSLinearGradientValue::customCssText() const
{
StringBuilder result;
- if (m_deprecatedType) {
+ if (m_gradientType == CSSDeprecatedLinearGradient) {
result.appendLiteral("-webkit-gradient(linear, ");
result.append(m_firstX->cssText());
result.append(' ');
@@ -514,7 +500,7 @@ String CSSLinearGradientValue::customCssText() const
result.append(')');
}
}
- } else {
+ } else if (m_gradientType == CSSPrefixedLinearGradient) {
if (m_repeating)
result.appendLiteral("-webkit-repeating-linear-gradient(");
else
@@ -545,6 +531,44 @@ String CSSLinearGradientValue::customCssText() const
result.append(stop.m_position->cssText());
}
}
+ } else {
+ if (m_repeating)
+ result.appendLiteral("repeating-linear-gradient(");
+ else
+ result.appendLiteral("linear-gradient(");
+
+ bool wroteSomething = false;
+
+ if (m_angle && m_angle->computeDegrees() != 180) {
+ result.append(m_angle->cssText());
+ wroteSomething = true;
+ } else if ((m_firstX || m_firstY) && !(!m_firstX && m_firstY && m_firstY->getValueID() == CSSValueBottom)) {
+ result.appendLiteral("to ");
+ if (m_firstX && m_firstY) {
+ result.append(m_firstX->cssText());
+ result.append(' ');
+ result.append(m_firstY->cssText());
+ } else if (m_firstX)
+ result.append(m_firstX->cssText());
+ else
+ result.append(m_firstY->cssText());
+ wroteSomething = true;
+ }
+
+ if (wroteSomething)
+ result.appendLiteral(", ");
+
+ for (unsigned i = 0; i < m_stops.size(); i++) {
+ const CSSGradientColorStop& stop = m_stops[i];
+ if (i)
+ result.appendLiteral(", ");
+ result.append(stop.m_color->cssText());
+ if (stop.m_position) {
+ result.append(' ');
+ result.append(stop.m_position->cssText());
+ }
+ }
+
}
result.append(')');
@@ -552,64 +576,71 @@ String CSSLinearGradientValue::customCssText() const
}
// Compute the endpoints so that a gradient of the given angle covers a box of the given size.
-static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint)
+static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint, CSSGradientType type)
{
+ // Prefixed gradients use "polar coordinate" angles, rather than "bearing" angles.
+ if (type == CSSPrefixedLinearGradient)
+ angleDeg = 90 - angleDeg;
+
angleDeg = fmodf(angleDeg, 360);
if (angleDeg < 0)
angleDeg += 360;
if (!angleDeg) {
- firstPoint.set(0, 0);
- secondPoint.set(size.width(), 0);
+ firstPoint.set(0, size.height());
+ secondPoint.set(0, 0);
return;
}
if (angleDeg == 90) {
- firstPoint.set(0, size.height());
- secondPoint.set(0, 0);
+ firstPoint.set(0, 0);
+ secondPoint.set(size.width(), 0);
return;
}
if (angleDeg == 180) {
- firstPoint.set(size.width(), 0);
- secondPoint.set(0, 0);
+ firstPoint.set(0, 0);
+ secondPoint.set(0, size.height());
return;
}
if (angleDeg == 270) {
- firstPoint.set(0, 0);
- secondPoint.set(0, size.height());
+ firstPoint.set(size.width(), 0);
+ secondPoint.set(0, 0);
return;
}
- float slope = tan(deg2rad(angleDeg));
+ // angleDeg is a "bearing angle" (0deg = N, 90deg = E),
+ // but tan expects 0deg = E, 90deg = N.
+ float slope = tan(deg2rad(90 - angleDeg));
// We find the endpoint by computing the intersection of the line formed by the slope,
// and a line perpendicular to it that intersects the corner.
float perpendicularSlope = -1 / slope;
- // Compute start corner relative to center.
+ // Compute start corner relative to center, in Cartesian space (+y = up).
float halfHeight = size.height() / 2;
float halfWidth = size.width() / 2;
FloatPoint endCorner;
if (angleDeg < 90)
endCorner.set(halfWidth, halfHeight);
else if (angleDeg < 180)
- endCorner.set(-halfWidth, halfHeight);
+ endCorner.set(halfWidth, -halfHeight);
else if (angleDeg < 270)
endCorner.set(-halfWidth, -halfHeight);
else
- endCorner.set(halfWidth, -halfHeight);
+ endCorner.set(-halfWidth, halfHeight);
// Compute c (of y = mx + c) using the corner point.
float c = endCorner.y() - perpendicularSlope * endCorner.x();
float endX = c / (slope - perpendicularSlope);
float endY = perpendicularSlope * endX + c;
- // We computed the end point, so set the second point, flipping the Y to account for angles going anticlockwise.
- secondPoint.set(halfWidth + endX, size.height() - (halfHeight + endY));
+ // We computed the end point, so set the second point,
+ // taking into account the moved origin and the fact that we're in drawing space (+y = down).
+ secondPoint.set(halfWidth + endX, halfHeight - endY);
// Reflect around the center for the start point.
- firstPoint.set(size.width() - secondPoint.x(), size.height() - secondPoint.y());
+ firstPoint.set(halfWidth - endX, halfHeight + endY);
}
PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* renderer, const IntSize& size)
@@ -622,18 +653,52 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render
FloatPoint secondPoint;
if (m_angle) {
float angle = m_angle->getFloatValue(CSSPrimitiveValue::CSS_DEG);
- endPointsFromAngle(angle, size, firstPoint, secondPoint);
+ endPointsFromAngle(angle, size, firstPoint, secondPoint, m_gradientType);
} else {
- firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size);
-
- if (m_secondX || m_secondY)
- secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size);
- else {
+ switch (m_gradientType) {
+ case CSSDeprecatedLinearGradient:
+ firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size);
+ if (m_secondX || m_secondY)
+ secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size);
+ else {
+ if (m_firstX)
+ secondPoint.setX(size.width() - firstPoint.x());
+ if (m_firstY)
+ secondPoint.setY(size.height() - firstPoint.y());
+ }
+ break;
+ case CSSPrefixedLinearGradient:
+ firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size);
if (m_firstX)
secondPoint.setX(size.width() - firstPoint.x());
if (m_firstY)
secondPoint.setY(size.height() - firstPoint.y());
+ break;
+ case CSSLinearGradient:
+ if (m_firstX && m_firstY) {
+ // "Magic" corners, so the 50% line touches two corners.
+ float rise = size.width();
+ float run = size.height();
+ if (m_firstX && m_firstX->getValueID() == CSSValueLeft)
+ run *= -1;
+ if (m_firstY && m_firstY->getValueID() == CSSValueBottom)
+ rise *= -1;
+ // Compute angle, and flip it back to "bearing angle" degrees.
+ float angle = 90 - rad2deg(atan2(rise, run));
+ endPointsFromAngle(angle, size, firstPoint, secondPoint, m_gradientType);
+ } else if (m_firstX || m_firstY) {
+ secondPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size);
+ if (m_firstX)
+ firstPoint.setX(size.width() - secondPoint.x());
+ if (m_firstY)
+ firstPoint.setY(size.height() - secondPoint.y());
+ } else
+ secondPoint.setY(size.height());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
}
+
}
RefPtr<Gradient> gradient = Gradient::create(firstPoint, secondPoint);
@@ -644,18 +709,43 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render
return gradient.release();
}
-void CSSLinearGradientValue::reportDescendantMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+bool CSSLinearGradientValue::equals(const CSSLinearGradientValue& other) const
{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- CSSGradientValue::reportBaseClassMemoryUsage(memoryObjectInfo);
- info.addMember(m_angle);
+ if (m_gradientType == CSSDeprecatedLinearGradient)
+ return other.m_gradientType == m_gradientType
+ && compareCSSValuePtr(m_firstX, other.m_firstX)
+ && compareCSSValuePtr(m_firstY, other.m_firstY)
+ && compareCSSValuePtr(m_secondX, other.m_secondX)
+ && compareCSSValuePtr(m_secondY, other.m_secondY)
+ && m_stops == other.m_stops;
+
+ if (m_repeating != other.m_repeating)
+ return false;
+
+ if (m_angle)
+ return compareCSSValuePtr(m_angle, other.m_angle) && m_stops == other.m_stops;
+
+ if (other.m_angle)
+ return false;
+
+ bool equalXorY = false;
+ if (m_firstX && m_firstY)
+ equalXorY = compareCSSValuePtr(m_firstX, other.m_firstX) && compareCSSValuePtr(m_firstY, other.m_firstY);
+ else if (m_firstX)
+ equalXorY =compareCSSValuePtr(m_firstX, other.m_firstX) && !other.m_firstY;
+ else if (m_firstY)
+ equalXorY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX;
+ else
+ equalXorY = !other.m_firstX || !other.m_firstY;
+
+ return equalXorY && m_stops == other.m_stops;
}
String CSSRadialGradientValue::customCssText() const
{
StringBuilder result;
- if (m_deprecatedType) {
+ if (m_gradientType == CSSDeprecatedRadialGradient) {
result.appendLiteral("-webkit-gradient(radial, ");
result.append(m_firstX->cssText());
result.append(' ');
@@ -689,7 +779,7 @@ String CSSRadialGradientValue::customCssText() const
result.append(')');
}
}
- } else {
+ } else if (m_gradientType == CSSPrefixedRadialGradient) {
if (m_repeating)
result.appendLiteral("-webkit-repeating-radial-gradient(");
else
@@ -735,6 +825,66 @@ String CSSRadialGradientValue::customCssText() const
result.append(stop.m_position->cssText());
}
}
+ } else {
+ if (m_repeating)
+ result.appendLiteral("repeating-radial-gradient(");
+ else
+ result.appendLiteral("radial-gradient(");
+
+ bool wroteSomething = false;
+
+ // The only ambiguous case that needs an explicit shape to be provided
+ // is when a sizing keyword is used (or all sizing is omitted).
+ if (m_shape && m_shape->getValueID() != CSSValueEllipse && (m_sizingBehavior || (!m_sizingBehavior && !m_endHorizontalSize))) {
+ result.appendLiteral("circle");
+ wroteSomething = true;
+ }
+
+ if (m_sizingBehavior && m_sizingBehavior->getValueID() != CSSValueFarthestCorner) {
+ if (wroteSomething)
+ result.append(' ');
+ result.append(m_sizingBehavior->cssText());
+ wroteSomething = true;
+ } else if (m_endHorizontalSize) {
+ if (wroteSomething)
+ result.append(' ');
+ result.append(m_endHorizontalSize->cssText());
+ if (m_endVerticalSize) {
+ result.append(' ');
+ result.append(m_endVerticalSize->cssText());
+ }
+ wroteSomething = true;
+ }
+
+ if (m_firstX || m_firstY) {
+ if (wroteSomething)
+ result.append(' ');
+ result.appendLiteral("at ");
+ if (m_firstX && m_firstY) {
+ result.append(m_firstX->cssText());
+ result.append(' ');
+ result.append(m_firstY->cssText());
+ } else if (m_firstX)
+ result.append(m_firstX->cssText());
+ else
+ result.append(m_firstY->cssText());
+ wroteSomething = true;
+ }
+
+ if (wroteSomething)
+ result.appendLiteral(", ");
+
+ for (unsigned i = 0; i < m_stops.size(); i++) {
+ const CSSGradientColorStop& stop = m_stops[i];
+ if (i)
+ result.appendLiteral(", ");
+ result.append(stop.m_color->cssText());
+ if (stop.m_position) {
+ result.append(' ');
+ result.append(stop.m_position->cssText());
+ }
+ }
+
}
result.append(')');
@@ -859,21 +1009,25 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render
float aspectRatio = 1; // width / height.
if (m_secondRadius)
secondRadius = resolveRadius(m_secondRadius.get(), renderer->style(), rootStyle);
- else if (m_endHorizontalSize || m_endVerticalSize) {
+ else if (m_endHorizontalSize) {
float width = size.width();
float height = size.height();
secondRadius = resolveRadius(m_endHorizontalSize.get(), renderer->style(), rootStyle, &width);
- aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height);
+ if (m_endVerticalSize)
+ aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height);
+ else
+ aspectRatio = 1;
} else {
enum GradientShape { Circle, Ellipse };
GradientShape shape = Ellipse;
- if (m_shape && m_shape->getIdent() == CSSValueCircle)
+ if ((m_shape && m_shape->getValueID() == CSSValueCircle)
+ || (!m_shape && !m_sizingBehavior && m_endHorizontalSize && !m_endVerticalSize))
shape = Circle;
enum GradientFill { ClosestSide, ClosestCorner, FarthestSide, FarthestCorner };
GradientFill fill = FarthestCorner;
- switch (m_sizingBehavior ? m_sizingBehavior->getIdent() : 0) {
+ switch (m_sizingBehavior ? m_sizingBehavior->getValueID() : 0) {
case CSSValueContain:
case CSSValueClosestSide:
fill = ClosestSide;
@@ -888,6 +1042,8 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render
case CSSValueFarthestCorner:
fill = FarthestCorner;
break;
+ default:
+ break;
}
// Now compute the end radii based on the second point, shape and fill.
@@ -969,16 +1125,50 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render
return gradient.release();
}
-void CSSRadialGradientValue::reportDescendantMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
+bool CSSRadialGradientValue::equals(const CSSRadialGradientValue& other) const
{
- MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
- CSSGradientValue::reportBaseClassMemoryUsage(memoryObjectInfo);
- info.addMember(m_firstRadius);
- info.addMember(m_secondRadius);
- info.addMember(m_shape);
- info.addMember(m_sizingBehavior);
- info.addMember(m_endHorizontalSize);
- info.addMember(m_endVerticalSize);
+ if (m_gradientType == CSSDeprecatedRadialGradient)
+ return other.m_gradientType == m_gradientType
+ && compareCSSValuePtr(m_firstX, other.m_firstX)
+ && compareCSSValuePtr(m_firstY, other.m_firstY)
+ && compareCSSValuePtr(m_secondX, other.m_secondX)
+ && compareCSSValuePtr(m_secondY, other.m_secondY)
+ && compareCSSValuePtr(m_firstRadius, other.m_firstRadius)
+ && compareCSSValuePtr(m_secondRadius, other.m_secondRadius)
+ && m_stops == other.m_stops;
+
+ if (m_repeating != other.m_repeating)
+ return false;
+
+ bool equalXorY = false;
+ if (m_firstX && m_firstY)
+ equalXorY = compareCSSValuePtr(m_firstX, other.m_firstX) && compareCSSValuePtr(m_firstY, other.m_firstY);
+ else if (m_firstX)
+ equalXorY = compareCSSValuePtr(m_firstX, other.m_firstX) && !other.m_firstY;
+ else if (m_firstY)
+ equalXorY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX;
+ else
+ equalXorY == !other.m_firstX || !other.m_firstY;
+
+ if (!equalXorY)
+ return false;
+
+ bool equalShape = true;
+ bool equalSizingBehavior = true;
+ bool equalHorizontalAndVerticalSize = true;
+
+ if (m_shape)
+ equalShape = compareCSSValuePtr(m_shape, other.m_shape);
+ else if (m_sizingBehavior)
+ equalSizingBehavior = compareCSSValuePtr(m_sizingBehavior, other.m_sizingBehavior);
+ else if (m_endHorizontalSize && m_endVerticalSize)
+ equalHorizontalAndVerticalSize = compareCSSValuePtr(m_endHorizontalSize, other.m_endHorizontalSize) && compareCSSValuePtr(m_endVerticalSize, other.m_endVerticalSize);
+ else {
+ equalShape = !other.m_shape;
+ equalSizingBehavior = !other.m_sizingBehavior;
+ equalHorizontalAndVerticalSize = !other.m_endHorizontalSize && !other.m_endVerticalSize;
+ }
+ return equalShape && equalSizingBehavior && equalHorizontalAndVerticalSize && m_stops == other.m_stops;
}
} // namespace WebCore