1 /*
2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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.
25 */
26
27 #include "config.h"
28 #include "Gradient.h"
29
30 #include "Color.h"
31 #include "FloatRect.h"
32 #include <wtf/UnusedParam.h>
33
34 namespace WebCore {
35
Gradient(const FloatPoint & p0,const FloatPoint & p1)36 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
37 : m_radial(false)
38 , m_p0(p0)
39 , m_p1(p1)
40 , m_r0(0)
41 , m_r1(0)
42 , m_aspectRatio(1)
43 , m_stopsSorted(false)
44 , m_lastStop(0)
45 , m_spreadMethod(SpreadMethodPad)
46 {
47 platformInit();
48 }
49
Gradient(const FloatPoint & p0,float r0,const FloatPoint & p1,float r1,float aspectRatio)50 Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio)
51 : m_radial(true)
52 , m_p0(p0)
53 , m_p1(p1)
54 , m_r0(r0)
55 , m_r1(r1)
56 , m_aspectRatio(aspectRatio)
57 , m_stopsSorted(false)
58 , m_lastStop(0)
59 , m_spreadMethod(SpreadMethodPad)
60 {
61 platformInit();
62 }
63
~Gradient()64 Gradient::~Gradient()
65 {
66 platformDestroy();
67 }
68
adjustParametersForTiledDrawing(IntSize & size,FloatRect & srcRect)69 void Gradient::adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect)
70 {
71 if (m_radial)
72 return;
73
74 if (srcRect.isEmpty())
75 return;
76
77 if (m_p0.x() == m_p1.x()) {
78 size.setWidth(1);
79 srcRect.setWidth(1);
80 srcRect.setX(0);
81 return;
82 }
83 if (m_p0.y() != m_p1.y())
84 return;
85
86 size.setHeight(1);
87 srcRect.setHeight(1);
88 srcRect.setY(0);
89 }
90
addColorStop(float value,const Color & color)91 void Gradient::addColorStop(float value, const Color& color)
92 {
93 float r;
94 float g;
95 float b;
96 float a;
97 color.getRGBA(r, g, b, a);
98 m_stops.append(ColorStop(value, r, g, b, a));
99
100 m_stopsSorted = false;
101 platformDestroy();
102 }
103
addColorStop(const Gradient::ColorStop & stop)104 void Gradient::addColorStop(const Gradient::ColorStop& stop)
105 {
106 m_stops.append(stop);
107
108 m_stopsSorted = false;
109 platformDestroy();
110 }
111
compareStops(const Gradient::ColorStop & a,const Gradient::ColorStop & b)112 static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
113 {
114 return a.stop < b.stop;
115 }
116
sortStopsIfNecessary()117 void Gradient::sortStopsIfNecessary()
118 {
119 if (m_stopsSorted)
120 return;
121
122 m_stopsSorted = true;
123
124 if (!m_stops.size())
125 return;
126
127 // Shortcut for the ideal case (ordered 2-stop gradient)
128 if (m_stops.size() == 2 && compareStops(*m_stops.begin(), *m_stops.end()))
129 return;
130
131 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
132 }
133
getColor(float value,float * r,float * g,float * b,float * a) const134 void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
135 {
136 ASSERT(value >= 0);
137 ASSERT(value <= 1);
138
139 if (m_stops.isEmpty()) {
140 *r = 0;
141 *g = 0;
142 *b = 0;
143 *a = 0;
144 return;
145 }
146 if (!m_stopsSorted) {
147 if (m_stops.size())
148 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
149 m_stopsSorted = true;
150 }
151 if (value <= 0 || value <= m_stops.first().stop) {
152 *r = m_stops.first().red;
153 *g = m_stops.first().green;
154 *b = m_stops.first().blue;
155 *a = m_stops.first().alpha;
156 return;
157 }
158 if (value >= 1 || value >= m_stops.last().stop) {
159 *r = m_stops.last().red;
160 *g = m_stops.last().green;
161 *b = m_stops.last().blue;
162 *a = m_stops.last().alpha;
163 return;
164 }
165
166 // Find stop before and stop after and interpolate.
167 int stop = findStop(value);
168 const ColorStop& lastStop = m_stops[stop];
169 const ColorStop& nextStop = m_stops[stop + 1];
170 float stopFraction = (value - lastStop.stop) / (nextStop.stop - lastStop.stop);
171 *r = lastStop.red + (nextStop.red - lastStop.red) * stopFraction;
172 *g = lastStop.green + (nextStop.green - lastStop.green) * stopFraction;
173 *b = lastStop.blue + (nextStop.blue - lastStop.blue) * stopFraction;
174 *a = lastStop.alpha + (nextStop.alpha - lastStop.alpha) * stopFraction;
175 }
176
findStop(float value) const177 int Gradient::findStop(float value) const
178 {
179 ASSERT(value >= 0);
180 ASSERT(value <= 1);
181 ASSERT(m_stopsSorted);
182
183 int numStops = m_stops.size();
184 ASSERT(numStops >= 2);
185 ASSERT(m_lastStop < numStops - 1);
186
187 int i = m_lastStop;
188 if (value < m_stops[i].stop)
189 i = 1;
190 else
191 i = m_lastStop + 1;
192
193 for (; i < numStops - 1; ++i)
194 if (value < m_stops[i].stop)
195 break;
196
197 m_lastStop = i - 1;
198 return m_lastStop;
199 }
200
hasAlpha() const201 bool Gradient::hasAlpha() const
202 {
203 for (size_t i = 0; i < m_stops.size(); i++) {
204 if (m_stops[i].alpha < 1)
205 return true;
206 }
207
208 return false;
209 }
210
setSpreadMethod(GradientSpreadMethod spreadMethod)211 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
212 {
213 // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
214 ASSERT(m_gradient == 0);
215 m_spreadMethod = spreadMethod;
216 }
217
setGradientSpaceTransform(const AffineTransform & gradientSpaceTransformation)218 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
219 {
220 m_gradientSpaceTransformation = gradientSpaceTransformation;
221 setPlatformGradientSpaceTransform(gradientSpaceTransformation);
222 }
223
224 #if !USE(SKIA) && !USE(CAIRO)
setPlatformGradientSpaceTransform(const AffineTransform &)225 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&)
226 {
227 }
228 #endif
229
230
231 } //namespace
232