1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "CSSImageGeneratorValue.h"
29#include "CSSPrimitiveValue.h"
30#include "Gradient.h"
31#include <wtf/Vector.h>
32
33namespace WebCore {
34
35class FloatPoint;
36class StyleResolver;
37
38enum CSSGradientType {
39 CSSDeprecatedLinearGradient,
40 CSSDeprecatedRadialGradient,
41 CSSPrefixedLinearGradient,
42 CSSPrefixedRadialGradient,
43 CSSLinearGradient,
44 CSSRadialGradient,
45 CSSConicGradient
46};
47enum CSSGradientRepeat { NonRepeating, Repeating };
48
49struct CSSGradientColorStop {
50 RefPtr<CSSPrimitiveValue> m_position; // percentage or length
51 RefPtr<CSSPrimitiveValue> m_color;
52 Color m_resolvedColor;
53 bool m_colorIsDerivedFromElement = false;
54 bool isMidpoint = false;
55 bool operator==(const CSSGradientColorStop& other) const
56 {
57 return compareCSSValuePtr(m_color, other.m_color)
58 && compareCSSValuePtr(m_position, other.m_position);
59 }
60};
61
62class CSSGradientValue : public CSSImageGeneratorValue {
63public:
64 RefPtr<Image> image(RenderElement&, const FloatSize&);
65
66 void setFirstX(RefPtr<CSSPrimitiveValue>&& val) { m_firstX = WTFMove(val); }
67 void setFirstY(RefPtr<CSSPrimitiveValue>&& val) { m_firstY = WTFMove(val); }
68 void setSecondX(RefPtr<CSSPrimitiveValue>&& val) { m_secondX = WTFMove(val); }
69 void setSecondY(RefPtr<CSSPrimitiveValue>&& val) { m_secondY = WTFMove(val); }
70
71 void addStop(const CSSGradientColorStop& stop) { m_stops.append(stop); }
72 void doneAddingStops() { m_stops.shrinkToFit(); }
73
74 unsigned stopCount() const { return m_stops.size(); }
75
76 void sortStopsIfNeeded();
77
78 bool isRepeating() const { return m_repeating; }
79
80 CSSGradientType gradientType() const { return m_gradientType; }
81
82 bool isFixedSize() const { return false; }
83 FloatSize fixedSize(const RenderElement&) const { return FloatSize(); }
84
85 bool isPending() const { return false; }
86 bool knownToBeOpaque(const RenderElement&) const;
87
88 void loadSubimages(CachedResourceLoader&, const ResourceLoaderOptions&) { }
89 Ref<CSSGradientValue> gradientWithStylesResolved(const StyleResolver&);
90
91protected:
92 CSSGradientValue(ClassType classType, CSSGradientRepeat repeat, CSSGradientType gradientType)
93 : CSSImageGeneratorValue(classType)
94 , m_stopsSorted(false)
95 , m_gradientType(gradientType)
96 , m_repeating(repeat == Repeating)
97 {
98 }
99
100 CSSGradientValue(const CSSGradientValue& other, ClassType classType, CSSGradientType gradientType)
101 : CSSImageGeneratorValue(classType)
102 , m_firstX(other.m_firstX)
103 , m_firstY(other.m_firstY)
104 , m_secondX(other.m_secondX)
105 , m_secondY(other.m_secondY)
106 , m_stops(other.m_stops)
107 , m_stopsSorted(other.m_stopsSorted)
108 , m_gradientType(gradientType)
109 , m_repeating(other.isRepeating() ? Repeating : NonRepeating)
110 {
111 }
112
113 template<typename GradientAdapter>
114 Gradient::ColorStopVector computeStops(GradientAdapter&, const CSSToLengthConversionData&, const RenderStyle&, float maxLengthForRepeat);
115
116 // Resolve points/radii to front end values.
117 FloatPoint computeEndPoint(CSSPrimitiveValue*, CSSPrimitiveValue*, const CSSToLengthConversionData&, const FloatSize&);
118
119 bool isCacheable() const;
120
121 // Points. Some of these may be null.
122 RefPtr<CSSPrimitiveValue> m_firstX;
123 RefPtr<CSSPrimitiveValue> m_firstY;
124
125 RefPtr<CSSPrimitiveValue> m_secondX;
126 RefPtr<CSSPrimitiveValue> m_secondY;
127
128 // Stops
129 Vector<CSSGradientColorStop, 2> m_stops;
130 bool m_stopsSorted;
131 CSSGradientType m_gradientType;
132 bool m_repeating;
133};
134
135class CSSLinearGradientValue final : public CSSGradientValue {
136public:
137 static Ref<CSSLinearGradientValue> create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSLinearGradient)
138 {
139 return adoptRef(*new CSSLinearGradientValue(repeat, gradientType));
140 }
141
142 void setAngle(Ref<CSSPrimitiveValue>&& val) { m_angle = WTFMove(val); }
143
144 String customCSSText() const;
145
146 // Create the gradient for a given size.
147 Ref<Gradient> createGradient(RenderElement&, const FloatSize&);
148
149 Ref<CSSLinearGradientValue> clone() const
150 {
151 return adoptRef(*new CSSLinearGradientValue(*this));
152 }
153
154 bool equals(const CSSLinearGradientValue&) const;
155
156private:
157 CSSLinearGradientValue(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSLinearGradient)
158 : CSSGradientValue(LinearGradientClass, repeat, gradientType)
159 {
160 }
161
162 CSSLinearGradientValue(const CSSLinearGradientValue& other)
163 : CSSGradientValue(other, LinearGradientClass, other.gradientType())
164 , m_angle(other.m_angle)
165 {
166 }
167
168 RefPtr<CSSPrimitiveValue> m_angle; // may be null.
169};
170
171class CSSRadialGradientValue final : public CSSGradientValue {
172public:
173 static Ref<CSSRadialGradientValue> create(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSRadialGradient)
174 {
175 return adoptRef(*new CSSRadialGradientValue(repeat, gradientType));
176 }
177
178 Ref<CSSRadialGradientValue> clone() const
179 {
180 return adoptRef(*new CSSRadialGradientValue(*this));
181 }
182
183 String customCSSText() const;
184
185 void setFirstRadius(RefPtr<CSSPrimitiveValue>&& val) { m_firstRadius = WTFMove(val); }
186 void setSecondRadius(RefPtr<CSSPrimitiveValue>&& val) { m_secondRadius = WTFMove(val); }
187
188 void setShape(RefPtr<CSSPrimitiveValue>&& val) { m_shape = WTFMove(val); }
189 void setSizingBehavior(RefPtr<CSSPrimitiveValue>&& val) { m_sizingBehavior = WTFMove(val); }
190
191 void setEndHorizontalSize(RefPtr<CSSPrimitiveValue>&& val) { m_endHorizontalSize = WTFMove(val); }
192 void setEndVerticalSize(RefPtr<CSSPrimitiveValue>&& val) { m_endVerticalSize = WTFMove(val); }
193
194 // Create the gradient for a given size.
195 Ref<Gradient> createGradient(RenderElement&, const FloatSize&);
196
197 bool equals(const CSSRadialGradientValue&) const;
198
199private:
200 CSSRadialGradientValue(CSSGradientRepeat repeat, CSSGradientType gradientType = CSSRadialGradient)
201 : CSSGradientValue(RadialGradientClass, repeat, gradientType)
202 {
203 }
204
205 CSSRadialGradientValue(const CSSRadialGradientValue& other)
206 : CSSGradientValue(other, RadialGradientClass, other.gradientType())
207 , m_firstRadius(other.m_firstRadius)
208 , m_secondRadius(other.m_secondRadius)
209 , m_shape(other.m_shape)
210 , m_sizingBehavior(other.m_sizingBehavior)
211 , m_endHorizontalSize(other.m_endHorizontalSize)
212 , m_endVerticalSize(other.m_endVerticalSize)
213 {
214 }
215
216 // Resolve points/radii to front end values.
217 float resolveRadius(CSSPrimitiveValue&, const CSSToLengthConversionData&, float* widthOrHeight = 0);
218
219 // These may be null for non-deprecated gradients.
220 RefPtr<CSSPrimitiveValue> m_firstRadius;
221 RefPtr<CSSPrimitiveValue> m_secondRadius;
222
223 // The below are only used for non-deprecated gradients. Any of them may be null.
224 RefPtr<CSSPrimitiveValue> m_shape;
225 RefPtr<CSSPrimitiveValue> m_sizingBehavior;
226
227 RefPtr<CSSPrimitiveValue> m_endHorizontalSize;
228 RefPtr<CSSPrimitiveValue> m_endVerticalSize;
229};
230
231class CSSConicGradientValue final : public CSSGradientValue {
232public:
233 static Ref<CSSConicGradientValue> create(CSSGradientRepeat repeat)
234 {
235 return adoptRef(*new CSSConicGradientValue(repeat));
236 }
237
238 Ref<CSSConicGradientValue> clone() const
239 {
240 return adoptRef(*new CSSConicGradientValue(*this));
241 }
242
243 String customCSSText() const;
244
245 void setAngle(RefPtr<CSSPrimitiveValue>&& val) { m_angle = WTFMove(val); }
246
247 // Create the gradient for a given size.
248 Ref<Gradient> createGradient(RenderElement&, const FloatSize&);
249
250 bool equals(const CSSConicGradientValue&) const;
251
252private:
253 CSSConicGradientValue(CSSGradientRepeat repeat)
254 : CSSGradientValue(ConicGradientClass, repeat, CSSConicGradient)
255 {
256 }
257
258 CSSConicGradientValue(const CSSConicGradientValue& other)
259 : CSSGradientValue(other, ConicGradientClass, other.gradientType())
260 , m_angle(other.m_angle)
261 {
262 }
263
264 RefPtr<CSSPrimitiveValue> m_angle; // may be null.
265};
266
267} // namespace WebCore
268
269SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSGradientValue, isGradientValue())
270SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSLinearGradientValue, isLinearGradientValue())
271SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSRadialGradientValue, isRadialGradientValue())
272SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSConicGradientValue, isConicGradientValue())
273