[Color] Make gradients work with ExtendedColors
[WebKit-https.git] / Source / WebCore / platform / graphics / Gradient.cpp
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 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 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/HashFunctions.h>
33 #include <wtf/Hasher.h>
34
35 using WTF::pairIntHash;
36
37 namespace WebCore {
38
39 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
40     : m_radial(false)
41     , m_p0(p0)
42     , m_p1(p1)
43     , m_r0(0)
44     , m_r1(0)
45     , m_aspectRatio(1)
46     , m_stopsSorted(false)
47     , m_spreadMethod(SpreadMethodPad)
48     , m_cachedHash(0)
49 {
50     platformInit();
51 }
52
53 Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio)
54     : m_radial(true)
55     , m_p0(p0)
56     , m_p1(p1)
57     , m_r0(r0)
58     , m_r1(r1)
59     , m_aspectRatio(aspectRatio)
60     , m_stopsSorted(false)
61     , m_spreadMethod(SpreadMethodPad)
62     , m_cachedHash(0)
63 {
64     platformInit();
65 }
66
67 Gradient::~Gradient()
68 {
69     platformDestroy();
70 }
71
72 void Gradient::adjustParametersForTiledDrawing(FloatSize& size, FloatRect& srcRect, const FloatSize& spacing)
73 {
74     if (m_radial)
75         return;
76
77     if (srcRect.isEmpty())
78         return;
79
80     if (!spacing.isZero())
81         return;
82
83     if (m_p0.x() == m_p1.x()) {
84         size.setWidth(1);
85         srcRect.setWidth(1);
86         srcRect.setX(0);
87         return;
88     }
89     if (m_p0.y() != m_p1.y())
90         return;
91
92     size.setHeight(1);
93     srcRect.setHeight(1);
94     srcRect.setY(0);
95 }
96
97 void Gradient::addColorStop(float offset, const Color& color)
98 {
99     m_stops.append(ColorStop(offset, color));
100
101     m_stopsSorted = false;
102     platformDestroy();
103
104     invalidateHash();
105 }
106
107 void Gradient::addColorStop(const Gradient::ColorStop& stop)
108 {
109     m_stops.append(stop);
110
111     m_stopsSorted = false;
112     platformDestroy();
113
114     invalidateHash();
115 }
116
117 static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
118 {
119     return a.offset < b.offset;
120 }
121
122 void Gradient::sortStopsIfNecessary()
123 {
124     if (m_stopsSorted)
125         return;
126
127     m_stopsSorted = true;
128
129     if (!m_stops.size())
130         return;
131
132     std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
133
134     invalidateHash();
135 }
136
137 bool Gradient::hasAlpha() const
138 {
139     for (const auto& stop : m_stops) {
140         if (!stop.color.isOpaque())
141             return true;
142     }
143
144     return false;
145 }
146
147 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
148 {
149     // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
150     ASSERT(m_gradient == 0);
151
152     if (m_spreadMethod == spreadMethod)
153         return;
154
155     m_spreadMethod = spreadMethod;
156
157     invalidateHash();
158 }
159
160 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
161 {
162     if (m_gradientSpaceTransformation == gradientSpaceTransformation)
163         return;
164
165     m_gradientSpaceTransformation = gradientSpaceTransformation;
166     setPlatformGradientSpaceTransform(gradientSpaceTransformation);
167
168     invalidateHash();
169 }
170
171 #if !USE(CAIRO)
172 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&)
173 {
174 }
175 #endif
176
177 unsigned Gradient::hash() const
178 {
179     if (m_cachedHash)
180         return m_cachedHash;
181
182     struct {
183         AffineTransform gradientSpaceTransformation;
184         FloatPoint p0;
185         FloatPoint p1;
186         float r0;
187         float r1;
188         float aspectRatio;
189         GradientSpreadMethod spreadMethod;
190         bool radial;
191     } parameters;
192
193     // StringHasher requires that the memory it hashes be a multiple of two in size.
194     COMPILE_ASSERT(!(sizeof(parameters) % 2), Gradient_parameters_size_should_be_multiple_of_two);
195     COMPILE_ASSERT(!(sizeof(ColorStop) % 2), Color_stop_size_should_be_multiple_of_two);
196     
197     // Ensure that any padding in the struct is zero-filled, so it will not affect the hash value.
198     memset(&parameters, 0, sizeof(parameters));
199     
200     parameters.gradientSpaceTransformation = m_gradientSpaceTransformation;
201     parameters.p0 = m_p0;
202     parameters.p1 = m_p1;
203     parameters.r0 = m_r0;
204     parameters.r1 = m_r1;
205     parameters.aspectRatio = m_aspectRatio;
206     parameters.spreadMethod = m_spreadMethod;
207     parameters.radial = m_radial;
208
209     unsigned parametersHash = StringHasher::hashMemory(&parameters, sizeof(parameters));
210     unsigned stopHash = StringHasher::hashMemory(m_stops.data(), m_stops.size() * sizeof(ColorStop));
211
212     m_cachedHash = pairIntHash(parametersHash, stopHash);
213
214     return m_cachedHash;
215 }
216
217 } //namespace