1/*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#include "config.h"
23#include "FillLayer.h"
24
25#include <wtf/PointerComparison.h>
26#include <wtf/text/TextStream.h>
27
28namespace WebCore {
29
30struct SameSizeAsFillLayer {
31 FillLayer* next;
32
33 RefPtr<StyleImage> image;
34
35 Length x;
36 Length y;
37
38 LengthSize sizeLength;
39
40 unsigned bitfields : 32;
41 unsigned bitfields2 : 11;
42};
43
44COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small);
45
46FillLayer::FillLayer(FillLayerType type)
47 : m_image(FillLayer::initialFillImage(type))
48 , m_xPosition(FillLayer::initialFillXPosition(type))
49 , m_yPosition(FillLayer::initialFillYPosition(type))
50 , m_attachment(static_cast<unsigned>(FillLayer::initialFillAttachment(type)))
51 , m_clip(static_cast<unsigned>(FillLayer::initialFillClip(type)))
52 , m_origin(static_cast<unsigned>(FillLayer::initialFillOrigin(type)))
53 , m_repeatX(static_cast<unsigned>(FillLayer::initialFillRepeatX(type)))
54 , m_repeatY(static_cast<unsigned>(FillLayer::initialFillRepeatY(type)))
55 , m_composite(FillLayer::initialFillComposite(type))
56 , m_sizeType(static_cast<unsigned>(FillSizeType::None))
57 , m_blendMode(static_cast<unsigned>(FillLayer::initialFillBlendMode(type)))
58 , m_maskSourceType(static_cast<unsigned>(FillLayer::initialFillMaskSourceType(type)))
59 , m_imageSet(false)
60 , m_attachmentSet(false)
61 , m_clipSet(false)
62 , m_originSet(false)
63 , m_repeatXSet(false)
64 , m_repeatYSet(false)
65 , m_xPosSet(false)
66 , m_yPosSet(false)
67 , m_backgroundXOriginSet(false)
68 , m_backgroundYOriginSet(false)
69 , m_backgroundXOrigin(static_cast<unsigned>(Edge::Left))
70 , m_backgroundYOrigin(static_cast<unsigned>(Edge::Top))
71 , m_compositeSet(type == FillLayerType::Mask)
72 , m_blendModeSet(false)
73 , m_maskSourceTypeSet(false)
74 , m_type(static_cast<unsigned>(type))
75{
76}
77
78FillLayer::FillLayer(const FillLayer& o)
79 : m_next(o.m_next ? std::make_unique<FillLayer>(*o.m_next) : nullptr)
80 , m_image(o.m_image)
81 , m_xPosition(o.m_xPosition)
82 , m_yPosition(o.m_yPosition)
83 , m_sizeLength(o.m_sizeLength)
84 , m_attachment(o.m_attachment)
85 , m_clip(o.m_clip)
86 , m_origin(o.m_origin)
87 , m_repeatX(o.m_repeatX)
88 , m_repeatY(o.m_repeatY)
89 , m_composite(o.m_composite)
90 , m_sizeType(o.m_sizeType)
91 , m_blendMode(o.m_blendMode)
92 , m_maskSourceType(o.m_maskSourceType)
93 , m_imageSet(o.m_imageSet)
94 , m_attachmentSet(o.m_attachmentSet)
95 , m_clipSet(o.m_clipSet)
96 , m_originSet(o.m_originSet)
97 , m_repeatXSet(o.m_repeatXSet)
98 , m_repeatYSet(o.m_repeatYSet)
99 , m_xPosSet(o.m_xPosSet)
100 , m_yPosSet(o.m_yPosSet)
101 , m_backgroundXOriginSet(o.m_backgroundXOriginSet)
102 , m_backgroundYOriginSet(o.m_backgroundYOriginSet)
103 , m_backgroundXOrigin(o.m_backgroundXOrigin)
104 , m_backgroundYOrigin(o.m_backgroundYOrigin)
105 , m_compositeSet(o.m_compositeSet)
106 , m_blendModeSet(o.m_blendModeSet)
107 , m_maskSourceTypeSet(o.m_maskSourceTypeSet)
108 , m_type(o.m_type)
109{
110}
111
112FillLayer::~FillLayer()
113{
114 // Delete the layers in a loop rather than allowing recursive calls to the destructors.
115 for (std::unique_ptr<FillLayer> next = WTFMove(m_next); next; next = WTFMove(next->m_next)) { }
116}
117
118FillLayer& FillLayer::operator=(const FillLayer& o)
119{
120 m_next = o.m_next ? std::make_unique<FillLayer>(*o.m_next) : nullptr;
121
122 m_image = o.m_image;
123 m_xPosition = o.m_xPosition;
124 m_yPosition = o.m_yPosition;
125 m_backgroundXOrigin = o.m_backgroundXOrigin;
126 m_backgroundYOrigin = o.m_backgroundYOrigin;
127 m_backgroundXOriginSet = o.m_backgroundXOriginSet;
128 m_backgroundYOriginSet = o.m_backgroundYOriginSet;
129 m_sizeLength = o.m_sizeLength;
130 m_attachment = o.m_attachment;
131 m_clip = o.m_clip;
132 m_composite = o.m_composite;
133 m_blendMode = o.m_blendMode;
134 m_origin = o.m_origin;
135 m_repeatX = o.m_repeatX;
136 m_repeatY = o.m_repeatY;
137 m_sizeType = o.m_sizeType;
138 m_maskSourceType = o.m_maskSourceType;
139
140 m_imageSet = o.m_imageSet;
141 m_attachmentSet = o.m_attachmentSet;
142 m_clipSet = o.m_clipSet;
143 m_compositeSet = o.m_compositeSet;
144 m_blendModeSet = o.m_blendModeSet;
145 m_originSet = o.m_originSet;
146 m_repeatXSet = o.m_repeatXSet;
147 m_repeatYSet = o.m_repeatYSet;
148 m_xPosSet = o.m_xPosSet;
149 m_yPosSet = o.m_yPosSet;
150 m_maskSourceTypeSet = o.m_maskSourceTypeSet;
151
152 m_type = o.m_type;
153
154 return *this;
155}
156
157bool FillLayer::operator==(const FillLayer& o) const
158{
159 // We do not check the "isSet" booleans for each property, since those are only used during initial construction
160 // to propagate patterns into layers. All layer comparisons happen after values have all been filled in anyway.
161 return arePointingToEqualData(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition
162 && m_backgroundXOrigin == o.m_backgroundXOrigin && m_backgroundYOrigin == o.m_backgroundYOrigin
163 && m_attachment == o.m_attachment && m_clip == o.m_clip && m_composite == o.m_composite
164 && m_blendMode == o.m_blendMode && m_origin == o.m_origin && m_repeatX == o.m_repeatX
165 && m_repeatY == o.m_repeatY && m_sizeType == o.m_sizeType && m_maskSourceType == o.m_maskSourceType
166 && m_sizeLength == o.m_sizeLength && m_type == o.m_type
167 && ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
168}
169
170void FillLayer::fillUnsetProperties()
171{
172 FillLayer* curr;
173 for (curr = this; curr && curr->isXPositionSet(); curr = curr->next()) { }
174 if (curr && curr != this) {
175 // We need to fill in the remaining values with the pattern specified.
176 for (FillLayer* pattern = this; curr; curr = curr->next()) {
177 curr->m_xPosition = pattern->m_xPosition;
178 if (pattern->isBackgroundXOriginSet())
179 curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
180 if (pattern->isBackgroundYOriginSet())
181 curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
182 pattern = pattern->next();
183 if (pattern == curr || !pattern)
184 pattern = this;
185 }
186 }
187
188 for (curr = this; curr && curr->isYPositionSet(); curr = curr->next()) { }
189 if (curr && curr != this) {
190 // We need to fill in the remaining values with the pattern specified.
191 for (FillLayer* pattern = this; curr; curr = curr->next()) {
192 curr->m_yPosition = pattern->m_yPosition;
193 if (pattern->isBackgroundXOriginSet())
194 curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
195 if (pattern->isBackgroundYOriginSet())
196 curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
197 pattern = pattern->next();
198 if (pattern == curr || !pattern)
199 pattern = this;
200 }
201 }
202
203 for (curr = this; curr && curr->isAttachmentSet(); curr = curr->next()) { }
204 if (curr && curr != this) {
205 // We need to fill in the remaining values with the pattern specified.
206 for (FillLayer* pattern = this; curr; curr = curr->next()) {
207 curr->m_attachment = pattern->m_attachment;
208 pattern = pattern->next();
209 if (pattern == curr || !pattern)
210 pattern = this;
211 }
212 }
213
214 for (curr = this; curr && curr->isClipSet(); curr = curr->next()) { }
215 if (curr && curr != this) {
216 // We need to fill in the remaining values with the pattern specified.
217 for (FillLayer* pattern = this; curr; curr = curr->next()) {
218 curr->m_clip = pattern->m_clip;
219 pattern = pattern->next();
220 if (pattern == curr || !pattern)
221 pattern = this;
222 }
223 }
224
225 for (curr = this; curr && curr->isCompositeSet(); curr = curr->next()) { }
226 if (curr && curr != this) {
227 // We need to fill in the remaining values with the pattern specified.
228 for (FillLayer* pattern = this; curr; curr = curr->next()) {
229 curr->m_composite = pattern->m_composite;
230 pattern = pattern->next();
231 if (pattern == curr || !pattern)
232 pattern = this;
233 }
234 }
235
236 for (curr = this; curr && curr->isBlendModeSet(); curr = curr->next()) { }
237 if (curr && curr != this) {
238 // We need to fill in the remaining values with the pattern specified.
239 for (FillLayer* pattern = this; curr; curr = curr->next()) {
240 curr->m_blendMode = pattern->m_blendMode;
241 pattern = pattern->next();
242 if (pattern == curr || !pattern)
243 pattern = this;
244 }
245 }
246
247 for (curr = this; curr && curr->isOriginSet(); curr = curr->next()) { }
248 if (curr && curr != this) {
249 // We need to fill in the remaining values with the pattern specified.
250 for (FillLayer* pattern = this; curr; curr = curr->next()) {
251 curr->m_origin = pattern->m_origin;
252 pattern = pattern->next();
253 if (pattern == curr || !pattern)
254 pattern = this;
255 }
256 }
257
258 for (curr = this; curr && curr->isRepeatXSet(); curr = curr->next()) { }
259 if (curr && curr != this) {
260 // We need to fill in the remaining values with the pattern specified.
261 for (FillLayer* pattern = this; curr; curr = curr->next()) {
262 curr->m_repeatX = pattern->m_repeatX;
263 pattern = pattern->next();
264 if (pattern == curr || !pattern)
265 pattern = this;
266 }
267 }
268
269 for (curr = this; curr && curr->isRepeatYSet(); curr = curr->next()) { }
270 if (curr && curr != this) {
271 // We need to fill in the remaining values with the pattern specified.
272 for (FillLayer* pattern = this; curr; curr = curr->next()) {
273 curr->m_repeatY = pattern->m_repeatY;
274 pattern = pattern->next();
275 if (pattern == curr || !pattern)
276 pattern = this;
277 }
278 }
279
280 for (curr = this; curr && curr->isSizeSet(); curr = curr->next()) { }
281 if (curr && curr != this) {
282 // We need to fill in the remaining values with the pattern specified.
283 for (FillLayer* pattern = this; curr; curr = curr->next()) {
284 curr->m_sizeType = pattern->m_sizeType;
285 curr->m_sizeLength = pattern->m_sizeLength;
286 pattern = pattern->next();
287 if (pattern == curr || !pattern)
288 pattern = this;
289 }
290 }
291}
292
293void FillLayer::cullEmptyLayers()
294{
295 for (FillLayer* layer = this; layer; layer = layer->m_next.get()) {
296 if (layer->m_next && !layer->m_next->isImageSet()) {
297 layer->m_next = nullptr;
298 break;
299 }
300 }
301}
302
303static inline FillBox clipMax(FillBox clipA, FillBox clipB)
304{
305 if (clipA == FillBox::Border || clipB == FillBox::Border)
306 return FillBox::Border;
307 if (clipA == FillBox::Padding || clipB == FillBox::Padding)
308 return FillBox::Padding;
309 if (clipA == FillBox::Content || clipB == FillBox::Content)
310 return FillBox::Content;
311 return FillBox::Text;
312}
313
314void FillLayer::computeClipMax() const
315{
316 Vector<const FillLayer*, 4> layers;
317 for (auto* layer = this; layer; layer = layer->m_next.get())
318 layers.append(layer);
319 FillBox computedClipMax = FillBox::Text;
320 for (unsigned i = layers.size(); i; --i) {
321 auto& layer = *layers[i - 1];
322 computedClipMax = clipMax(computedClipMax, layer.clip());
323 layer.m_clipMax = static_cast<unsigned>(computedClipMax);
324 }
325}
326
327bool FillLayer::clipOccludesNextLayers(bool firstLayer) const
328{
329 if (firstLayer)
330 computeClipMax();
331 return m_clip == m_clipMax;
332}
333
334bool FillLayer::containsImage(StyleImage& image) const
335{
336 for (auto* layer = this; layer; layer = layer->m_next.get()) {
337 if (layer->m_image && image == *layer->m_image)
338 return true;
339 }
340 return false;
341}
342
343bool FillLayer::imagesAreLoaded() const
344{
345 for (auto* layer = this; layer; layer = layer->m_next.get()) {
346 if (layer->m_image && !layer->m_image->isLoaded())
347 return false;
348 }
349 return true;
350}
351
352bool FillLayer::hasOpaqueImage(const RenderElement& renderer) const
353{
354 if (!m_image)
355 return false;
356
357 if (m_composite == CompositeClear || m_composite == CompositeCopy)
358 return true;
359
360 return static_cast<BlendMode>(m_blendMode) == BlendMode::Normal && m_composite == CompositeSourceOver && m_image->knownToBeOpaque(&renderer);
361}
362
363bool FillLayer::hasRepeatXY() const
364{
365 return repeatX() == FillRepeat::Repeat && repeatY() == FillRepeat::Repeat;
366}
367
368bool FillLayer::hasImage() const
369{
370 for (auto* layer = this; layer; layer = layer->m_next.get()) {
371 if (layer->image())
372 return true;
373 }
374 return false;
375}
376
377bool FillLayer::hasFixedImage() const
378{
379 for (auto* layer = this; layer; layer = layer->m_next.get()) {
380 if (layer->m_image && layer->attachment() == FillAttachment::FixedBackground)
381 return true;
382 }
383 return false;
384}
385
386bool FillLayer::imagesIdentical(const FillLayer* layer1, const FillLayer* layer2)
387{
388 for (; layer1 && layer2; layer1 = layer1->next(), layer2 = layer2->next()) {
389 if (!arePointingToEqualData(layer1->image(), layer2->image()))
390 return false;
391 }
392
393 return !layer1 && !layer2;
394}
395
396TextStream& operator<<(TextStream& ts, FillSize fillSize)
397{
398 return ts << fillSize.type << " " << fillSize.size;
399}
400
401TextStream& operator<<(TextStream& ts, const FillLayer& layer)
402{
403 TextStream::GroupScope scope(ts);
404 ts << "fill-layer";
405
406 ts.startGroup();
407 ts << "position " << layer.xPosition() << " " << layer.yPosition();
408 ts.endGroup();
409
410 ts.dumpProperty("size", layer.size());
411
412 ts.startGroup();
413 ts << "background-origin " << layer.backgroundXOrigin() << " " << layer.backgroundYOrigin();
414 ts.endGroup();
415
416 ts.startGroup();
417 ts << "repeat " << layer.repeatX() << " " << layer.repeatY();
418 ts.endGroup();
419
420 ts.dumpProperty("clip", layer.clip());
421 ts.dumpProperty("origin", layer.origin());
422
423 ts.dumpProperty("composite", layer.composite());
424 ts.dumpProperty("blend-mode", layer.blendMode());
425 ts.dumpProperty("mask-type", layer.maskSourceType());
426
427 if (layer.next())
428 ts << *layer.next();
429
430 return ts;
431}
432
433} // namespace WebCore
434