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 | |
28 | namespace WebCore { |
29 | |
30 | struct 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 | |
44 | COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small); |
45 | |
46 | FillLayer::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 | |
78 | FillLayer::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 | |
112 | FillLayer::~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 | |
118 | FillLayer& 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 | |
157 | bool 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 | |
170 | void 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 | |
293 | void 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 | |
303 | static 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 | |
314 | void 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 | |
327 | bool FillLayer::clipOccludesNextLayers(bool firstLayer) const |
328 | { |
329 | if (firstLayer) |
330 | computeClipMax(); |
331 | return m_clip == m_clipMax; |
332 | } |
333 | |
334 | bool 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 | |
343 | bool 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 | |
352 | bool 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 | |
363 | bool FillLayer::hasRepeatXY() const |
364 | { |
365 | return repeatX() == FillRepeat::Repeat && repeatY() == FillRepeat::Repeat; |
366 | } |
367 | |
368 | bool 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 | |
377 | bool 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 | |
386 | bool 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 | |
396 | TextStream& operator<<(TextStream& ts, FillSize fillSize) |
397 | { |
398 | return ts << fillSize.type << " " << fillSize.size; |
399 | } |
400 | |
401 | TextStream& 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 | |