1cad810f21b803229eb11403f9209855525a25d57Steve Block/* 2cad810f21b803229eb11403f9209855525a25d57Steve Block * Copyright (C) 2008 Apple Inc. All rights reserved. 3cad810f21b803229eb11403f9209855525a25d57Steve Block * 4cad810f21b803229eb11403f9209855525a25d57Steve Block * Redistribution and use in source and binary forms, with or without 5cad810f21b803229eb11403f9209855525a25d57Steve Block * modification, are permitted provided that the following conditions 6cad810f21b803229eb11403f9209855525a25d57Steve Block * are met: 7cad810f21b803229eb11403f9209855525a25d57Steve Block * 1. Redistributions of source code must retain the above copyright 8cad810f21b803229eb11403f9209855525a25d57Steve Block * notice, this list of conditions and the following disclaimer. 9cad810f21b803229eb11403f9209855525a25d57Steve Block * 2. Redistributions in binary form must reproduce the above copyright 10cad810f21b803229eb11403f9209855525a25d57Steve Block * notice, this list of conditions and the following disclaimer in the 11cad810f21b803229eb11403f9209855525a25d57Steve Block * documentation and/or other materials provided with the distribution. 12cad810f21b803229eb11403f9209855525a25d57Steve Block * 13cad810f21b803229eb11403f9209855525a25d57Steve Block * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14cad810f21b803229eb11403f9209855525a25d57Steve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15cad810f21b803229eb11403f9209855525a25d57Steve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16cad810f21b803229eb11403f9209855525a25d57Steve Block * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17cad810f21b803229eb11403f9209855525a25d57Steve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18cad810f21b803229eb11403f9209855525a25d57Steve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19cad810f21b803229eb11403f9209855525a25d57Steve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20cad810f21b803229eb11403f9209855525a25d57Steve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21cad810f21b803229eb11403f9209855525a25d57Steve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22cad810f21b803229eb11403f9209855525a25d57Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23cad810f21b803229eb11403f9209855525a25d57Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24cad810f21b803229eb11403f9209855525a25d57Steve Block */ 25cad810f21b803229eb11403f9209855525a25d57Steve Block 26cad810f21b803229eb11403f9209855525a25d57Steve Block#include "config.h" 27cad810f21b803229eb11403f9209855525a25d57Steve Block#include "CSSGradientValue.h" 28cad810f21b803229eb11403f9209855525a25d57Steve Block 29cad810f21b803229eb11403f9209855525a25d57Steve Block#include "CSSValueKeywords.h" 30cad810f21b803229eb11403f9209855525a25d57Steve Block#include "CSSStyleSelector.h" 31cad810f21b803229eb11403f9209855525a25d57Steve Block#include "GeneratedImage.h" 32cad810f21b803229eb11403f9209855525a25d57Steve Block#include "Gradient.h" 33cad810f21b803229eb11403f9209855525a25d57Steve Block#include "Image.h" 34cad810f21b803229eb11403f9209855525a25d57Steve Block#include "IntSize.h" 35cad810f21b803229eb11403f9209855525a25d57Steve Block#include "IntSizeHash.h" 36cad810f21b803229eb11403f9209855525a25d57Steve Block#include "NodeRenderStyle.h" 37cad810f21b803229eb11403f9209855525a25d57Steve Block#include "PlatformString.h" 38cad810f21b803229eb11403f9209855525a25d57Steve Block#include "RenderObject.h" 39cad810f21b803229eb11403f9209855525a25d57Steve Block 40cad810f21b803229eb11403f9209855525a25d57Steve Blockusing namespace std; 41cad810f21b803229eb11403f9209855525a25d57Steve Block 42cad810f21b803229eb11403f9209855525a25d57Steve Blocknamespace WebCore { 43cad810f21b803229eb11403f9209855525a25d57Steve Block 442fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockPassRefPtr<Image> CSSGradientValue::image(RenderObject* renderer, const IntSize& size) 45cad810f21b803229eb11403f9209855525a25d57Steve Block{ 46cad810f21b803229eb11403f9209855525a25d57Steve Block if (size.isEmpty()) 47cad810f21b803229eb11403f9209855525a25d57Steve Block return 0; 48cad810f21b803229eb11403f9209855525a25d57Steve Block 492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block bool cacheable = isCacheable(); 502fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (cacheable) { 512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!m_clients.contains(renderer)) 522fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return 0; 532fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 542fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Need to look up our size. Create a string of width*height to use as a hash key. 552fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Image* result = getImage(renderer, size); 562fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (result) 572fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return result; 582fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 592fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 60cad810f21b803229eb11403f9209855525a25d57Steve Block // We need to create an image. 61cad810f21b803229eb11403f9209855525a25d57Steve Block RefPtr<Image> newImage = GeneratedImage::create(createGradient(renderer, size), size); 622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (cacheable) 632fc2651226baac27029e38c9d6ef883fa32084dbSteve Block putImage(size, newImage); 64cad810f21b803229eb11403f9209855525a25d57Steve Block 652fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return newImage.release(); 66cad810f21b803229eb11403f9209855525a25d57Steve Block} 67cad810f21b803229eb11403f9209855525a25d57Steve Block 68cad810f21b803229eb11403f9209855525a25d57Steve Block// Should only ever be called for deprecated gradients. 69cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic inline bool compareStops(const CSSGradientColorStop& a, const CSSGradientColorStop& b) 70cad810f21b803229eb11403f9209855525a25d57Steve Block{ 71cad810f21b803229eb11403f9209855525a25d57Steve Block double aVal = a.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); 72cad810f21b803229eb11403f9209855525a25d57Steve Block double bVal = b.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER); 73cad810f21b803229eb11403f9209855525a25d57Steve Block 74cad810f21b803229eb11403f9209855525a25d57Steve Block return aVal < bVal; 75cad810f21b803229eb11403f9209855525a25d57Steve Block} 76cad810f21b803229eb11403f9209855525a25d57Steve Block 77cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid CSSGradientValue::sortStopsIfNeeded() 78cad810f21b803229eb11403f9209855525a25d57Steve Block{ 79cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(m_deprecatedType); 80cad810f21b803229eb11403f9209855525a25d57Steve Block if (!m_stopsSorted) { 81cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_stops.size()) 82cad810f21b803229eb11403f9209855525a25d57Steve Block std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); 83cad810f21b803229eb11403f9209855525a25d57Steve Block m_stopsSorted = true; 84cad810f21b803229eb11403f9209855525a25d57Steve Block } 85cad810f21b803229eb11403f9209855525a25d57Steve Block} 86cad810f21b803229eb11403f9209855525a25d57Steve Block 87cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic inline int blend(int from, int to, float progress) 88cad810f21b803229eb11403f9209855525a25d57Steve Block{ 89cad810f21b803229eb11403f9209855525a25d57Steve Block return int(from + (to - from) * progress); 90cad810f21b803229eb11403f9209855525a25d57Steve Block} 91cad810f21b803229eb11403f9209855525a25d57Steve Block 92cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic inline Color blend(const Color& from, const Color& to, float progress) 93cad810f21b803229eb11403f9209855525a25d57Steve Block{ 94cad810f21b803229eb11403f9209855525a25d57Steve Block // FIXME: when we interpolate gradients using premultiplied colors, this should also do premultiplication. 95cad810f21b803229eb11403f9209855525a25d57Steve Block return Color(blend(from.red(), to.red(), progress), 96cad810f21b803229eb11403f9209855525a25d57Steve Block blend(from.green(), to.green(), progress), 97cad810f21b803229eb11403f9209855525a25d57Steve Block blend(from.blue(), to.blue(), progress), 98cad810f21b803229eb11403f9209855525a25d57Steve Block blend(from.alpha(), to.alpha(), progress)); 99cad810f21b803229eb11403f9209855525a25d57Steve Block} 100cad810f21b803229eb11403f9209855525a25d57Steve Block 101cad810f21b803229eb11403f9209855525a25d57Steve Blockstruct GradientStop { 102cad810f21b803229eb11403f9209855525a25d57Steve Block Color color; 103cad810f21b803229eb11403f9209855525a25d57Steve Block float offset; 104cad810f21b803229eb11403f9209855525a25d57Steve Block bool specified; 105cad810f21b803229eb11403f9209855525a25d57Steve Block 106cad810f21b803229eb11403f9209855525a25d57Steve Block GradientStop() 107cad810f21b803229eb11403f9209855525a25d57Steve Block : offset(0) 108cad810f21b803229eb11403f9209855525a25d57Steve Block , specified(false) 109cad810f21b803229eb11403f9209855525a25d57Steve Block { } 110cad810f21b803229eb11403f9209855525a25d57Steve Block}; 111cad810f21b803229eb11403f9209855525a25d57Steve Block 112cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid CSSGradientValue::addStops(Gradient* gradient, RenderObject* renderer, RenderStyle* rootStyle, float maxLengthForRepeat) 113cad810f21b803229eb11403f9209855525a25d57Steve Block{ 114cad810f21b803229eb11403f9209855525a25d57Steve Block RenderStyle* style = renderer->style(); 115cad810f21b803229eb11403f9209855525a25d57Steve Block 116cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_deprecatedType) { 117cad810f21b803229eb11403f9209855525a25d57Steve Block sortStopsIfNeeded(); 118cad810f21b803229eb11403f9209855525a25d57Steve Block 119cad810f21b803229eb11403f9209855525a25d57Steve Block // We have to resolve colors. 120cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < m_stops.size(); i++) { 121cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 122cad810f21b803229eb11403f9209855525a25d57Steve Block Color color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(stop.m_color.get()); 123cad810f21b803229eb11403f9209855525a25d57Steve Block 124cad810f21b803229eb11403f9209855525a25d57Steve Block float offset; 125cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) 126cad810f21b803229eb11403f9209855525a25d57Steve Block offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; 127cad810f21b803229eb11403f9209855525a25d57Steve Block else 128cad810f21b803229eb11403f9209855525a25d57Steve Block offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); 129cad810f21b803229eb11403f9209855525a25d57Steve Block 130cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->addColorStop(offset, color); 131cad810f21b803229eb11403f9209855525a25d57Steve Block } 132cad810f21b803229eb11403f9209855525a25d57Steve Block 133cad810f21b803229eb11403f9209855525a25d57Steve Block // The back end already sorted the stops. 134cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setStopsSorted(true); 135cad810f21b803229eb11403f9209855525a25d57Steve Block return; 136cad810f21b803229eb11403f9209855525a25d57Steve Block } 137cad810f21b803229eb11403f9209855525a25d57Steve Block 138cad810f21b803229eb11403f9209855525a25d57Steve Block size_t numStops = m_stops.size(); 139cad810f21b803229eb11403f9209855525a25d57Steve Block 140cad810f21b803229eb11403f9209855525a25d57Steve Block Vector<GradientStop> stops(numStops); 141cad810f21b803229eb11403f9209855525a25d57Steve Block 142cad810f21b803229eb11403f9209855525a25d57Steve Block float gradientLength = 0; 143cad810f21b803229eb11403f9209855525a25d57Steve Block bool computedGradientLength = false; 144cad810f21b803229eb11403f9209855525a25d57Steve Block 145cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint gradientStart = gradient->p0(); 146cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint gradientEnd; 147cad810f21b803229eb11403f9209855525a25d57Steve Block if (isLinearGradient()) 148cad810f21b803229eb11403f9209855525a25d57Steve Block gradientEnd = gradient->p1(); 149cad810f21b803229eb11403f9209855525a25d57Steve Block else if (isRadialGradient()) 150cad810f21b803229eb11403f9209855525a25d57Steve Block gradientEnd = gradientStart + FloatSize(gradient->endRadius(), 0); 151cad810f21b803229eb11403f9209855525a25d57Steve Block 152cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < numStops; ++i) { 153cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 154cad810f21b803229eb11403f9209855525a25d57Steve Block 155cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(stop.m_color.get()); 156cad810f21b803229eb11403f9209855525a25d57Steve Block 157cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position) { 158cad810f21b803229eb11403f9209855525a25d57Steve Block int type = stop.m_position->primitiveType(); 159cad810f21b803229eb11403f9209855525a25d57Steve Block if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 160cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = stop.m_position->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE) / 100; 161cad810f21b803229eb11403f9209855525a25d57Steve Block else if (CSSPrimitiveValue::isUnitTypeLength(type)) { 162cad810f21b803229eb11403f9209855525a25d57Steve Block float length = stop.m_position->computeLengthFloat(style, rootStyle, style->effectiveZoom()); 163cad810f21b803229eb11403f9209855525a25d57Steve Block if (!computedGradientLength) { 164cad810f21b803229eb11403f9209855525a25d57Steve Block FloatSize gradientSize(gradientStart - gradientEnd); 165cad810f21b803229eb11403f9209855525a25d57Steve Block gradientLength = gradientSize.diagonalLength(); 166cad810f21b803229eb11403f9209855525a25d57Steve Block } 167cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = (gradientLength > 0) ? length / gradientLength : 0; 168cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 169cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT_NOT_REACHED(); 170cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = 0; 171cad810f21b803229eb11403f9209855525a25d57Steve Block } 172cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].specified = true; 173cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 174cad810f21b803229eb11403f9209855525a25d57Steve Block // If the first color-stop does not have a position, its position defaults to 0%. 175cad810f21b803229eb11403f9209855525a25d57Steve Block // If the last color-stop does not have a position, its position defaults to 100%. 176cad810f21b803229eb11403f9209855525a25d57Steve Block if (!i) { 177cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = 0; 178cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].specified = true; 179cad810f21b803229eb11403f9209855525a25d57Steve Block } else if (numStops > 1 && i == numStops - 1) { 180cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = 1; 181cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].specified = true; 182cad810f21b803229eb11403f9209855525a25d57Steve Block } 183cad810f21b803229eb11403f9209855525a25d57Steve Block } 184cad810f21b803229eb11403f9209855525a25d57Steve Block 185cad810f21b803229eb11403f9209855525a25d57Steve Block // If a color-stop has a position that is less than the specified position of any 186cad810f21b803229eb11403f9209855525a25d57Steve Block // color-stop before it in the list, its position is changed to be equal to the 187cad810f21b803229eb11403f9209855525a25d57Steve Block // largest specified position of any color-stop before it. 188cad810f21b803229eb11403f9209855525a25d57Steve Block if (stops[i].specified && i > 0) { 189cad810f21b803229eb11403f9209855525a25d57Steve Block size_t prevSpecifiedIndex; 190cad810f21b803229eb11403f9209855525a25d57Steve Block for (prevSpecifiedIndex = i - 1; prevSpecifiedIndex; --prevSpecifiedIndex) { 191cad810f21b803229eb11403f9209855525a25d57Steve Block if (stops[prevSpecifiedIndex].specified) 192cad810f21b803229eb11403f9209855525a25d57Steve Block break; 193cad810f21b803229eb11403f9209855525a25d57Steve Block } 194cad810f21b803229eb11403f9209855525a25d57Steve Block 195cad810f21b803229eb11403f9209855525a25d57Steve Block if (stops[i].offset < stops[prevSpecifiedIndex].offset) 196cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = stops[prevSpecifiedIndex].offset; 197cad810f21b803229eb11403f9209855525a25d57Steve Block } 198cad810f21b803229eb11403f9209855525a25d57Steve Block } 199cad810f21b803229eb11403f9209855525a25d57Steve Block 200cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(stops[0].specified && stops[numStops - 1].specified); 201cad810f21b803229eb11403f9209855525a25d57Steve Block 202cad810f21b803229eb11403f9209855525a25d57Steve Block // If any color-stop still does not have a position, then, for each run of adjacent 203cad810f21b803229eb11403f9209855525a25d57Steve Block // color-stops without positions, set their positions so that they are evenly spaced 204cad810f21b803229eb11403f9209855525a25d57Steve Block // between the preceding and following color-stops with positions. 205cad810f21b803229eb11403f9209855525a25d57Steve Block if (numStops > 2) { 206cad810f21b803229eb11403f9209855525a25d57Steve Block size_t unspecifiedRunStart = 0; 207cad810f21b803229eb11403f9209855525a25d57Steve Block bool inUnspecifiedRun = false; 208cad810f21b803229eb11403f9209855525a25d57Steve Block 209cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < numStops; ++i) { 210cad810f21b803229eb11403f9209855525a25d57Steve Block if (!stops[i].specified && !inUnspecifiedRun) { 211cad810f21b803229eb11403f9209855525a25d57Steve Block unspecifiedRunStart = i; 212cad810f21b803229eb11403f9209855525a25d57Steve Block inUnspecifiedRun = true; 213cad810f21b803229eb11403f9209855525a25d57Steve Block } else if (stops[i].specified && inUnspecifiedRun) { 214cad810f21b803229eb11403f9209855525a25d57Steve Block size_t unspecifiedRunEnd = i; 215cad810f21b803229eb11403f9209855525a25d57Steve Block 216cad810f21b803229eb11403f9209855525a25d57Steve Block if (unspecifiedRunStart < unspecifiedRunEnd) { 217cad810f21b803229eb11403f9209855525a25d57Steve Block float lastSpecifiedOffset = stops[unspecifiedRunStart - 1].offset; 218cad810f21b803229eb11403f9209855525a25d57Steve Block float nextSpecifiedOffset = stops[unspecifiedRunEnd].offset; 219cad810f21b803229eb11403f9209855525a25d57Steve Block float delta = (nextSpecifiedOffset - lastSpecifiedOffset) / (unspecifiedRunEnd - unspecifiedRunStart + 1); 220cad810f21b803229eb11403f9209855525a25d57Steve Block 221cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t j = unspecifiedRunStart; j < unspecifiedRunEnd; ++j) 222cad810f21b803229eb11403f9209855525a25d57Steve Block stops[j].offset = lastSpecifiedOffset + (j - unspecifiedRunStart + 1) * delta; 223cad810f21b803229eb11403f9209855525a25d57Steve Block } 224cad810f21b803229eb11403f9209855525a25d57Steve Block 225cad810f21b803229eb11403f9209855525a25d57Steve Block inUnspecifiedRun = false; 226cad810f21b803229eb11403f9209855525a25d57Steve Block } 227cad810f21b803229eb11403f9209855525a25d57Steve Block } 228cad810f21b803229eb11403f9209855525a25d57Steve Block } 229cad810f21b803229eb11403f9209855525a25d57Steve Block 230cad810f21b803229eb11403f9209855525a25d57Steve Block // If the gradient is repeating, repeat the color stops. 231cad810f21b803229eb11403f9209855525a25d57Steve Block // We can't just push this logic down into the platform-specific Gradient code, 232cad810f21b803229eb11403f9209855525a25d57Steve Block // because we have to know the extent of the gradient, and possible move the end points. 233cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_repeating && numStops > 1) { 234ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // If the difference in the positions of the first and last color-stops is 0, 235ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // the gradient defines a solid-color image with the color of the last color-stop in the rule. 236ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float gradientRange = stops[numStops - 1].offset - stops[0].offset; 237ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!gradientRange) { 238ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch stops.first().offset = 0; 239ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch stops.first().color = stops.last().color; 240ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch stops.shrink(1); 241ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch numStops = 1; 242ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } else { 243ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float maxExtent = 1; 244cad810f21b803229eb11403f9209855525a25d57Steve Block 245ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // Radial gradients may need to extend further than the endpoints, because they have 246ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // to repeat out to the corners of the box. 247ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (isRadialGradient()) { 248ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!computedGradientLength) { 249ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch FloatSize gradientSize(gradientStart - gradientEnd); 250ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch gradientLength = gradientSize.diagonalLength(); 251ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 252ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 253ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (maxLengthForRepeat > gradientLength) 254ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch maxExtent = maxLengthForRepeat / gradientLength; 255ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 256cad810f21b803229eb11403f9209855525a25d57Steve Block 257ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch size_t originalNumStops = numStops; 258ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch size_t originalFirstStopIndex = 0; 259ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 260ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // Work backwards from the first, adding stops until we get one before 0. 261ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float firstOffset = stops[0].offset; 262ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (firstOffset > 0) { 263ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float currOffset = firstOffset; 264ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch size_t srcStopOrdinal = originalNumStops - 1; 265ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 266ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch while (true) { 267ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch GradientStop newStop = stops[originalFirstStopIndex + srcStopOrdinal]; 268ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch newStop.offset = currOffset; 269ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch stops.prepend(newStop); 270ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch ++originalFirstStopIndex; 271ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (currOffset < 0) 272ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch break; 273ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 274ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (srcStopOrdinal) 275ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch currOffset -= stops[originalFirstStopIndex + srcStopOrdinal].offset - stops[originalFirstStopIndex + srcStopOrdinal - 1].offset; 276ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch srcStopOrdinal = (srcStopOrdinal + originalNumStops - 1) % originalNumStops; 277ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 278cad810f21b803229eb11403f9209855525a25d57Steve Block } 279ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 280ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // Work forwards from the end, adding stops until we get one after 1. 281ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float lastOffset = stops[stops.size() - 1].offset; 282ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (lastOffset < maxExtent) { 283ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch float currOffset = lastOffset; 2842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block size_t srcStopOrdinal = originalFirstStopIndex; 285ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 286ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch while (true) { 287ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch GradientStop newStop = stops[srcStopOrdinal]; 288ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch newStop.offset = currOffset; 289ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch stops.append(newStop); 290ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (currOffset > maxExtent) 291ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch break; 292ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (srcStopOrdinal < originalNumStops - 1) 2932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block currOffset += stops[srcStopOrdinal + 1].offset - stops[srcStopOrdinal].offset; 294ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch srcStopOrdinal = (srcStopOrdinal + 1) % originalNumStops; 295ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch } 296cad810f21b803229eb11403f9209855525a25d57Steve Block } 297cad810f21b803229eb11403f9209855525a25d57Steve Block } 298cad810f21b803229eb11403f9209855525a25d57Steve Block } 299cad810f21b803229eb11403f9209855525a25d57Steve Block 300cad810f21b803229eb11403f9209855525a25d57Steve Block numStops = stops.size(); 301cad810f21b803229eb11403f9209855525a25d57Steve Block 302cad810f21b803229eb11403f9209855525a25d57Steve Block // If the gradient goes outside the 0-1 range, normalize it by moving the endpoints, and adjusting the stops. 303cad810f21b803229eb11403f9209855525a25d57Steve Block if (numStops > 1 && (stops[0].offset < 0 || stops[numStops - 1].offset > 1)) { 304cad810f21b803229eb11403f9209855525a25d57Steve Block if (isLinearGradient()) { 305cad810f21b803229eb11403f9209855525a25d57Steve Block float firstOffset = stops[0].offset; 306cad810f21b803229eb11403f9209855525a25d57Steve Block float lastOffset = stops[numStops - 1].offset; 307cad810f21b803229eb11403f9209855525a25d57Steve Block float scale = lastOffset - firstOffset; 308cad810f21b803229eb11403f9209855525a25d57Steve Block 309cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < numStops; ++i) 310cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = (stops[i].offset - firstOffset) / scale; 311cad810f21b803229eb11403f9209855525a25d57Steve Block 312cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint p0 = gradient->p0(); 313cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint p1 = gradient->p1(); 314cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setP0(FloatPoint(p0.x() + firstOffset * (p1.x() - p0.x()), p0.y() + firstOffset * (p1.y() - p0.y()))); 315cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setP1(FloatPoint(p1.x() + (lastOffset - 1) * (p1.x() - p0.x()), p1.y() + (lastOffset - 1) * (p1.y() - p0.y()))); 316cad810f21b803229eb11403f9209855525a25d57Steve Block } else if (isRadialGradient()) { 317cad810f21b803229eb11403f9209855525a25d57Steve Block // Rather than scaling the points < 0, we truncate them, so only scale according to the largest point. 318cad810f21b803229eb11403f9209855525a25d57Steve Block float firstOffset = 0; 319cad810f21b803229eb11403f9209855525a25d57Steve Block float lastOffset = stops[numStops - 1].offset; 320cad810f21b803229eb11403f9209855525a25d57Steve Block float scale = lastOffset - firstOffset; 321cad810f21b803229eb11403f9209855525a25d57Steve Block 322cad810f21b803229eb11403f9209855525a25d57Steve Block // Reset points below 0 to the first visible color. 323cad810f21b803229eb11403f9209855525a25d57Steve Block size_t firstZeroOrGreaterIndex = numStops; 324cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < numStops; ++i) { 325cad810f21b803229eb11403f9209855525a25d57Steve Block if (stops[i].offset >= 0) { 326cad810f21b803229eb11403f9209855525a25d57Steve Block firstZeroOrGreaterIndex = i; 327cad810f21b803229eb11403f9209855525a25d57Steve Block break; 328cad810f21b803229eb11403f9209855525a25d57Steve Block } 329cad810f21b803229eb11403f9209855525a25d57Steve Block } 330cad810f21b803229eb11403f9209855525a25d57Steve Block 331cad810f21b803229eb11403f9209855525a25d57Steve Block if (firstZeroOrGreaterIndex > 0) { 332cad810f21b803229eb11403f9209855525a25d57Steve Block if (firstZeroOrGreaterIndex < numStops && stops[firstZeroOrGreaterIndex].offset > 0) { 333cad810f21b803229eb11403f9209855525a25d57Steve Block float prevOffset = stops[firstZeroOrGreaterIndex - 1].offset; 334cad810f21b803229eb11403f9209855525a25d57Steve Block float nextOffset = stops[firstZeroOrGreaterIndex].offset; 335cad810f21b803229eb11403f9209855525a25d57Steve Block 336cad810f21b803229eb11403f9209855525a25d57Steve Block float interStopProportion = -prevOffset / (nextOffset - prevOffset); 337cad810f21b803229eb11403f9209855525a25d57Steve Block Color blendedColor = blend(stops[firstZeroOrGreaterIndex - 1].color, stops[firstZeroOrGreaterIndex].color, interStopProportion); 338cad810f21b803229eb11403f9209855525a25d57Steve Block 339cad810f21b803229eb11403f9209855525a25d57Steve Block // Clamp the positions to 0 and set the color. 340cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) { 341cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = 0; 342cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].color = blendedColor; 343cad810f21b803229eb11403f9209855525a25d57Steve Block } 344cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 345cad810f21b803229eb11403f9209855525a25d57Steve Block // All stops are below 0; just clamp them. 346cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) 347cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset = 0; 348cad810f21b803229eb11403f9209855525a25d57Steve Block } 349cad810f21b803229eb11403f9209855525a25d57Steve Block } 350cad810f21b803229eb11403f9209855525a25d57Steve Block 351cad810f21b803229eb11403f9209855525a25d57Steve Block for (size_t i = 0; i < numStops; ++i) 352cad810f21b803229eb11403f9209855525a25d57Steve Block stops[i].offset /= scale; 353cad810f21b803229eb11403f9209855525a25d57Steve Block 354cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setStartRadius(gradient->startRadius() * scale); 355cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setEndRadius(gradient->endRadius() * scale); 356cad810f21b803229eb11403f9209855525a25d57Steve Block } 357cad810f21b803229eb11403f9209855525a25d57Steve Block } 358cad810f21b803229eb11403f9209855525a25d57Steve Block 359cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < numStops; i++) 360cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->addColorStop(stops[i].offset, stops[i].color); 361cad810f21b803229eb11403f9209855525a25d57Steve Block 362cad810f21b803229eb11403f9209855525a25d57Steve Block gradient->setStopsSorted(true); 363cad810f21b803229eb11403f9209855525a25d57Steve Block} 364cad810f21b803229eb11403f9209855525a25d57Steve Block 365cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic float positionFromValue(CSSPrimitiveValue* value, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size, bool isHorizontal) 366cad810f21b803229eb11403f9209855525a25d57Steve Block{ 367cad810f21b803229eb11403f9209855525a25d57Steve Block float zoomFactor = style->effectiveZoom(); 368cad810f21b803229eb11403f9209855525a25d57Steve Block 369cad810f21b803229eb11403f9209855525a25d57Steve Block switch (value->primitiveType()) { 370cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSPrimitiveValue::CSS_NUMBER: 371cad810f21b803229eb11403f9209855525a25d57Steve Block return value->getFloatValue() * zoomFactor; 372cad810f21b803229eb11403f9209855525a25d57Steve Block 373cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSPrimitiveValue::CSS_PERCENTAGE: 374cad810f21b803229eb11403f9209855525a25d57Steve Block return value->getFloatValue() / 100.f * (isHorizontal ? size.width() : size.height()); 375cad810f21b803229eb11403f9209855525a25d57Steve Block 376cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSPrimitiveValue::CSS_IDENT: 377cad810f21b803229eb11403f9209855525a25d57Steve Block switch (value->getIdent()) { 378cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueTop: 379cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(!isHorizontal); 380cad810f21b803229eb11403f9209855525a25d57Steve Block return 0; 381cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueLeft: 382cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(isHorizontal); 383cad810f21b803229eb11403f9209855525a25d57Steve Block return 0; 384cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueBottom: 385cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(!isHorizontal); 386cad810f21b803229eb11403f9209855525a25d57Steve Block return size.height(); 387cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueRight: 388cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(isHorizontal); 389cad810f21b803229eb11403f9209855525a25d57Steve Block return size.width(); 390cad810f21b803229eb11403f9209855525a25d57Steve Block } 391cad810f21b803229eb11403f9209855525a25d57Steve Block 392cad810f21b803229eb11403f9209855525a25d57Steve Block default: 393cad810f21b803229eb11403f9209855525a25d57Steve Block return value->computeLengthFloat(style, rootStyle, zoomFactor); 394cad810f21b803229eb11403f9209855525a25d57Steve Block } 395cad810f21b803229eb11403f9209855525a25d57Steve Block} 396cad810f21b803229eb11403f9209855525a25d57Steve Block 397cad810f21b803229eb11403f9209855525a25d57Steve BlockFloatPoint CSSGradientValue::computeEndPoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, RenderStyle* style, RenderStyle* rootStyle, const IntSize& size) 398cad810f21b803229eb11403f9209855525a25d57Steve Block{ 399cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint result; 400cad810f21b803229eb11403f9209855525a25d57Steve Block 401cad810f21b803229eb11403f9209855525a25d57Steve Block if (first) 402cad810f21b803229eb11403f9209855525a25d57Steve Block result.setX(positionFromValue(first, style, rootStyle, size, true)); 403cad810f21b803229eb11403f9209855525a25d57Steve Block 404cad810f21b803229eb11403f9209855525a25d57Steve Block if (second) 405cad810f21b803229eb11403f9209855525a25d57Steve Block result.setY(positionFromValue(second, style, rootStyle, size, false)); 406cad810f21b803229eb11403f9209855525a25d57Steve Block 407cad810f21b803229eb11403f9209855525a25d57Steve Block return result; 408cad810f21b803229eb11403f9209855525a25d57Steve Block} 409cad810f21b803229eb11403f9209855525a25d57Steve Block 4102fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockbool CSSGradientValue::isCacheable() const 4112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{ 4122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block for (size_t i = 0; i < m_stops.size(); ++i) { 4132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block const CSSGradientColorStop& stop = m_stops[i]; 4142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!stop.m_position) 4152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block continue; 4162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 4172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block unsigned short unitType = stop.m_position->primitiveType(); 4182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (unitType == CSSPrimitiveValue::CSS_EMS || unitType == CSSPrimitiveValue::CSS_EXS || unitType == CSSPrimitiveValue::CSS_REMS) 4192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return false; 4202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 4212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 4222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return true; 4232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block} 4242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 425cad810f21b803229eb11403f9209855525a25d57Steve BlockString CSSLinearGradientValue::cssText() const 426cad810f21b803229eb11403f9209855525a25d57Steve Block{ 427cad810f21b803229eb11403f9209855525a25d57Steve Block String result; 428cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_deprecatedType) { 429cad810f21b803229eb11403f9209855525a25d57Steve Block result = "-webkit-gradient(linear, "; 430cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText() + " "; 431cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstY->cssText() + ", "; 432cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_secondX->cssText() + " "; 433cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_secondY->cssText(); 434cad810f21b803229eb11403f9209855525a25d57Steve Block 435cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < m_stops.size(); i++) { 436cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 437cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 438cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) 439cad810f21b803229eb11403f9209855525a25d57Steve Block result += "from(" + stop.m_color->cssText() + ")"; 440cad810f21b803229eb11403f9209855525a25d57Steve Block else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) 441cad810f21b803229eb11403f9209855525a25d57Steve Block result += "to(" + stop.m_color->cssText() + ")"; 442cad810f21b803229eb11403f9209855525a25d57Steve Block else 443cad810f21b803229eb11403f9209855525a25d57Steve Block result += "color-stop(" + String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)) + ", " + stop.m_color->cssText() + ")"; 444cad810f21b803229eb11403f9209855525a25d57Steve Block } 445cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 446cad810f21b803229eb11403f9209855525a25d57Steve Block result = m_repeating ? "-webkit-repeating-linear-gradient(" : "-webkit-linear-gradient("; 447cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_angle) 448cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_angle->cssText(); 449cad810f21b803229eb11403f9209855525a25d57Steve Block else { 450cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstX && m_firstY) 451cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText() + " " + m_firstY->cssText(); 452cad810f21b803229eb11403f9209855525a25d57Steve Block else if (m_firstX || m_firstY) { 453cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstX) 454cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText(); 455cad810f21b803229eb11403f9209855525a25d57Steve Block 456cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstY) 457cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstY->cssText(); 458cad810f21b803229eb11403f9209855525a25d57Steve Block } 459cad810f21b803229eb11403f9209855525a25d57Steve Block } 460cad810f21b803229eb11403f9209855525a25d57Steve Block 461cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < m_stops.size(); i++) { 462cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 463cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 464cad810f21b803229eb11403f9209855525a25d57Steve Block result += stop.m_color->cssText(); 465cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position) 466cad810f21b803229eb11403f9209855525a25d57Steve Block result += " " + stop.m_position->cssText(); 467cad810f21b803229eb11403f9209855525a25d57Steve Block } 468cad810f21b803229eb11403f9209855525a25d57Steve Block } 469cad810f21b803229eb11403f9209855525a25d57Steve Block 470cad810f21b803229eb11403f9209855525a25d57Steve Block result += ")"; 471cad810f21b803229eb11403f9209855525a25d57Steve Block return result; 472cad810f21b803229eb11403f9209855525a25d57Steve Block} 473cad810f21b803229eb11403f9209855525a25d57Steve Block 474cad810f21b803229eb11403f9209855525a25d57Steve Block// Compute the endpoints so that a gradient of the given angle covers a box of the given size. 475cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic void endPointsFromAngle(float angleDeg, const IntSize& size, FloatPoint& firstPoint, FloatPoint& secondPoint) 476cad810f21b803229eb11403f9209855525a25d57Steve Block{ 477cad810f21b803229eb11403f9209855525a25d57Steve Block angleDeg = fmodf(angleDeg, 360); 478cad810f21b803229eb11403f9209855525a25d57Steve Block if (angleDeg < 0) 479cad810f21b803229eb11403f9209855525a25d57Steve Block angleDeg += 360; 480cad810f21b803229eb11403f9209855525a25d57Steve Block 481cad810f21b803229eb11403f9209855525a25d57Steve Block if (!angleDeg) { 482cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.set(0, 0); 483cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.set(size.width(), 0); 484cad810f21b803229eb11403f9209855525a25d57Steve Block return; 485cad810f21b803229eb11403f9209855525a25d57Steve Block } 486cad810f21b803229eb11403f9209855525a25d57Steve Block 487cad810f21b803229eb11403f9209855525a25d57Steve Block if (angleDeg == 90) { 488cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.set(0, size.height()); 489cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.set(0, 0); 490cad810f21b803229eb11403f9209855525a25d57Steve Block return; 491cad810f21b803229eb11403f9209855525a25d57Steve Block } 492cad810f21b803229eb11403f9209855525a25d57Steve Block 493cad810f21b803229eb11403f9209855525a25d57Steve Block if (angleDeg == 180) { 494cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.set(size.width(), 0); 495cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.set(0, 0); 496cad810f21b803229eb11403f9209855525a25d57Steve Block return; 497cad810f21b803229eb11403f9209855525a25d57Steve Block } 498cad810f21b803229eb11403f9209855525a25d57Steve Block 499cad810f21b803229eb11403f9209855525a25d57Steve Block float slope = tan(deg2rad(angleDeg)); 500cad810f21b803229eb11403f9209855525a25d57Steve Block 501cad810f21b803229eb11403f9209855525a25d57Steve Block // We find the endpoint by computing the intersection of the line formed by the slope, 502cad810f21b803229eb11403f9209855525a25d57Steve Block // and a line perpendicular to it that intersects the corner. 503cad810f21b803229eb11403f9209855525a25d57Steve Block float perpendicularSlope = -1 / slope; 504cad810f21b803229eb11403f9209855525a25d57Steve Block 505cad810f21b803229eb11403f9209855525a25d57Steve Block // Compute start corner relative to center. 506cad810f21b803229eb11403f9209855525a25d57Steve Block float halfHeight = size.height() / 2; 507cad810f21b803229eb11403f9209855525a25d57Steve Block float halfWidth = size.width() / 2; 508cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint endCorner; 509cad810f21b803229eb11403f9209855525a25d57Steve Block if (angleDeg < 90) 510cad810f21b803229eb11403f9209855525a25d57Steve Block endCorner.set(halfWidth, halfHeight); 511cad810f21b803229eb11403f9209855525a25d57Steve Block else if (angleDeg < 180) 512cad810f21b803229eb11403f9209855525a25d57Steve Block endCorner.set(-halfWidth, halfHeight); 513cad810f21b803229eb11403f9209855525a25d57Steve Block else if (angleDeg < 270) 514cad810f21b803229eb11403f9209855525a25d57Steve Block endCorner.set(-halfWidth, -halfHeight); 515cad810f21b803229eb11403f9209855525a25d57Steve Block else 516cad810f21b803229eb11403f9209855525a25d57Steve Block endCorner.set(halfWidth, -halfHeight); 517cad810f21b803229eb11403f9209855525a25d57Steve Block 518cad810f21b803229eb11403f9209855525a25d57Steve Block // Compute c (of y = mx + c) using the corner point. 519cad810f21b803229eb11403f9209855525a25d57Steve Block float c = endCorner.y() - perpendicularSlope * endCorner.x(); 520cad810f21b803229eb11403f9209855525a25d57Steve Block float endX = c / (slope - perpendicularSlope); 521cad810f21b803229eb11403f9209855525a25d57Steve Block float endY = perpendicularSlope * endX + c; 522cad810f21b803229eb11403f9209855525a25d57Steve Block 523cad810f21b803229eb11403f9209855525a25d57Steve Block // We computed the end point, so set the second point, flipping the Y to account for angles going anticlockwise. 524cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.set(halfWidth + endX, size.height() - (halfHeight + endY)); 525cad810f21b803229eb11403f9209855525a25d57Steve Block // Reflect around the center for the start point. 526cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.set(size.width() - secondPoint.x(), size.height() - secondPoint.y()); 527cad810f21b803229eb11403f9209855525a25d57Steve Block} 528cad810f21b803229eb11403f9209855525a25d57Steve Block 529cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<Gradient> CSSLinearGradientValue::createGradient(RenderObject* renderer, const IntSize& size) 530cad810f21b803229eb11403f9209855525a25d57Steve Block{ 531cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(!size.isEmpty()); 532cad810f21b803229eb11403f9209855525a25d57Steve Block 533cad810f21b803229eb11403f9209855525a25d57Steve Block RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); 534cad810f21b803229eb11403f9209855525a25d57Steve Block 535cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint firstPoint; 536cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint secondPoint; 537cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_angle) { 538cad810f21b803229eb11403f9209855525a25d57Steve Block float angle = m_angle->getFloatValue(CSSPrimitiveValue::CSS_DEG); 539cad810f21b803229eb11403f9209855525a25d57Steve Block endPointsFromAngle(angle, size, firstPoint, secondPoint); 540cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 541cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); 542cad810f21b803229eb11403f9209855525a25d57Steve Block 543cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_secondX || m_secondY) 544cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); 545cad810f21b803229eb11403f9209855525a25d57Steve Block else { 546cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstX) 547cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.setX(size.width() - firstPoint.x()); 548cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstY) 549cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.setY(size.height() - firstPoint.y()); 550cad810f21b803229eb11403f9209855525a25d57Steve Block } 551cad810f21b803229eb11403f9209855525a25d57Steve Block } 552cad810f21b803229eb11403f9209855525a25d57Steve Block 553cad810f21b803229eb11403f9209855525a25d57Steve Block RefPtr<Gradient> gradient = Gradient::create(firstPoint, secondPoint); 554cad810f21b803229eb11403f9209855525a25d57Steve Block 555cad810f21b803229eb11403f9209855525a25d57Steve Block // Now add the stops. 556cad810f21b803229eb11403f9209855525a25d57Steve Block addStops(gradient.get(), renderer, rootStyle, 1); 557cad810f21b803229eb11403f9209855525a25d57Steve Block 558cad810f21b803229eb11403f9209855525a25d57Steve Block return gradient.release(); 559cad810f21b803229eb11403f9209855525a25d57Steve Block} 560cad810f21b803229eb11403f9209855525a25d57Steve Block 561cad810f21b803229eb11403f9209855525a25d57Steve BlockString CSSRadialGradientValue::cssText() const 562cad810f21b803229eb11403f9209855525a25d57Steve Block{ 563cad810f21b803229eb11403f9209855525a25d57Steve Block String result; 564cad810f21b803229eb11403f9209855525a25d57Steve Block 565cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_deprecatedType) { 566cad810f21b803229eb11403f9209855525a25d57Steve Block result = "-webkit-gradient(radial, "; 567cad810f21b803229eb11403f9209855525a25d57Steve Block 568cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText() + " "; 569cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstY->cssText() + ", "; 570cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstRadius->cssText() + ", "; 571cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_secondX->cssText() + " "; 572cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_secondY->cssText(); 573cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 574cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_secondRadius->cssText(); 575cad810f21b803229eb11403f9209855525a25d57Steve Block 576cad810f21b803229eb11403f9209855525a25d57Steve Block // FIXME: share? 577cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < m_stops.size(); i++) { 578cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 579cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 580cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 0) 581cad810f21b803229eb11403f9209855525a25d57Steve Block result += "from(" + stop.m_color->cssText() + ")"; 582cad810f21b803229eb11403f9209855525a25d57Steve Block else if (stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER) == 1) 583cad810f21b803229eb11403f9209855525a25d57Steve Block result += "to(" + stop.m_color->cssText() + ")"; 584cad810f21b803229eb11403f9209855525a25d57Steve Block else 585cad810f21b803229eb11403f9209855525a25d57Steve Block result += "color-stop(" + String::number(stop.m_position->getDoubleValue(CSSPrimitiveValue::CSS_NUMBER)) + ", " + stop.m_color->cssText() + ")"; 586cad810f21b803229eb11403f9209855525a25d57Steve Block } 587cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 588cad810f21b803229eb11403f9209855525a25d57Steve Block 589cad810f21b803229eb11403f9209855525a25d57Steve Block result = m_repeating ? "-webkit-repeating-radial-gradient(" : "-webkit-radial-gradient("; 590cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstX && m_firstY) { 591cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText() + " " + m_firstY->cssText(); 592cad810f21b803229eb11403f9209855525a25d57Steve Block } else if (m_firstX) 593cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstX->cssText(); 594cad810f21b803229eb11403f9209855525a25d57Steve Block else if (m_firstY) 595cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_firstY->cssText(); 596cad810f21b803229eb11403f9209855525a25d57Steve Block else 597cad810f21b803229eb11403f9209855525a25d57Steve Block result += "center"; 598cad810f21b803229eb11403f9209855525a25d57Steve Block 599cad810f21b803229eb11403f9209855525a25d57Steve Block 600cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_shape || m_sizingBehavior) { 601cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 602cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_shape) 603cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_shape->cssText() + " "; 604cad810f21b803229eb11403f9209855525a25d57Steve Block else 605cad810f21b803229eb11403f9209855525a25d57Steve Block result += "ellipse "; 606cad810f21b803229eb11403f9209855525a25d57Steve Block 607cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_sizingBehavior) 608cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_sizingBehavior->cssText(); 609cad810f21b803229eb11403f9209855525a25d57Steve Block else 610cad810f21b803229eb11403f9209855525a25d57Steve Block result += "cover"; 611cad810f21b803229eb11403f9209855525a25d57Steve Block 612cad810f21b803229eb11403f9209855525a25d57Steve Block } else if (m_endHorizontalSize && m_endVerticalSize) { 613cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 614cad810f21b803229eb11403f9209855525a25d57Steve Block result += m_endHorizontalSize->cssText() + " " + m_endVerticalSize->cssText(); 615cad810f21b803229eb11403f9209855525a25d57Steve Block } 616cad810f21b803229eb11403f9209855525a25d57Steve Block 617cad810f21b803229eb11403f9209855525a25d57Steve Block for (unsigned i = 0; i < m_stops.size(); i++) { 618cad810f21b803229eb11403f9209855525a25d57Steve Block const CSSGradientColorStop& stop = m_stops[i]; 619cad810f21b803229eb11403f9209855525a25d57Steve Block result += ", "; 620cad810f21b803229eb11403f9209855525a25d57Steve Block result += stop.m_color->cssText(); 621cad810f21b803229eb11403f9209855525a25d57Steve Block if (stop.m_position) 622cad810f21b803229eb11403f9209855525a25d57Steve Block result += " " + stop.m_position->cssText(); 623cad810f21b803229eb11403f9209855525a25d57Steve Block } 624cad810f21b803229eb11403f9209855525a25d57Steve Block } 625cad810f21b803229eb11403f9209855525a25d57Steve Block 626cad810f21b803229eb11403f9209855525a25d57Steve Block result += ")"; 627cad810f21b803229eb11403f9209855525a25d57Steve Block return result; 628cad810f21b803229eb11403f9209855525a25d57Steve Block} 629cad810f21b803229eb11403f9209855525a25d57Steve Block 630cad810f21b803229eb11403f9209855525a25d57Steve Blockfloat CSSRadialGradientValue::resolveRadius(CSSPrimitiveValue* radius, RenderStyle* style, RenderStyle* rootStyle, float* widthOrHeight) 631cad810f21b803229eb11403f9209855525a25d57Steve Block{ 632cad810f21b803229eb11403f9209855525a25d57Steve Block float zoomFactor = style->effectiveZoom(); 633cad810f21b803229eb11403f9209855525a25d57Steve Block 634cad810f21b803229eb11403f9209855525a25d57Steve Block float result = 0; 635cad810f21b803229eb11403f9209855525a25d57Steve Block if (radius->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // Can the radius be a percentage? 636cad810f21b803229eb11403f9209855525a25d57Steve Block result = radius->getFloatValue() * zoomFactor; 637cad810f21b803229eb11403f9209855525a25d57Steve Block else if (widthOrHeight && radius->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) 638cad810f21b803229eb11403f9209855525a25d57Steve Block result = *widthOrHeight * radius->getFloatValue() / 100; 639cad810f21b803229eb11403f9209855525a25d57Steve Block else 640cad810f21b803229eb11403f9209855525a25d57Steve Block result = radius->computeLengthFloat(style, rootStyle, zoomFactor); 641cad810f21b803229eb11403f9209855525a25d57Steve Block 642cad810f21b803229eb11403f9209855525a25d57Steve Block return result; 643cad810f21b803229eb11403f9209855525a25d57Steve Block} 644cad810f21b803229eb11403f9209855525a25d57Steve Block 645cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic float distanceToClosestCorner(const FloatPoint& p, const FloatSize& size, FloatPoint& corner) 646cad810f21b803229eb11403f9209855525a25d57Steve Block{ 647cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint topLeft; 648cad810f21b803229eb11403f9209855525a25d57Steve Block float topLeftDistance = FloatSize(p - topLeft).diagonalLength(); 649cad810f21b803229eb11403f9209855525a25d57Steve Block 650cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint topRight(size.width(), 0); 651cad810f21b803229eb11403f9209855525a25d57Steve Block float topRightDistance = FloatSize(p - topRight).diagonalLength(); 652cad810f21b803229eb11403f9209855525a25d57Steve Block 653cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint bottomLeft(0, size.height()); 654cad810f21b803229eb11403f9209855525a25d57Steve Block float bottomLeftDistance = FloatSize(p - bottomLeft).diagonalLength(); 655cad810f21b803229eb11403f9209855525a25d57Steve Block 656cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint bottomRight(size.width(), size.height()); 657cad810f21b803229eb11403f9209855525a25d57Steve Block float bottomRightDistance = FloatSize(p - bottomRight).diagonalLength(); 658cad810f21b803229eb11403f9209855525a25d57Steve Block 659cad810f21b803229eb11403f9209855525a25d57Steve Block corner = topLeft; 660cad810f21b803229eb11403f9209855525a25d57Steve Block float minDistance = topLeftDistance; 661cad810f21b803229eb11403f9209855525a25d57Steve Block if (topRightDistance < minDistance) { 662cad810f21b803229eb11403f9209855525a25d57Steve Block minDistance = topRightDistance; 663cad810f21b803229eb11403f9209855525a25d57Steve Block corner = topRight; 664cad810f21b803229eb11403f9209855525a25d57Steve Block } 665cad810f21b803229eb11403f9209855525a25d57Steve Block 666cad810f21b803229eb11403f9209855525a25d57Steve Block if (bottomLeftDistance < minDistance) { 667cad810f21b803229eb11403f9209855525a25d57Steve Block minDistance = bottomLeftDistance; 668cad810f21b803229eb11403f9209855525a25d57Steve Block corner = bottomLeft; 669cad810f21b803229eb11403f9209855525a25d57Steve Block } 670cad810f21b803229eb11403f9209855525a25d57Steve Block 671cad810f21b803229eb11403f9209855525a25d57Steve Block if (bottomRightDistance < minDistance) { 672cad810f21b803229eb11403f9209855525a25d57Steve Block minDistance = bottomRightDistance; 673cad810f21b803229eb11403f9209855525a25d57Steve Block corner = bottomRight; 674cad810f21b803229eb11403f9209855525a25d57Steve Block } 675cad810f21b803229eb11403f9209855525a25d57Steve Block return minDistance; 676cad810f21b803229eb11403f9209855525a25d57Steve Block} 677cad810f21b803229eb11403f9209855525a25d57Steve Block 678cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic float distanceToFarthestCorner(const FloatPoint& p, const FloatSize& size, FloatPoint& corner) 679cad810f21b803229eb11403f9209855525a25d57Steve Block{ 680cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint topLeft; 681cad810f21b803229eb11403f9209855525a25d57Steve Block float topLeftDistance = FloatSize(p - topLeft).diagonalLength(); 682cad810f21b803229eb11403f9209855525a25d57Steve Block 683cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint topRight(size.width(), 0); 684cad810f21b803229eb11403f9209855525a25d57Steve Block float topRightDistance = FloatSize(p - topRight).diagonalLength(); 685cad810f21b803229eb11403f9209855525a25d57Steve Block 686cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint bottomLeft(0, size.height()); 687cad810f21b803229eb11403f9209855525a25d57Steve Block float bottomLeftDistance = FloatSize(p - bottomLeft).diagonalLength(); 688cad810f21b803229eb11403f9209855525a25d57Steve Block 689cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint bottomRight(size.width(), size.height()); 690cad810f21b803229eb11403f9209855525a25d57Steve Block float bottomRightDistance = FloatSize(p - bottomRight).diagonalLength(); 691cad810f21b803229eb11403f9209855525a25d57Steve Block 692cad810f21b803229eb11403f9209855525a25d57Steve Block corner = topLeft; 693cad810f21b803229eb11403f9209855525a25d57Steve Block float maxDistance = topLeftDistance; 694cad810f21b803229eb11403f9209855525a25d57Steve Block if (topRightDistance > maxDistance) { 695cad810f21b803229eb11403f9209855525a25d57Steve Block maxDistance = topRightDistance; 696cad810f21b803229eb11403f9209855525a25d57Steve Block corner = topRight; 697cad810f21b803229eb11403f9209855525a25d57Steve Block } 698cad810f21b803229eb11403f9209855525a25d57Steve Block 699cad810f21b803229eb11403f9209855525a25d57Steve Block if (bottomLeftDistance > maxDistance) { 700cad810f21b803229eb11403f9209855525a25d57Steve Block maxDistance = bottomLeftDistance; 701cad810f21b803229eb11403f9209855525a25d57Steve Block corner = bottomLeft; 702cad810f21b803229eb11403f9209855525a25d57Steve Block } 703cad810f21b803229eb11403f9209855525a25d57Steve Block 704cad810f21b803229eb11403f9209855525a25d57Steve Block if (bottomRightDistance > maxDistance) { 705cad810f21b803229eb11403f9209855525a25d57Steve Block maxDistance = bottomRightDistance; 706cad810f21b803229eb11403f9209855525a25d57Steve Block corner = bottomRight; 707cad810f21b803229eb11403f9209855525a25d57Steve Block } 708cad810f21b803229eb11403f9209855525a25d57Steve Block return maxDistance; 709cad810f21b803229eb11403f9209855525a25d57Steve Block} 710cad810f21b803229eb11403f9209855525a25d57Steve Block 711cad810f21b803229eb11403f9209855525a25d57Steve Block// Compute horizontal radius of ellipse with center at 0,0 which passes through p, and has 712cad810f21b803229eb11403f9209855525a25d57Steve Block// width/height given by aspectRatio. 713cad810f21b803229eb11403f9209855525a25d57Steve Blockstatic inline float horizontalEllipseRadius(const FloatSize& p, float aspectRatio) 714cad810f21b803229eb11403f9209855525a25d57Steve Block{ 715cad810f21b803229eb11403f9209855525a25d57Steve Block // x^2/a^2 + y^2/b^2 = 1 716cad810f21b803229eb11403f9209855525a25d57Steve Block // a/b = aspectRatio, b = a/aspectRatio 717cad810f21b803229eb11403f9209855525a25d57Steve Block // a = sqrt(x^2 + y^2/(1/r^2)) 718cad810f21b803229eb11403f9209855525a25d57Steve Block return sqrtf(p.width() * p.width() + (p.height() * p.height()) / (1 / (aspectRatio * aspectRatio))); 719cad810f21b803229eb11403f9209855525a25d57Steve Block} 720cad810f21b803229eb11403f9209855525a25d57Steve Block 721cad810f21b803229eb11403f9209855525a25d57Steve Block// FIXME: share code with the linear version 722cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<Gradient> CSSRadialGradientValue::createGradient(RenderObject* renderer, const IntSize& size) 723cad810f21b803229eb11403f9209855525a25d57Steve Block{ 724cad810f21b803229eb11403f9209855525a25d57Steve Block ASSERT(!size.isEmpty()); 725cad810f21b803229eb11403f9209855525a25d57Steve Block 726cad810f21b803229eb11403f9209855525a25d57Steve Block RenderStyle* rootStyle = renderer->document()->documentElement()->renderStyle(); 727cad810f21b803229eb11403f9209855525a25d57Steve Block 728cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint firstPoint = computeEndPoint(m_firstX.get(), m_firstY.get(), renderer->style(), rootStyle, size); 729cad810f21b803229eb11403f9209855525a25d57Steve Block if (!m_firstX) 730cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.setX(size.width() / 2); 731cad810f21b803229eb11403f9209855525a25d57Steve Block if (!m_firstY) 732cad810f21b803229eb11403f9209855525a25d57Steve Block firstPoint.setY(size.height() / 2); 733cad810f21b803229eb11403f9209855525a25d57Steve Block 734cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint secondPoint = computeEndPoint(m_secondX.get(), m_secondY.get(), renderer->style(), rootStyle, size); 735cad810f21b803229eb11403f9209855525a25d57Steve Block if (!m_secondX) 736cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.setX(size.width() / 2); 737cad810f21b803229eb11403f9209855525a25d57Steve Block if (!m_secondY) 738cad810f21b803229eb11403f9209855525a25d57Steve Block secondPoint.setY(size.height() / 2); 739cad810f21b803229eb11403f9209855525a25d57Steve Block 740cad810f21b803229eb11403f9209855525a25d57Steve Block float firstRadius = 0; 741cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_firstRadius) 742cad810f21b803229eb11403f9209855525a25d57Steve Block firstRadius = resolveRadius(m_firstRadius.get(), renderer->style(), rootStyle); 743cad810f21b803229eb11403f9209855525a25d57Steve Block 744cad810f21b803229eb11403f9209855525a25d57Steve Block float secondRadius = 0; 745cad810f21b803229eb11403f9209855525a25d57Steve Block float aspectRatio = 1; // width / height. 746cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_secondRadius) 747cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = resolveRadius(m_secondRadius.get(), renderer->style(), rootStyle); 748cad810f21b803229eb11403f9209855525a25d57Steve Block else if (m_endHorizontalSize || m_endVerticalSize) { 749cad810f21b803229eb11403f9209855525a25d57Steve Block float width = size.width(); 750cad810f21b803229eb11403f9209855525a25d57Steve Block float height = size.height(); 751cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = resolveRadius(m_endHorizontalSize.get(), renderer->style(), rootStyle, &width); 752cad810f21b803229eb11403f9209855525a25d57Steve Block aspectRatio = secondRadius / resolveRadius(m_endVerticalSize.get(), renderer->style(), rootStyle, &height); 753cad810f21b803229eb11403f9209855525a25d57Steve Block } else { 754cad810f21b803229eb11403f9209855525a25d57Steve Block enum GradientShape { Circle, Ellipse }; 755cad810f21b803229eb11403f9209855525a25d57Steve Block GradientShape shape = Ellipse; 756cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_shape && m_shape->primitiveType() == CSSPrimitiveValue::CSS_IDENT && m_shape->getIdent() == CSSValueCircle) 757cad810f21b803229eb11403f9209855525a25d57Steve Block shape = Circle; 758cad810f21b803229eb11403f9209855525a25d57Steve Block 759cad810f21b803229eb11403f9209855525a25d57Steve Block enum GradientFill { ClosestSide, ClosestCorner, FarthestSide, FarthestCorner }; 760cad810f21b803229eb11403f9209855525a25d57Steve Block GradientFill fill = FarthestCorner; 761cad810f21b803229eb11403f9209855525a25d57Steve Block 762cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_sizingBehavior && m_sizingBehavior->primitiveType() == CSSPrimitiveValue::CSS_IDENT) { 763cad810f21b803229eb11403f9209855525a25d57Steve Block switch (m_sizingBehavior->getIdent()) { 764cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueContain: 765cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueClosestSide: 766cad810f21b803229eb11403f9209855525a25d57Steve Block fill = ClosestSide; 767cad810f21b803229eb11403f9209855525a25d57Steve Block break; 768cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueClosestCorner: 769cad810f21b803229eb11403f9209855525a25d57Steve Block fill = ClosestCorner; 770cad810f21b803229eb11403f9209855525a25d57Steve Block break; 771cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueFarthestSide: 772cad810f21b803229eb11403f9209855525a25d57Steve Block fill = FarthestSide; 773cad810f21b803229eb11403f9209855525a25d57Steve Block break; 774cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueCover: 775cad810f21b803229eb11403f9209855525a25d57Steve Block case CSSValueFarthestCorner: 776cad810f21b803229eb11403f9209855525a25d57Steve Block fill = FarthestCorner; 777cad810f21b803229eb11403f9209855525a25d57Steve Block break; 778cad810f21b803229eb11403f9209855525a25d57Steve Block } 779cad810f21b803229eb11403f9209855525a25d57Steve Block } 780cad810f21b803229eb11403f9209855525a25d57Steve Block 781cad810f21b803229eb11403f9209855525a25d57Steve Block // Now compute the end radii based on the second point, shape and fill. 782cad810f21b803229eb11403f9209855525a25d57Steve Block 783cad810f21b803229eb11403f9209855525a25d57Steve Block // Horizontal 784cad810f21b803229eb11403f9209855525a25d57Steve Block switch (fill) { 785cad810f21b803229eb11403f9209855525a25d57Steve Block case ClosestSide: { 786cad810f21b803229eb11403f9209855525a25d57Steve Block float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); 787cad810f21b803229eb11403f9209855525a25d57Steve Block float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); 788cad810f21b803229eb11403f9209855525a25d57Steve Block if (shape == Circle) { 789cad810f21b803229eb11403f9209855525a25d57Steve Block float smaller = min(xDist, yDist); 790cad810f21b803229eb11403f9209855525a25d57Steve Block xDist = smaller; 791cad810f21b803229eb11403f9209855525a25d57Steve Block yDist = smaller; 792cad810f21b803229eb11403f9209855525a25d57Steve Block } 793cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = xDist; 794cad810f21b803229eb11403f9209855525a25d57Steve Block aspectRatio = xDist / yDist; 795cad810f21b803229eb11403f9209855525a25d57Steve Block break; 796cad810f21b803229eb11403f9209855525a25d57Steve Block } 797cad810f21b803229eb11403f9209855525a25d57Steve Block case FarthestSide: { 798cad810f21b803229eb11403f9209855525a25d57Steve Block float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); 799cad810f21b803229eb11403f9209855525a25d57Steve Block float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); 800cad810f21b803229eb11403f9209855525a25d57Steve Block if (shape == Circle) { 801cad810f21b803229eb11403f9209855525a25d57Steve Block float larger = max(xDist, yDist); 802cad810f21b803229eb11403f9209855525a25d57Steve Block xDist = larger; 803cad810f21b803229eb11403f9209855525a25d57Steve Block yDist = larger; 804cad810f21b803229eb11403f9209855525a25d57Steve Block } 805cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = xDist; 806cad810f21b803229eb11403f9209855525a25d57Steve Block aspectRatio = xDist / yDist; 807cad810f21b803229eb11403f9209855525a25d57Steve Block break; 808cad810f21b803229eb11403f9209855525a25d57Steve Block } 809cad810f21b803229eb11403f9209855525a25d57Steve Block case ClosestCorner: { 810cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint corner; 811cad810f21b803229eb11403f9209855525a25d57Steve Block float distance = distanceToClosestCorner(secondPoint, size, corner); 812cad810f21b803229eb11403f9209855525a25d57Steve Block if (shape == Circle) 813cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = distance; 814cad810f21b803229eb11403f9209855525a25d57Steve Block else { 815cad810f21b803229eb11403f9209855525a25d57Steve Block // If <shape> is ellipse, the gradient-shape has the same ratio of width to height 816cad810f21b803229eb11403f9209855525a25d57Steve Block // that it would if closest-side or farthest-side were specified, as appropriate. 817cad810f21b803229eb11403f9209855525a25d57Steve Block float xDist = min(secondPoint.x(), size.width() - secondPoint.x()); 818cad810f21b803229eb11403f9209855525a25d57Steve Block float yDist = min(secondPoint.y(), size.height() - secondPoint.y()); 819cad810f21b803229eb11403f9209855525a25d57Steve Block 820cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); 821cad810f21b803229eb11403f9209855525a25d57Steve Block aspectRatio = xDist / yDist; 822cad810f21b803229eb11403f9209855525a25d57Steve Block } 823cad810f21b803229eb11403f9209855525a25d57Steve Block break; 824cad810f21b803229eb11403f9209855525a25d57Steve Block } 825cad810f21b803229eb11403f9209855525a25d57Steve Block 826cad810f21b803229eb11403f9209855525a25d57Steve Block case FarthestCorner: { 827cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint corner; 828cad810f21b803229eb11403f9209855525a25d57Steve Block float distance = distanceToFarthestCorner(secondPoint, size, corner); 829cad810f21b803229eb11403f9209855525a25d57Steve Block if (shape == Circle) 830cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = distance; 831cad810f21b803229eb11403f9209855525a25d57Steve Block else { 832cad810f21b803229eb11403f9209855525a25d57Steve Block // If <shape> is ellipse, the gradient-shape has the same ratio of width to height 833cad810f21b803229eb11403f9209855525a25d57Steve Block // that it would if closest-side or farthest-side were specified, as appropriate. 834cad810f21b803229eb11403f9209855525a25d57Steve Block float xDist = max(secondPoint.x(), size.width() - secondPoint.x()); 835cad810f21b803229eb11403f9209855525a25d57Steve Block float yDist = max(secondPoint.y(), size.height() - secondPoint.y()); 836cad810f21b803229eb11403f9209855525a25d57Steve Block 837cad810f21b803229eb11403f9209855525a25d57Steve Block secondRadius = horizontalEllipseRadius(corner - secondPoint, xDist / yDist); 838cad810f21b803229eb11403f9209855525a25d57Steve Block aspectRatio = xDist / yDist; 839cad810f21b803229eb11403f9209855525a25d57Steve Block } 840cad810f21b803229eb11403f9209855525a25d57Steve Block break; 841cad810f21b803229eb11403f9209855525a25d57Steve Block } 842cad810f21b803229eb11403f9209855525a25d57Steve Block } 843cad810f21b803229eb11403f9209855525a25d57Steve Block } 844cad810f21b803229eb11403f9209855525a25d57Steve Block 845cad810f21b803229eb11403f9209855525a25d57Steve Block RefPtr<Gradient> gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius, aspectRatio); 846cad810f21b803229eb11403f9209855525a25d57Steve Block 847cad810f21b803229eb11403f9209855525a25d57Steve Block // addStops() only uses maxExtent for repeating gradients. 848cad810f21b803229eb11403f9209855525a25d57Steve Block float maxExtent = 0; 849cad810f21b803229eb11403f9209855525a25d57Steve Block if (m_repeating) { 850cad810f21b803229eb11403f9209855525a25d57Steve Block FloatPoint corner; 851cad810f21b803229eb11403f9209855525a25d57Steve Block maxExtent = distanceToFarthestCorner(secondPoint, size, corner); 852cad810f21b803229eb11403f9209855525a25d57Steve Block } 853cad810f21b803229eb11403f9209855525a25d57Steve Block 854cad810f21b803229eb11403f9209855525a25d57Steve Block // Now add the stops. 855cad810f21b803229eb11403f9209855525a25d57Steve Block addStops(gradient.get(), renderer, rootStyle, maxExtent); 856cad810f21b803229eb11403f9209855525a25d57Steve Block 857cad810f21b803229eb11403f9209855525a25d57Steve Block return gradient.release(); 858cad810f21b803229eb11403f9209855525a25d57Steve Block} 859cad810f21b803229eb11403f9209855525a25d57Steve Block 860cad810f21b803229eb11403f9209855525a25d57Steve Block} // namespace WebCore 861