92c1af20a8bc27e274b47ba56d66e8934bc10538
[WebKit-https.git] / Source / WebCore / rendering / style / FillLayer.cpp
1 /*
2  * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 namespace WebCore {
26
27 struct SameSizeAsFillLayer {
28     FillLayer* m_next;
29
30     RefPtr<StyleImage> m_image;
31
32     Length m_xPosition;
33     Length m_yPosition;
34
35     LengthSize m_sizeLength;
36
37     unsigned m_bitfields: 32;
38
39 #if ENABLE(CSS3_BACKGROUND)
40     unsigned m_bitfields2: 1;
41 #endif
42 };
43
44 COMPILE_ASSERT(sizeof(FillLayer) == sizeof(SameSizeAsFillLayer), FillLayer_should_stay_small);
45
46 FillLayer::FillLayer(EFillLayerType type)
47     : m_next(0)
48     , m_image(FillLayer::initialFillImage(type))
49     , m_xPosition(FillLayer::initialFillXPosition(type))
50     , m_yPosition(FillLayer::initialFillYPosition(type))
51     , m_sizeLength(FillLayer::initialFillSizeLength(type))
52     , m_attachment(FillLayer::initialFillAttachment(type))
53     , m_clip(FillLayer::initialFillClip(type))
54     , m_origin(FillLayer::initialFillOrigin(type))
55     , m_repeatX(FillLayer::initialFillRepeatX(type))
56     , m_repeatY(FillLayer::initialFillRepeatY(type))
57     , m_composite(FillLayer::initialFillComposite(type))
58     , m_sizeType(SizeNone)
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 #if ENABLE(CSS3_BACKGROUND)
68     , m_backgroundOriginSet(false)
69     , m_backgroundXOrigin(LeftEdge)
70     , m_backgroundYOrigin(TopEdge)
71 #endif
72     , m_compositeSet(type == MaskFillLayer)
73     , m_type(type)
74 {
75 }
76
77 FillLayer::FillLayer(const FillLayer& o)
78     : m_next(o.m_next ? new FillLayer(*o.m_next) : 0)
79     , m_image(o.m_image)
80     , m_xPosition(o.m_xPosition)
81     , m_yPosition(o.m_yPosition)
82     , m_sizeLength(o.m_sizeLength)
83     , m_attachment(o.m_attachment)
84     , m_clip(o.m_clip)
85     , m_origin(o.m_origin)
86     , m_repeatX(o.m_repeatX)
87     , m_repeatY(o.m_repeatY)
88     , m_composite(o.m_composite)
89     , m_sizeType(o.m_sizeType)
90     , m_imageSet(o.m_imageSet)
91     , m_attachmentSet(o.m_attachmentSet)
92     , m_clipSet(o.m_clipSet)
93     , m_originSet(o.m_originSet)
94     , m_repeatXSet(o.m_repeatXSet)
95     , m_repeatYSet(o.m_repeatYSet)
96     , m_xPosSet(o.m_xPosSet)
97     , m_yPosSet(o.m_yPosSet)
98 #if ENABLE(CSS3_BACKGROUND)
99     , m_backgroundOriginSet(o.m_backgroundOriginSet)
100     , m_backgroundXOrigin(o.m_backgroundXOrigin)
101     , m_backgroundYOrigin(o.m_backgroundYOrigin)
102 #endif
103     , m_compositeSet(o.m_compositeSet)
104     , m_type(o.m_type)
105 {
106 }
107
108 FillLayer::~FillLayer()
109 {
110     delete m_next;
111 }
112
113 FillLayer& FillLayer::operator=(const FillLayer& o)
114 {
115     if (m_next != o.m_next) {
116         delete m_next;
117         m_next = o.m_next ? new FillLayer(*o.m_next) : 0;
118     }
119
120     m_image = o.m_image;
121     m_xPosition = o.m_xPosition;
122     m_yPosition = o.m_yPosition;
123 #if ENABLE(CSS3_BACKGROUND)
124     m_backgroundXOrigin = o.m_backgroundXOrigin;
125     m_backgroundYOrigin = o.m_backgroundYOrigin;
126     m_backgroundOriginSet = o.m_backgroundOriginSet;
127 #endif
128     m_sizeLength = o.m_sizeLength;
129     m_attachment = o.m_attachment;
130     m_clip = o.m_clip;
131     m_composite = o.m_composite;
132     m_origin = o.m_origin;
133     m_repeatX = o.m_repeatX;
134     m_repeatY = o.m_repeatY;
135     m_sizeType = o.m_sizeType;
136
137     m_imageSet = o.m_imageSet;
138     m_attachmentSet = o.m_attachmentSet;
139     m_clipSet = o.m_clipSet;
140     m_compositeSet = o.m_compositeSet;
141     m_originSet = o.m_originSet;
142     m_repeatXSet = o.m_repeatXSet;
143     m_repeatYSet = o.m_repeatYSet;
144     m_xPosSet = o.m_xPosSet;
145     m_yPosSet = o.m_yPosSet;
146     
147     m_type = o.m_type;
148
149     return *this;
150 }
151
152 bool FillLayer::operator==(const FillLayer& o) const
153 {
154     // We do not check the "isSet" booleans for each property, since those are only used during initial construction
155     // to propagate patterns into layers.  All layer comparisons happen after values have all been filled in anyway.
156     return StyleImage::imagesEquivalent(m_image.get(), o.m_image.get()) && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition
157 #if ENABLE(CSS3_BACKGROUND)
158             && m_backgroundXOrigin == o.m_backgroundXOrigin && m_backgroundYOrigin == o.m_backgroundYOrigin
159 #endif
160             && m_attachment == o.m_attachment && m_clip == o.m_clip
161             && m_composite == o.m_composite && m_origin == o.m_origin && m_repeatX == o.m_repeatX
162             && m_repeatY == o.m_repeatY && m_sizeType == o.m_sizeType && m_sizeLength == o.m_sizeLength
163             && m_type == o.m_type && ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
164 }
165
166 void FillLayer::fillUnsetProperties()
167 {
168     FillLayer* curr;
169     for (curr = this; curr && curr->isXPositionSet(); curr = curr->next()) { }
170     if (curr && curr != this) {
171         // We need to fill in the remaining values with the pattern specified.
172         for (FillLayer* pattern = this; curr; curr = curr->next()) {
173             curr->m_xPosition = pattern->m_xPosition;
174 #if ENABLE(CSS3_BACKGROUND)
175             if (pattern->isBackgroundOriginSet()) {
176                 curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
177                 curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
178             }
179 #endif
180             pattern = pattern->next();
181             if (pattern == curr || !pattern)
182                 pattern = this;
183         }
184     }
185     
186     for (curr = this; curr && curr->isYPositionSet(); curr = curr->next()) { }
187     if (curr && curr != this) {
188         // We need to fill in the remaining values with the pattern specified.
189         for (FillLayer* pattern = this; curr; curr = curr->next()) {
190             curr->m_yPosition = pattern->m_yPosition;
191 #if ENABLE(CSS3_BACKGROUND)
192             if (pattern->isBackgroundOriginSet()) {
193                 curr->m_backgroundXOrigin = pattern->m_backgroundXOrigin;
194                 curr->m_backgroundYOrigin = pattern->m_backgroundYOrigin;
195             }
196 #endif
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->isOriginSet(); 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_origin = pattern->m_origin;
241             pattern = pattern->next();
242             if (pattern == curr || !pattern)
243                 pattern = this;
244         }
245     }
246
247     for (curr = this; curr && curr->isRepeatXSet(); 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_repeatX = pattern->m_repeatX;
252             pattern = pattern->next();
253             if (pattern == curr || !pattern)
254                 pattern = this;
255         }
256     }
257
258     for (curr = this; curr && curr->isRepeatYSet(); 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_repeatY = pattern->m_repeatY;
263             pattern = pattern->next();
264             if (pattern == curr || !pattern)
265                 pattern = this;
266         }
267     }
268     
269     for (curr = this; curr && curr->isSizeSet(); 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_sizeType = pattern->m_sizeType;
274             curr->m_sizeLength = pattern->m_sizeLength;
275             pattern = pattern->next();
276             if (pattern == curr || !pattern)
277                 pattern = this;
278         }
279     }
280 }
281
282 void FillLayer::cullEmptyLayers()
283 {
284     FillLayer* next;
285     for (FillLayer* p = this; p; p = next) {
286         next = p->m_next;
287         if (next && !next->isImageSet()) {
288             delete next;
289             p->m_next = 0;
290             break;
291         }
292     }
293 }
294
295 static EFillBox clipMax(EFillBox clipA, EFillBox clipB)
296 {
297     if (clipA == BorderFillBox || clipB == BorderFillBox)
298         return BorderFillBox;
299     if (clipA == PaddingFillBox || clipB == PaddingFillBox)
300         return PaddingFillBox;
301     if (clipA == ContentFillBox || clipB == ContentFillBox)
302         return ContentFillBox;
303     return TextFillBox;
304 }
305
306 void FillLayer::computeClipMax() const
307 {
308     if (m_next) {
309         m_next->computeClipMax();
310         m_clipMax = clipMax(clip(), m_next->clip());
311     } else
312         m_clipMax = m_clip;
313 }
314
315 bool FillLayer::clipOccludesNextLayers(bool firstLayer) const
316 {
317     if (firstLayer)
318         computeClipMax();
319     return m_clip == m_clipMax;
320 }
321
322 bool FillLayer::containsImage(StyleImage* s) const
323 {
324     if (!s)
325         return false;
326     if (m_image && *s == *m_image)
327         return true;
328     if (m_next)
329         return m_next->containsImage(s);
330     return false;
331 }
332
333 bool FillLayer::imagesAreLoaded() const
334 {
335     const FillLayer* curr;
336     for (curr = this; curr; curr = curr->next()) {
337         if (curr->m_image && !curr->m_image->isLoaded())
338             return false;
339     }
340
341     return true;
342 }
343
344 bool FillLayer::hasOpaqueImage(const RenderObject* renderer) const
345 {
346     if (!m_image)
347         return false;
348
349     if (m_composite == CompositeClear || m_composite == CompositeCopy)
350         return true;
351
352     if (m_composite == CompositeSourceOver)
353         return !m_image->hasAlpha(renderer);
354
355     return false;
356 }
357
358 bool FillLayer::hasRepeatXY() const
359 {
360     return m_repeatX == RepeatFill && m_repeatY == RepeatFill;
361 }
362
363 } // namespace WebCore