diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/css/CSSGradientValue.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/css/CSSGradientValue.cpp')
-rw-r--r-- | Source/WebCore/css/CSSGradientValue.cpp | 368 |
1 files changed, 235 insertions, 133 deletions
diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp index 500598bd9..568857e1b 100644 --- a/Source/WebCore/css/CSSGradientValue.cpp +++ b/Source/WebCore/css/CSSGradientValue.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,31 +27,31 @@ #include "CSSGradientValue.h" #include "CSSCalculationValue.h" +#include "CSSToLengthConversionData.h" #include "CSSValueKeywords.h" -#include "GeneratorGeneratedImage.h" +#include "FloatSize.h" +#include "FloatSizeHash.h" #include "Gradient.h" +#include "GradientImage.h" #include "Image.h" -#include "IntSize.h" -#include "IntSizeHash.h" #include "NodeRenderStyle.h" -#include "RenderObject.h" +#include "RenderElement.h" +#include "RenderView.h" #include "StyleResolver.h" #include <wtf/text/StringBuilder.h> #include <wtf/text/WTFString.h> -using namespace std; - namespace WebCore { -PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize& size) +RefPtr<Image> CSSGradientValue::image(RenderElement* renderer, const FloatSize& size) { if (size.isEmpty()) - return 0; + return nullptr; bool cacheable = isCacheable(); if (cacheable) { if (!clients().contains(renderer)) - return 0; + return nullptr; Image* result = cachedImageForSize(size); if (result) @@ -60,18 +60,16 @@ PassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize& RefPtr<Gradient> gradient; - if (isLinearGradient()) - gradient = static_cast<CSSLinearGradientValue*>(this)->createGradient(renderer, size); - else { - ASSERT(isRadialGradient()); - gradient = static_cast<CSSRadialGradientValue*>(this)->createGradient(renderer, size); - } + if (is<CSSLinearGradientValue>(*this)) + gradient = downcast<CSSLinearGradientValue>(*this).createGradient(*renderer, size); + else + gradient = downcast<CSSRadialGradientValue>(*this).createGradient(*renderer, size); - RefPtr<GeneratorGeneratedImage> newImage = GeneratorGeneratedImage::create(gradient, size); + RefPtr<GradientImage> newImage = GradientImage::create(gradient, size); if (cacheable) saveCachedImageForSize(size, newImage); - return newImage.release(); + return newImage; } // Should only ever be called for deprecated gradients. @@ -97,45 +95,63 @@ struct GradientStop { Color color; float offset; bool specified; + bool isMidpoint; GradientStop() : offset(0) , specified(false) + , isMidpoint(false) { } }; -PassRefPtr<CSSGradientValue> CSSGradientValue::gradientWithStylesResolved(StyleResolver* styleResolver) +RefPtr<CSSGradientValue> CSSGradientValue::gradientWithStylesResolved(StyleResolver* styleResolver) { bool derived = false; - for (unsigned i = 0; i < m_stops.size(); i++) - if (styleResolver->colorFromPrimitiveValueIsDerivedFromElement(m_stops[i].m_color.get())) { - m_stops[i].m_colorIsDerivedFromElement = true; + for (auto& stop : m_stops) { + if (!stop.isMidpoint && styleResolver->colorFromPrimitiveValueIsDerivedFromElement(*stop.m_color)) { + stop.m_colorIsDerivedFromElement = true; derived = true; break; } + } RefPtr<CSSGradientValue> result; if (!derived) result = this; - else if (isLinearGradient()) - result = static_cast<CSSLinearGradientValue*>(this)->clone(); - else if (isRadialGradient()) - result = static_cast<CSSRadialGradientValue*>(this)->clone(); + else if (is<CSSLinearGradientValue>(*this)) + result = downcast<CSSLinearGradientValue>(*this).clone(); + else if (is<CSSRadialGradientValue>(*this)) + result = downcast<CSSRadialGradientValue>(*this).clone(); else { ASSERT_NOT_REACHED(); - return 0; + return nullptr; + } + + for (auto& stop : result->m_stops) { + if (!stop.isMidpoint) + stop.m_resolvedColor = styleResolver->colorFromPrimitiveValue(*stop.m_color); } - for (unsigned i = 0; i < result->m_stops.size(); i++) - result->m_stops[i].m_resolvedColor = styleResolver->colorFromPrimitiveValue(result->m_stops[i].m_color.get()); + return result; +} - return result.release(); +static inline int interpolate(int min, int max, float position) +{ + return min + static_cast<int>(position * (max - min)); } -void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, RenderStyle* rootStyle, float maxLengthForRepeat) +static inline Color interpolate(Color color1, Color color2, float position) { - RenderStyle* style = renderer->style(); + int red = interpolate(color1.red(), color2.red(), position); + int green = interpolate(color1.green(), color2.green(), position); + int blue = interpolate(color1.blue(), color2.blue(), position); + int alpha = interpolate(color1.alpha(), color2.alpha(), position); + return Color(red, green, blue, alpha); +} + +void CSSGradientValue::addStops(Gradient& gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat) +{ if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) { sortStopsIfNeeded(); @@ -148,11 +164,11 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend else offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); - gradient->addColorStop(offset, stop.m_resolvedColor); + gradient.addColorStop(offset, stop.m_resolvedColor); } // The back end already sorted the stops. - gradient->setStopsSorted(true); + gradient.setStopsSorted(true); return; } @@ -163,31 +179,35 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend float gradientLength = 0; bool computedGradientLength = false; - FloatPoint gradientStart = gradient->p0(); + FloatPoint gradientStart = gradient.p0(); FloatPoint gradientEnd; - if (isLinearGradient()) - gradientEnd = gradient->p1(); - else if (isRadialGradient()) - gradientEnd = gradientStart + FloatSize(gradient->endRadius(), 0); + if (isLinearGradientValue()) + gradientEnd = gradient.p1(); + else if (isRadialGradientValue()) + gradientEnd = gradientStart + FloatSize(gradient.endRadius(), 0); for (size_t i = 0; i < numStops; ++i) { const CSSGradientColorStop& stop = m_stops[i]; + stops[i].isMidpoint = stop.isMidpoint; stops[i].color = stop.m_resolvedColor; if (stop.m_position) { - if (stop.m_position->isPercentage()) - stops[i].offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; - else if (stop.m_position->isLength() || stop.m_position->isCalculatedPercentageWithLength()) { + const CSSPrimitiveValue& positionValue = *stop.m_position; + if (positionValue.isPercentage()) + stops[i].offset = positionValue.getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; + else if (positionValue.isLength() || positionValue.isViewportPercentageLength() || positionValue.isCalculatedPercentageWithLength()) { if (!computedGradientLength) { FloatSize gradientSize(gradientStart - gradientEnd); gradientLength = gradientSize.diagonalLength(); } float length; - if (stop.m_position->isLength()) - length = stop.m_position->computeLength<float>(style, rootStyle, style->effectiveZoom()); - else - length = stop.m_position->cssCalcValue()->toCalcValue(style, rootStyle, style->effectiveZoom())->evaluate(gradientLength); + if (positionValue.isLength()) + length = positionValue.computeLength<float>(conversionData); + else { + Ref<CalculationValue> calculationValue { positionValue.cssCalcValue()->createCalculationValue(conversionData) }; + length = calculationValue->evaluate(gradientLength); + } stops[i].offset = (gradientLength > 0) ? length / gradientLength : 0; } else { ASSERT_NOT_REACHED(); @@ -251,6 +271,86 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend } } + // Walk over the color stops, look for midpoints and add stops as needed. + // If mid < 50%, add 2 stops to the left and 6 to the right + // else add 6 stops to the left and 2 to the right. + // Stops on the side with the most stops start midway because the curve approximates + // a line in that region. We then add 5 more color stops on that side to minimize the change + // how the luminance changes at each of the color stops. We don't have to add as many on the other side + // since it becomes small which increases the differentation of luminance which hides the color stops. + // Even with 4 extra color stops, it *is* possible to discern the steps when the gradient is large and has + // large luminance differences between midpoint and color stop. If this becomes an issue, we can consider + // making this algorithm a bit smarter. + + // Midpoints that coincide with color stops are treated specially since they don't require + // extra stops and generate hard lines. + for (size_t x = 1; x < stops.size() - 1;) { + if (!stops[x].isMidpoint) { + ++x; + continue; + } + + // Find previous and next color so we know what to interpolate between. + // We already know they have a color since we checked for that earlier. + Color color1 = stops[x - 1].color; + Color color2 = stops[x + 1].color; + // Likewise find the position of previous and next color stop. + float offset1 = stops[x - 1].offset; + float offset2 = stops[x + 1].offset; + float offset = stops[x].offset; + + // Check if everything coincides or the midpoint is exactly in the middle. + // If so, ignore the midpoint. + if (offset - offset1 == offset2 - offset) { + stops.remove(x); + continue; + } + + // Check if we coincide with the left color stop. + if (offset1 == offset) { + // Morph the midpoint to a regular stop with the color of the next color stop. + stops[x].color = color2; + stops[x].isMidpoint = false; + continue; + } + + // Check if we coincide with the right color stop. + if (offset2 == offset) { + // Morph the midpoint to a regular stop with the color of the previous color stop. + stops[x].color = color1; + stops[x].isMidpoint = false; + continue; + } + + float midpoint = (offset - offset1) / (offset2 - offset1); + GradientStop newStops[9]; + if (midpoint > .5f) { + for (size_t y = 0; y < 7; ++y) + newStops[y].offset = offset1 + (offset - offset1) * (7 + y) / 13; + + newStops[7].offset = offset + (offset2 - offset) / 3; + newStops[8].offset = offset + (offset2 - offset) * 2 / 3; + } else { + newStops[0].offset = offset1 + (offset - offset1) / 3; + newStops[1].offset = offset1 + (offset - offset1) * 2 / 3; + + for (size_t y = 0; y < 7; ++y) + newStops[y + 2].offset = offset + (offset2 - offset) * y / 13; + } + // calculate colors + for (size_t y = 0; y < 9; ++y) { + float relativeOffset = (newStops[y].offset - offset1) / (offset2 - offset1); + float multiplier = powf(relativeOffset, logf(.5f) / logf(midpoint)); + newStops[y].color = interpolate(color1, color2, multiplier); + } + + stops.remove(x); + stops.insert(x, newStops, 9); + x += 9; + } + + numStops = stops.size(); + // If the gradient is repeating, repeat the color stops. // We can't just push this logic down into the platform-specific Gradient code, // because we have to know the extent of the gradient, and possible move the end points. @@ -268,14 +368,14 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend // Radial gradients may need to extend further than the endpoints, because they have // to repeat out to the corners of the box. - if (isRadialGradient()) { + if (isRadialGradientValue()) { if (!computedGradientLength) { FloatSize gradientSize(gradientStart - gradientEnd); gradientLength = gradientSize.diagonalLength(); } if (maxLengthForRepeat > gradientLength) - maxExtent = maxLengthForRepeat / gradientLength; + maxExtent = gradientLength > 0 ? maxLengthForRepeat / gradientLength : 0; } size_t originalNumStops = numStops; @@ -326,7 +426,7 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend // If the gradient goes outside the 0-1 range, normalize it by moving the endpoints, and adjusting the stops. if (numStops > 1 && (stops[0].offset < 0 || stops[numStops - 1].offset > 1)) { - if (isLinearGradient()) { + if (isLinearGradientValue()) { float firstOffset = stops[0].offset; float lastOffset = stops[numStops - 1].offset; if (firstOffset != lastOffset) { @@ -335,16 +435,16 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend 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()) { + } else if (isRadialGradientValue()) { // Rather than scaling the points < 0, we truncate them, so only scale according to the largest point. float firstOffset = 0; float lastOffset = stops[numStops - 1].offset; @@ -383,32 +483,32 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, Rend for (size_t i = 0; i < numStops; ++i) stops[i].offset /= scale; - gradient->setStartRadius(gradient->startRadius() * scale); - gradient->setEndRadius(gradient->endRadius() * scale); + gradient.setStartRadius(gradient.startRadius() * scale); + gradient.setEndRadius(gradient.endRadius() * scale); } } for (unsigned i = 0; i < numStops; i++) - gradient->addColorStop(stops[i].offset, stops[i].color); + gradient.addColorStop(stops[i].offset, stops[i].color); - gradient->setStopsSorted(true); + gradient.setStopsSorted(true); } -static float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size, bool isHorizontal) +static float positionFromValue(CSSPrimitiveValue& value, const CSSToLengthConversionData& conversionData, const FloatSize& size, bool isHorizontal) { - float zoomFactor = style->effectiveZoom(); - - if (value->isNumber()) - return value->getFloatValue() * zoomFactor; + if (value.isNumber()) + return value.getFloatValue() * conversionData.zoom(); int edgeDistance = isHorizontal ? size.width() : size.height(); - if (value->isPercentage()) - return value->getFloatValue() / 100.f * edgeDistance; + if (value.isPercentage()) + return value.getFloatValue() / 100.f * edgeDistance; - if (value->isCalculatedPercentageWithLength()) - return value->cssCalcValue()->toCalcValue(style, rootStyle, style->effectiveZoom())->evaluate(edgeDistance); + if (value.isCalculatedPercentageWithLength()) { + Ref<CalculationValue> calculationValue { value.cssCalcValue()->createCalculationValue(conversionData) }; + return calculationValue->evaluate(edgeDistance); + } - switch (value->getValueID()) { + switch (value.getValueID()) { case CSSValueTop: ASSERT(!isHorizontal); return 0; @@ -425,18 +525,18 @@ static float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, Ren break; } - return value->computeLength<float>(style, rootStyle, zoomFactor); + return value.computeLength<float>(conversionData); } -FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* horizontal, CSSPrimitiveValue* vertical, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size) +FloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* horizontal, CSSPrimitiveValue* vertical, const CSSToLengthConversionData& conversionData, const FloatSize& size) { FloatPoint result; if (horizontal) - result.setX(positionFromValue(horizontal, style, rootStyle, size, true)); + result.setX(positionFromValue(*horizontal, conversionData, size, true)); if (vertical) - result.setY(positionFromValue(vertical, style, rootStyle, size, false)); + result.setY(positionFromValue(*vertical, conversionData, size, false)); return result; } @@ -459,7 +559,7 @@ bool CSSGradientValue::isCacheable() const return true; } -bool CSSGradientValue::knownToBeOpaque(const RenderObject*) const +bool CSSGradientValue::knownToBeOpaque(const RenderElement*) const { for (size_t i = 0; i < m_stops.size(); ++i) { if (m_stops[i].m_resolvedColor.hasAlpha()) @@ -468,7 +568,7 @@ bool CSSGradientValue::knownToBeOpaque(const RenderObject*) const return true; } -String CSSLinearGradientValue::customCssText() const +String CSSLinearGradientValue::customCSSText() const { StringBuilder result; if (m_gradientType == CSSDeprecatedLinearGradient) { @@ -494,7 +594,7 @@ String CSSLinearGradientValue::customCssText() const result.append(')'); } else { result.appendLiteral("color-stop("); - result.append(String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER))); + result.appendNumber(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)); result.appendLiteral(", "); result.append(stop.m_color->cssText()); result.append(')'); @@ -562,9 +662,11 @@ String CSSLinearGradientValue::customCssText() const const CSSGradientColorStop& stop = m_stops[i]; if (i) result.appendLiteral(", "); - result.append(stop.m_color->cssText()); + if (!stop.isMidpoint) + result.append(stop.m_color->cssText()); if (stop.m_position) { - result.append(' '); + if (!stop.isMidpoint) + result.append(' '); result.append(stop.m_position->cssText()); } } @@ -576,7 +678,7 @@ 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, CSSGradientType type) +static void endPointsFromAngle(float angleDeg, const FloatSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint, CSSGradientType type) { // Prefixed gradients use "polar coordinate" angles, rather than "bearing" angles. if (type == CSSPrefixedLinearGradient) @@ -643,11 +745,11 @@ static void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint.set(halfWidth - endX, halfHeight + endY); } -PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* renderer, const IntSize& size) +Ref<Gradient> CSSLinearGradientValue::createGradient(RenderElement& renderer, const FloatSize& size) { ASSERT(!size.isEmpty()); - RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); + CSSToLengthConversionData conversionData(&renderer.style(), renderer.document().documentElement()->renderStyle(), &renderer.view()); FloatPoint firstPoint; FloatPoint secondPoint; @@ -657,9 +759,9 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render } else { switch (m_gradientType) { case CSSDeprecatedLinearGradient: - firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_secondX || m_secondY) - secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), conversionData, size); else { if (m_firstX) secondPoint.setX(size.width() - firstPoint.x()); @@ -668,7 +770,7 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render } break; case CSSPrefixedLinearGradient: - firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_firstX) secondPoint.setX(size.width() - firstPoint.x()); if (m_firstY) @@ -687,7 +789,7 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render 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); + secondPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (m_firstX) firstPoint.setX(size.width() - secondPoint.x()); if (m_firstY) @@ -701,12 +803,12 @@ PassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* render } - RefPtr<Gradient> gradient = Gradient::create(firstPoint, secondPoint); + Ref<Gradient> gradient = Gradient::create(firstPoint, secondPoint); // Now add the stops. - addStops(gradient.get(), renderer, rootStyle, 1); + addStops(gradient, conversionData, 1); - return gradient.release(); + return gradient; } bool CSSLinearGradientValue::equals(const CSSLinearGradientValue& other) const @@ -728,20 +830,20 @@ bool CSSLinearGradientValue::equals(const CSSLinearGradientValue& other) const if (other.m_angle) return false; - bool equalXorY = false; + bool equalXandY = false; if (m_firstX && m_firstY) - equalXorY = compareCSSValuePtr(m_firstX, other.m_firstX) && compareCSSValuePtr(m_firstY, other.m_firstY); + equalXandY = 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; + equalXandY = compareCSSValuePtr(m_firstX, other.m_firstX) && !other.m_firstY; else if (m_firstY) - equalXorY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX; + equalXandY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX; else - equalXorY = !other.m_firstX || !other.m_firstY; + equalXandY = !other.m_firstX && !other.m_firstY; - return equalXorY && m_stops == other.m_stops; + return equalXandY && m_stops == other.m_stops; } -String CSSRadialGradientValue::customCssText() const +String CSSRadialGradientValue::customCSSText() const { StringBuilder result; @@ -773,7 +875,7 @@ String CSSRadialGradientValue::customCssText() const result.append(')'); } else { result.appendLiteral("color-stop("); - result.append(String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER))); + result.appendNumber(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)); result.appendLiteral(", "); result.append(stop.m_color->cssText()); result.append(')'); @@ -878,9 +980,11 @@ String CSSRadialGradientValue::customCssText() const const CSSGradientColorStop& stop = m_stops[i]; if (i) result.appendLiteral(", "); - result.append(stop.m_color->cssText()); + if (!stop.isMidpoint) + result.append(stop.m_color->cssText()); if (stop.m_position) { - result.append(' '); + if (!stop.isMidpoint) + result.append(' '); result.append(stop.m_position->cssText()); } } @@ -891,17 +995,15 @@ String CSSRadialGradientValue::customCssText() const return result.toString(); } -float CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue* radius, RenderStyle* style, RenderStyle* rootStyle, float* widthOrHeight) +float CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue& radius, const CSSToLengthConversionData& conversionData, float* widthOrHeight) { - float zoomFactor = style->effectiveZoom(); - float result = 0; - if (radius->isNumber()) // Can the radius be a percentage? - result = radius->getFloatValue() * zoomFactor; - else if (widthOrHeight && radius->isPercentage()) - result = *widthOrHeight * radius->getFloatValue() / 100; + if (radius.isNumber()) // Can the radius be a percentage? + result = radius.getFloatValue() * conversionData.zoom(); + else if (widthOrHeight && radius.isPercentage()) + result = *widthOrHeight * radius.getFloatValue() / 100; else - result = radius->computeLength<float>(style, rootStyle, zoomFactor); + result = radius.computeLength<float>(conversionData); return result; } @@ -983,19 +1085,19 @@ static inline float horizontalEllipseRadius(const FloatSize& p, float aspectRati } // FIXME: share code with the linear version -PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* renderer, const IntSize& size) +Ref<Gradient> CSSRadialGradientValue::createGradient(RenderElement& renderer, const FloatSize& size) { ASSERT(!size.isEmpty()); - RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); + CSSToLengthConversionData conversionData(&renderer.style(), renderer.document().documentElement()->renderStyle(), &renderer.view()); - FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); + FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), conversionData, size); if (!m_firstX) firstPoint.setX(size.width() / 2); if (!m_firstY) firstPoint.setY(size.height() / 2); - FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); + FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), conversionData, size); if (!m_secondX) secondPoint.setX(size.width() / 2); if (!m_secondY) @@ -1003,18 +1105,18 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render float firstRadius = 0; if (m_firstRadius) - firstRadius = resolveRadius(m_firstRadius.get(), renderer->style(), rootStyle); + firstRadius = resolveRadius(*m_firstRadius, conversionData); float secondRadius = 0; float aspectRatio = 1; // width / height. if (m_secondRadius) - secondRadius = resolveRadius(m_secondRadius.get(), renderer->style(), rootStyle); + secondRadius = resolveRadius(*m_secondRadius, conversionData); else if (m_endHorizontalSize) { float width = size.width(); float height = size.height(); - secondRadius = resolveRadius(m_endHorizontalSize.get(), renderer->style(), rootStyle, &width); + secondRadius = resolveRadius(*m_endHorizontalSize, conversionData, &width); if (m_endVerticalSize) - aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height); + aspectRatio = secondRadius / resolveRadius(*m_endVerticalSize, conversionData, &height); else aspectRatio = 1; } else { @@ -1051,10 +1153,10 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render // Horizontal switch (fill) { case ClosestSide: { - float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); - float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); + float xDist = std::min(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = std::min(secondPoint.y(), size.height() - secondPoint.y()); if (shape == Circle) { - float smaller = min(xDist, yDist); + float smaller = std::min(xDist, yDist); xDist = smaller; yDist = smaller; } @@ -1063,10 +1165,10 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render break; } case FarthestSide: { - float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); - float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); + float xDist = std::max(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = std::max(secondPoint.y(), size.height() - secondPoint.y()); if (shape == Circle) { - float larger = max(xDist, yDist); + float larger = std::max(xDist, yDist); xDist = larger; yDist = larger; } @@ -1082,8 +1184,8 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render else { // If <shape> is ellipse, the gradient-shape has the same ratio of width to height // that it would if closest-side or farthest-side were specified, as appropriate. - float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); - float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); + float xDist = std::min(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = std::min(secondPoint.y(), size.height() - secondPoint.y()); secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); aspectRatio = xDist / yDist; @@ -1099,8 +1201,8 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render else { // If <shape> is ellipse, the gradient-shape has the same ratio of width to height // that it would if closest-side or farthest-side were specified, as appropriate. - float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); - float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); + float xDist = std::max(secondPoint.x(), size.width() - secondPoint.x()); + float yDist = std::max(secondPoint.y(), size.height() - secondPoint.y()); secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); aspectRatio = xDist / yDist; @@ -1110,7 +1212,7 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render } } - RefPtr<Gradient> gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); + Ref<Gradient> gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); // addStops() only uses maxExtent for repeating gradients. float maxExtent = 0; @@ -1120,9 +1222,9 @@ PassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* render } // Now add the stops. - addStops(gradient.get(), renderer, rootStyle, maxExtent); + addStops(gradient, conversionData, maxExtent); - return gradient.release(); + return gradient; } bool CSSRadialGradientValue::equals(const CSSRadialGradientValue& other) const @@ -1140,17 +1242,17 @@ bool CSSRadialGradientValue::equals(const CSSRadialGradientValue& other) const if (m_repeating != other.m_repeating) return false; - bool equalXorY = false; + bool equalXandY = false; if (m_firstX && m_firstY) - equalXorY = compareCSSValuePtr(m_firstX, other.m_firstX) && compareCSSValuePtr(m_firstY, other.m_firstY); + equalXandY = 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; + equalXandY = compareCSSValuePtr(m_firstX, other.m_firstX) && !other.m_firstY; else if (m_firstY) - equalXorY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX; + equalXandY = compareCSSValuePtr(m_firstY, other.m_firstY) && !other.m_firstX; else - equalXorY == !other.m_firstX || !other.m_firstY; + equalXandY = !other.m_firstX && !other.m_firstY; - if (!equalXorY) + if (!equalXandY) return false; bool equalShape = true; |