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 COMPUTER, 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 COMPUTER, 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 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GRADIENT_VALUE_H_
27 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GRADIENT_VALUE_H_
28 
29 #include "base/memory/scoped_refptr.h"
30 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
31 #include "third_party/blink/renderer/core/css/css_image_generator_value.h"
32 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
33 #include "third_party/blink/renderer/platform/wtf/casting.h"
34 #include "third_party/blink/renderer/platform/wtf/vector.h"
35 
36 namespace blink {
37 
38 class Color;
39 class Gradient;
40 class Document;
41 
42 namespace cssvalue {
43 
44 enum CSSGradientType {
45   kCSSDeprecatedLinearGradient,
46   kCSSDeprecatedRadialGradient,
47   kCSSPrefixedLinearGradient,
48   kCSSPrefixedRadialGradient,
49   kCSSLinearGradient,
50   kCSSRadialGradient,
51   kCSSConicGradient
52 };
53 enum CSSGradientRepeat { kNonRepeating, kRepeating };
54 
55 // This struct is stack allocated and allocated as part of vectors.
56 // When allocated on the stack its members are found by conservative
57 // stack scanning. When allocated as part of Vectors in heap-allocated
58 // objects its members are visited via the containing object's
59 // (CSSGradientValue) traceAfterDispatch method.
60 //
61 // http://www.w3.org/TR/css3-images/#color-stop-syntax
62 struct CSSGradientColorStop {
63   DISALLOW_NEW();
64 
65   bool operator==(const CSSGradientColorStop& other) const {
66     return DataEquivalent(color_, other.color_) &&
67            DataEquivalent(offset_, other.offset_);
68   }
69 
IsHintCSSGradientColorStop70   bool IsHint() const {
71     DCHECK(color_ || offset_);
72     return !color_;
73   }
74 
75   bool IsCacheable() const;
76 
77   void Trace(Visitor*);
78 
79   Member<const CSSPrimitiveValue> offset_;  // percentage | length | angle
80   Member<const CSSValue> color_;
81 };
82 
83 }  // namespace cssvalue
84 }  // namespace blink
85 
86 // We have to declare the VectorTraits specialization before CSSGradientValue
87 // declares its inline capacity vector below.
WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::cssvalue::CSSGradientColorStop)88 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(
89     blink::cssvalue::CSSGradientColorStop)
90 
91 namespace blink {
92 namespace cssvalue {
93 
94 class CSSGradientValue : public CSSImageGeneratorValue {
95  public:
96   scoped_refptr<Image> GetImage(const ImageResourceObserver&,
97                                 const Document&,
98                                 const ComputedStyle&,
99                                 const FloatSize&) const;
100 
101   void AddStop(const CSSGradientColorStop& stop) {
102     stops_.push_back(stop);
103     is_cacheable_ = is_cacheable_ && stop.IsCacheable();
104   }
105 
106   size_t StopCount() const { return stops_.size(); }
107 
108   bool IsRepeating() const { return repeating_; }
109 
110   CSSGradientType GradientType() const { return gradient_type_; }
111 
112   bool IsFixedSize() const { return false; }
113   FloatSize FixedSize(const Document&) const { return FloatSize(); }
114 
115   bool IsPending() const { return false; }
116   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const;
117 
118   void LoadSubimages(const Document&) {}
119 
120   Vector<Color> GetStopColors(const Document&, const ComputedStyle&) const;
121 
122   void TraceAfterDispatch(blink::Visitor*) const;
123 
124   struct GradientDesc;
125 
126  protected:
127   CSSGradientValue(ClassType class_type,
128                    CSSGradientRepeat repeat,
129                    CSSGradientType gradient_type)
130       : CSSImageGeneratorValue(class_type),
131         gradient_type_(gradient_type),
132         repeating_(repeat == kRepeating),
133         is_cacheable_(true) {}
134 
135   void AddStops(GradientDesc&,
136                 const CSSToLengthConversionData&,
137                 const Document&,
138                 const ComputedStyle&) const;
139   void AddDeprecatedStops(GradientDesc&,
140                           const Document&,
141                           const ComputedStyle&) const;
142   void AddComputedStops(const ComputedStyle&,
143                         bool allow_visited_style,
144                         const HeapVector<CSSGradientColorStop, 2>& stops);
145 
146   void AppendCSSTextForColorStops(StringBuilder&,
147                                   bool requires_separator) const;
148   void AppendCSSTextForDeprecatedColorStops(StringBuilder&) const;
149 
150   // Stops
151   HeapVector<CSSGradientColorStop, 2> stops_;
152   CSSGradientType gradient_type_;
153   bool repeating_ : 1;
154   bool is_cacheable_ : 1;
155 };
156 
157 class CSSLinearGradientValue final : public CSSGradientValue {
158  public:
159   CSSLinearGradientValue(const CSSValue* first_x,
160                          const CSSValue* first_y,
161                          const CSSValue* second_x,
162                          const CSSValue* second_y,
163                          const CSSPrimitiveValue* angle,
164                          CSSGradientRepeat repeat,
165                          CSSGradientType gradient_type = kCSSLinearGradient)
166       : CSSGradientValue(kLinearGradientClass, repeat, gradient_type),
167         first_x_(first_x),
168         first_y_(first_y),
169         second_x_(second_x),
170         second_y_(second_y),
171         angle_(angle) {}
172 
173   String CustomCSSText() const;
174 
175   // Create the gradient for a given size.
176   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
177                                          const FloatSize&,
178                                          const Document&,
179                                          const ComputedStyle&) const;
180 
181   bool Equals(const CSSLinearGradientValue&) const;
182 
183   CSSLinearGradientValue* ComputedCSSValue(const ComputedStyle&,
184                                            bool allow_visited_style);
185 
186   void TraceAfterDispatch(blink::Visitor*) const;
187 
188  private:
189   // Any of these may be null.
190   Member<const CSSValue> first_x_;
191   Member<const CSSValue> first_y_;
192   Member<const CSSValue> second_x_;
193   Member<const CSSValue> second_y_;
194   Member<const CSSPrimitiveValue> angle_;
195 };
196 
197 class CSSRadialGradientValue final : public CSSGradientValue {
198  public:
199   CSSRadialGradientValue(const CSSValue* first_x,
200                          const CSSValue* first_y,
201                          const CSSPrimitiveValue* first_radius,
202                          const CSSValue* second_x,
203                          const CSSValue* second_y,
204                          const CSSPrimitiveValue* second_radius,
205                          const CSSIdentifierValue* shape,
206                          const CSSIdentifierValue* sizing_behavior,
207                          const CSSPrimitiveValue* horizontal_size,
208                          const CSSPrimitiveValue* vertical_size,
209                          CSSGradientRepeat repeat,
210                          CSSGradientType gradient_type = kCSSRadialGradient)
211       : CSSGradientValue(kRadialGradientClass, repeat, gradient_type),
212         first_x_(first_x),
213         first_y_(first_y),
214         second_x_(second_x),
215         second_y_(second_y),
216         first_radius_(first_radius),
217         second_radius_(second_radius),
218         shape_(shape),
219         sizing_behavior_(sizing_behavior),
220         end_horizontal_size_(horizontal_size),
221         end_vertical_size_(vertical_size) {}
222 
223   CSSRadialGradientValue(const CSSValue* first_x,
224                          const CSSValue* first_y,
225                          const CSSPrimitiveValue* first_radius,
226                          const CSSValue* second_x,
227                          const CSSValue* second_y,
228                          const CSSPrimitiveValue* second_radius,
229                          CSSGradientRepeat repeat,
230                          CSSGradientType gradient_type = kCSSRadialGradient)
231       : CSSGradientValue(kRadialGradientClass, repeat, gradient_type),
232         first_x_(first_x),
233         first_y_(first_y),
234         second_x_(second_x),
235         second_y_(second_y),
236         first_radius_(first_radius),
237         second_radius_(second_radius),
238         shape_(nullptr),
239         sizing_behavior_(nullptr),
240         end_horizontal_size_(nullptr),
241         end_vertical_size_(nullptr) {}
242 
243   CSSRadialGradientValue(const CSSValue* center_x,
244                          const CSSValue* center_y,
245                          const CSSIdentifierValue* shape,
246                          const CSSIdentifierValue* sizing_behavior,
247                          const CSSPrimitiveValue* horizontal_size,
248                          const CSSPrimitiveValue* vertical_size,
249                          CSSGradientRepeat repeat,
250                          CSSGradientType gradient_type)
251       : CSSGradientValue(kRadialGradientClass, repeat, gradient_type),
252         first_x_(center_x),
253         first_y_(center_y),
254         second_x_(center_x),
255         second_y_(center_y),
256         first_radius_(nullptr),
257         second_radius_(nullptr),
258         shape_(shape),
259         sizing_behavior_(sizing_behavior),
260         end_horizontal_size_(horizontal_size),
261         end_vertical_size_(vertical_size) {}
262 
263   String CustomCSSText() const;
264 
265   void SetShape(CSSIdentifierValue* val) { shape_ = val; }
266   void SetSizingBehavior(CSSIdentifierValue* val) { sizing_behavior_ = val; }
267 
268   void SetEndHorizontalSize(CSSPrimitiveValue* val) {
269     end_horizontal_size_ = val;
270   }
271   void SetEndVerticalSize(CSSPrimitiveValue* val) { end_vertical_size_ = val; }
272 
273   // Create the gradient for a given size.
274   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
275                                          const FloatSize&,
276                                          const Document&,
277                                          const ComputedStyle&) const;
278 
279   bool Equals(const CSSRadialGradientValue&) const;
280 
281   CSSRadialGradientValue* ComputedCSSValue(const ComputedStyle&,
282                                            bool allow_visited_style);
283 
284   void TraceAfterDispatch(blink::Visitor*) const;
285 
286  private:
287   // Any of these may be null.
288   Member<const CSSValue> first_x_;
289   Member<const CSSValue> first_y_;
290   Member<const CSSValue> second_x_;
291   Member<const CSSValue> second_y_;
292 
293   // These may be null for non-deprecated gradients.
294   Member<const CSSPrimitiveValue> first_radius_;
295   Member<const CSSPrimitiveValue> second_radius_;
296 
297   // The below are only used for non-deprecated gradients. Any of them may be
298   // null.
299   Member<const CSSIdentifierValue> shape_;
300   Member<const CSSIdentifierValue> sizing_behavior_;
301 
302   Member<const CSSPrimitiveValue> end_horizontal_size_;
303   Member<const CSSPrimitiveValue> end_vertical_size_;
304 };
305 
306 class CSSConicGradientValue final : public CSSGradientValue {
307  public:
308   CSSConicGradientValue(const CSSValue* x,
309                         const CSSValue* y,
310                         const CSSPrimitiveValue* from_angle,
311                         CSSGradientRepeat repeat)
312       : CSSGradientValue(kConicGradientClass, repeat, kCSSConicGradient),
313         x_(x),
314         y_(y),
315         from_angle_(from_angle) {}
316 
317   String CustomCSSText() const;
318 
319   // Create the gradient for a given size.
320   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
321                                          const FloatSize&,
322                                          const Document&,
323                                          const ComputedStyle&) const;
324 
325   bool Equals(const CSSConicGradientValue&) const;
326 
327   CSSConicGradientValue* ComputedCSSValue(const ComputedStyle&,
328                                           bool allow_visited_style);
329 
330   void TraceAfterDispatch(blink::Visitor*) const;
331 
332  private:
333   // Any of these may be null.
334   Member<const CSSValue> x_;
335   Member<const CSSValue> y_;
336   Member<const CSSPrimitiveValue> from_angle_;
337 };
338 
339 }  // namespace cssvalue
340 
341 template <>
342 struct DowncastTraits<cssvalue::CSSGradientValue> {
343   static bool AllowFrom(const CSSValue& value) {
344     return value.IsGradientValue();
345   }
346 };
347 
348 template <>
349 struct DowncastTraits<cssvalue::CSSLinearGradientValue> {
350   static bool AllowFrom(const CSSValue& value) {
351     return value.IsLinearGradientValue();
352   }
353 };
354 
355 template <>
356 struct DowncastTraits<cssvalue::CSSRadialGradientValue> {
357   static bool AllowFrom(const CSSValue& value) {
358     return value.IsRadialGradientValue();
359   }
360 };
361 
362 template <>
363 struct DowncastTraits<cssvalue::CSSConicGradientValue> {
364   static bool AllowFrom(const CSSValue& value) {
365     return value.IsConicGradientValue();
366   }
367 };
368 
369 }  // namespace blink
370 
371 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_GRADIENT_VALUE_H_
372