2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "FloatRect.h"
32 #include <wtf/UnusedParam.h>
36 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
43 , m_stopsSorted(false)
45 , m_spreadMethod(SpreadMethodPad)
50 Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio)
56 , m_aspectRatio(aspectRatio)
57 , m_stopsSorted(false)
59 , m_spreadMethod(SpreadMethodPad)
69 void Gradient::adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect)
74 if (srcRect.isEmpty())
77 if (m_p0.x() == m_p1.x()) {
83 if (m_p0.y() != m_p1.y())
91 void Gradient::addColorStop(float value, const Color& color)
97 color.getRGBA(r, g, b, a);
98 m_stops.append(ColorStop(value, r, g, b, a));
100 m_stopsSorted = false;
104 void Gradient::addColorStop(const Gradient::ColorStop& stop)
106 m_stops.append(stop);
108 m_stopsSorted = false;
112 static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
114 return a.stop < b.stop;
117 void Gradient::sortStopsIfNecessary()
122 m_stopsSorted = true;
127 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
130 void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
135 if (m_stops.isEmpty()) {
142 if (!m_stopsSorted) {
144 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
145 m_stopsSorted = true;
147 if (value <= 0 || value <= m_stops.first().stop) {
148 *r = m_stops.first().red;
149 *g = m_stops.first().green;
150 *b = m_stops.first().blue;
151 *a = m_stops.first().alpha;
154 if (value >= 1 || value >= m_stops.last().stop) {
155 *r = m_stops.last().red;
156 *g = m_stops.last().green;
157 *b = m_stops.last().blue;
158 *a = m_stops.last().alpha;
162 // Find stop before and stop after and interpolate.
163 int stop = findStop(value);
164 const ColorStop& lastStop = m_stops[stop];
165 const ColorStop& nextStop = m_stops[stop + 1];
166 float stopFraction = (value - lastStop.stop) / (nextStop.stop - lastStop.stop);
167 *r = lastStop.red + (nextStop.red - lastStop.red) * stopFraction;
168 *g = lastStop.green + (nextStop.green - lastStop.green) * stopFraction;
169 *b = lastStop.blue + (nextStop.blue - lastStop.blue) * stopFraction;
170 *a = lastStop.alpha + (nextStop.alpha - lastStop.alpha) * stopFraction;
173 int Gradient::findStop(float value) const
177 ASSERT(m_stopsSorted);
179 int numStops = m_stops.size();
180 ASSERT(numStops >= 2);
181 ASSERT(m_lastStop < numStops - 1);
184 if (value < m_stops[i].stop)
189 for (; i < numStops - 1; ++i)
190 if (value < m_stops[i].stop)
197 bool Gradient::hasAlpha() const
199 for (size_t i = 0; i < m_stops.size(); i++) {
200 if (m_stops[i].alpha < 1)
207 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
209 // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
210 ASSERT(m_gradient == 0);
211 m_spreadMethod = spreadMethod;
214 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
216 m_gradientSpaceTransformation = gradientSpaceTransformation;
217 setPlatformGradientSpaceTransform(gradientSpaceTransformation);
220 #if !USE(SKIA) && !USE(CAIRO)
221 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&)