220e657a90ab33af6c420b8ad11f51a1ae6d3136
[WebKit-https.git] / WebCore / rendering / style / RenderStyle.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 "RenderStyle.h"
24
25 #include "CSSPropertyNames.h"
26 #include "CSSStyleSelector.h"
27 #include "CachedImage.h"
28 #include "CounterContent.h"
29 #include "FontSelector.h"
30 #include "RenderArena.h"
31 #include "RenderObject.h"
32 #include "StyleImage.h"
33 #include <wtf/StdLibExtras.h>
34 #include <algorithm>
35
36 using namespace std;
37
38 namespace WebCore {
39
40 inline RenderStyle* defaultStyle()
41 {
42     static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef();
43     return s_defaultStyle;
44 }
45
46 PassRefPtr<RenderStyle> RenderStyle::create()
47 {
48     return adoptRef(new RenderStyle());
49 }
50
51 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
52 {
53     return adoptRef(new RenderStyle(true));
54 }
55
56 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
57 {
58     return adoptRef(new RenderStyle(*other));
59 }
60
61 ALWAYS_INLINE RenderStyle::RenderStyle()
62     : m_affectedByAttributeSelectors(false)
63     , m_unique(false)
64     , m_affectedByEmpty(false)
65     , m_emptyState(false)
66     , m_childrenAffectedByFirstChildRules(false)
67     , m_childrenAffectedByLastChildRules(false)
68     , m_childrenAffectedByDirectAdjacentRules(false)
69     , m_childrenAffectedByForwardPositionalRules(false)
70     , m_childrenAffectedByBackwardPositionalRules(false)
71     , m_firstChildState(false)
72     , m_lastChildState(false)
73     , m_childIndex(0)
74     , m_box(defaultStyle()->m_box)
75     , visual(defaultStyle()->visual)
76     , m_background(defaultStyle()->m_background)
77     , surround(defaultStyle()->surround)
78     , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
79     , rareInheritedData(defaultStyle()->rareInheritedData)
80     , inherited(defaultStyle()->inherited)
81 #if ENABLE(SVG)
82     , m_svgStyle(defaultStyle()->m_svgStyle)
83 #endif
84 {
85     setBitDefaults(); // Would it be faster to copy this from the default style?
86 }
87
88 ALWAYS_INLINE RenderStyle::RenderStyle(bool)
89     : m_affectedByAttributeSelectors(false)
90     , m_unique(false)
91     , m_affectedByEmpty(false)
92     , m_emptyState(false)
93     , m_childrenAffectedByFirstChildRules(false)
94     , m_childrenAffectedByLastChildRules(false)
95     , m_childrenAffectedByDirectAdjacentRules(false)
96     , m_childrenAffectedByForwardPositionalRules(false)
97     , m_childrenAffectedByBackwardPositionalRules(false)
98     , m_firstChildState(false)
99     , m_lastChildState(false)
100     , m_childIndex(0)
101 {
102     setBitDefaults();
103
104     m_box.init();
105     visual.init();
106     m_background.init();
107     surround.init();
108     rareNonInheritedData.init();
109     rareNonInheritedData.access()->flexibleBox.init();
110     rareNonInheritedData.access()->marquee.init();
111     rareNonInheritedData.access()->m_multiCol.init();
112     rareNonInheritedData.access()->m_transform.init();
113     rareInheritedData.init();
114     inherited.init();
115
116 #if ENABLE(SVG)
117     m_svgStyle.init();
118 #endif
119 }
120
121 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
122     : RefCounted<RenderStyle>()
123     , m_affectedByAttributeSelectors(false)
124     , m_unique(false)
125     , m_affectedByEmpty(false)
126     , m_emptyState(false)
127     , m_childrenAffectedByFirstChildRules(false)
128     , m_childrenAffectedByLastChildRules(false)
129     , m_childrenAffectedByDirectAdjacentRules(false)
130     , m_childrenAffectedByForwardPositionalRules(false)
131     , m_childrenAffectedByBackwardPositionalRules(false)
132     , m_firstChildState(false)
133     , m_lastChildState(false)
134     , m_childIndex(0)
135     , m_box(o.m_box)
136     , visual(o.visual)
137     , m_background(o.m_background)
138     , surround(o.surround)
139     , rareNonInheritedData(o.rareNonInheritedData)
140     , rareInheritedData(o.rareInheritedData)
141     , inherited(o.inherited)
142 #if ENABLE(SVG)
143     , m_svgStyle(o.m_svgStyle)
144 #endif
145     , inherited_flags(o.inherited_flags)
146     , noninherited_flags(o.noninherited_flags)
147 {
148 }
149
150 void RenderStyle::inheritFrom(const RenderStyle* inheritParent)
151 {
152     rareInheritedData = inheritParent->rareInheritedData;
153     inherited = inheritParent->inherited;
154     inherited_flags = inheritParent->inherited_flags;
155 #if ENABLE(SVG)
156     if (m_svgStyle != inheritParent->m_svgStyle)
157         m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
158 #endif
159 }
160
161 RenderStyle::~RenderStyle()
162 {
163 }
164
165 bool RenderStyle::operator==(const RenderStyle& o) const
166 {
167     // compare everything except the pseudoStyle pointer
168     return inherited_flags == o.inherited_flags &&
169             noninherited_flags == o.noninherited_flags &&
170             m_box == o.m_box &&
171             visual == o.visual &&
172             m_background == o.m_background &&
173             surround == o.surround &&
174             rareNonInheritedData == o.rareNonInheritedData &&
175             rareInheritedData == o.rareInheritedData &&
176             inherited == o.inherited
177 #if ENABLE(SVG)
178             && m_svgStyle == o.m_svgStyle
179 #endif
180             ;
181 }
182
183 bool RenderStyle::isStyleAvailable() const
184 {
185     return this != CSSStyleSelector::styleNotYetAvailable();
186 }
187
188 static inline int pseudoBit(PseudoId pseudo)
189 {
190     return 1 << (pseudo - 1);
191 }
192
193 bool RenderStyle::hasAnyPublicPseudoStyles() const
194 {
195     return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
196 }
197
198 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
199 {
200     ASSERT(pseudo > NOPSEUDO);
201     ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
202     return pseudoBit(pseudo) & noninherited_flags._pseudoBits;
203 }
204
205 void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
206 {
207     ASSERT(pseudo > NOPSEUDO);
208     ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
209     noninherited_flags._pseudoBits |= pseudoBit(pseudo);
210 }
211
212 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
213 {
214     ASSERT(styleType() != VISITED_LINK);
215
216     if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
217         return 0;
218
219     if (styleType() != NOPSEUDO) {
220         if (pid == VISITED_LINK)
221             return m_cachedPseudoStyles->at(0)->styleType() == VISITED_LINK ? m_cachedPseudoStyles->at(0).get() : 0;
222         return 0;
223     }
224
225     for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
226         RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
227         if (pseudoStyle->styleType() == pid)
228             return pseudoStyle;
229     }
230
231     return 0;
232 }
233
234 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
235 {
236     if (!pseudo)
237         return 0;
238     
239     RenderStyle* result = pseudo.get();
240
241     if (!m_cachedPseudoStyles)
242         m_cachedPseudoStyles.set(new PseudoStyleCache);
243
244     m_cachedPseudoStyles->append(pseudo);
245
246     return result;
247 }
248
249 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
250 {
251     return inherited_flags != other->inherited_flags ||
252            inherited != other->inherited ||
253 #if ENABLE(SVG)
254            m_svgStyle->inheritedNotEqual(other->m_svgStyle.get()) ||
255 #endif
256            rareInheritedData != other->rareInheritedData;
257 }
258
259 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
260 {
261     // If any unit types are different, then we can't guarantee
262     // that this was just a movement.
263     if (a.left().type() != b.left().type() ||
264         a.right().type() != b.right().type() ||
265         a.top().type() != b.top().type() ||
266         a.bottom().type() != b.bottom().type())
267         return false;
268
269     // Only one unit can be non-auto in the horizontal direction and
270     // in the vertical direction.  Otherwise the adjustment of values
271     // is changing the size of the box.
272     if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
273         return false;
274     if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
275         return false;
276
277     // One of the units is fixed or percent in both directions and stayed
278     // that way in the new style.  Therefore all we are doing is moving.
279     return true;
280 }
281
282 /*
283   compares two styles. The result gives an idea of the action that
284   needs to be taken when replacing the old style with a new one.
285
286   CbLayout: The containing block of the object needs a relayout.
287   Layout: the RenderObject needs a relayout after the style change
288   Visible: The change is visible, but no relayout is needed
289   NonVisible: The object does need neither repaint nor relayout after
290        the change.
291
292   ### TODO:
293   A lot can be optimised here based on the display type, lots of
294   optimisations are unimplemented, and currently result in the
295   worst case result causing a relayout of the containing block.
296 */
297 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
298 {
299     changedContextSensitiveProperties = ContextSensitivePropertyNone;
300
301 #if ENABLE(SVG)
302     // This is horribly inefficient.  Eventually we'll have to integrate
303     // this more directly by calling: Diff svgDiff = svgStyle->diff(other)
304     // and then checking svgDiff and returning from the appropriate places below.
305     if (m_svgStyle != other->m_svgStyle)
306         return StyleDifferenceLayout;
307 #endif
308
309     if (m_box->width() != other->m_box->width() ||
310         m_box->minWidth() != other->m_box->minWidth() ||
311         m_box->maxWidth() != other->m_box->maxWidth() ||
312         m_box->height() != other->m_box->height() ||
313         m_box->minHeight() != other->m_box->minHeight() ||
314         m_box->maxHeight() != other->m_box->maxHeight())
315         return StyleDifferenceLayout;
316
317     if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
318         return StyleDifferenceLayout;
319
320     if (m_box->boxSizing() != other->m_box->boxSizing())
321         return StyleDifferenceLayout;
322
323     if (surround->margin != other->surround->margin)
324         return StyleDifferenceLayout;
325
326     if (surround->padding != other->surround->padding)
327         return StyleDifferenceLayout;
328
329     if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
330         if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance ||
331             rareNonInheritedData->marginTopCollapse != other->rareNonInheritedData->marginTopCollapse ||
332             rareNonInheritedData->marginBottomCollapse != other->rareNonInheritedData->marginBottomCollapse ||
333             rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp ||
334             rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
335             return StyleDifferenceLayout;
336
337         if (rareNonInheritedData->flexibleBox.get() != other->rareNonInheritedData->flexibleBox.get() &&
338             *rareNonInheritedData->flexibleBox.get() != *other->rareNonInheritedData->flexibleBox.get())
339             return StyleDifferenceLayout;
340
341         // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
342         if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
343             return StyleDifferenceLayout;
344
345         if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
346             return StyleDifferenceLayout;
347
348         if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get() &&
349             *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
350             return StyleDifferenceLayout;
351
352         if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get() &&
353             *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) {
354 #if USE(ACCELERATED_COMPOSITING)
355             changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
356             // Don't return; keep looking for another change
357 #else
358             return StyleDifferenceLayout;
359 #endif
360         }
361
362 #if !USE(ACCELERATED_COMPOSITING)
363         if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
364             if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D ||
365                 rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility ||
366                 rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective ||
367                 rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX ||
368                 rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
369                 return StyleDifferenceLayout;
370         }
371 #endif
372
373 #if ENABLE(DASHBOARD_SUPPORT)
374         // If regions change, trigger a relayout to re-calc regions.
375         if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
376             return StyleDifferenceLayout;
377 #endif
378     }
379
380     if (rareInheritedData.get() != other->rareInheritedData.get()) {
381         if (rareInheritedData->highlight != other->rareInheritedData->highlight ||
382             rareInheritedData->indent != other->rareInheritedData->indent ||
383             rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom ||
384             rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust ||
385             rareInheritedData->wordBreak != other->rareInheritedData->wordBreak ||
386             rareInheritedData->wordWrap != other->rareInheritedData->wordWrap ||
387             rareInheritedData->nbspMode != other->rareInheritedData->nbspMode ||
388             rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak ||
389             rareInheritedData->textSecurity != other->rareInheritedData->textSecurity)
390             return StyleDifferenceLayout;
391
392         if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
393             return StyleDifferenceLayout;
394
395         if (textStrokeWidth() != other->textStrokeWidth())
396             return StyleDifferenceLayout;
397     }
398
399     if (inherited->line_height != other->inherited->line_height ||
400         inherited->list_style_image != other->inherited->list_style_image ||
401         inherited->font != other->inherited->font ||
402         inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing ||
403         inherited->vertical_border_spacing != other->inherited->vertical_border_spacing ||
404         inherited_flags._box_direction != other->inherited_flags._box_direction ||
405         inherited_flags._visuallyOrdered != other->inherited_flags._visuallyOrdered ||
406         inherited_flags._htmlHacks != other->inherited_flags._htmlHacks ||
407         noninherited_flags._position != other->noninherited_flags._position ||
408         noninherited_flags._floating != other->noninherited_flags._floating ||
409         noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
410         return StyleDifferenceLayout;
411
412
413     if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
414         if (inherited_flags._border_collapse != other->inherited_flags._border_collapse ||
415             inherited_flags._empty_cells != other->inherited_flags._empty_cells ||
416             inherited_flags._caption_side != other->inherited_flags._caption_side ||
417             noninherited_flags._table_layout != other->noninherited_flags._table_layout)
418             return StyleDifferenceLayout;
419
420         // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
421         // does not, so these style differences can be width differences.
422         if (inherited_flags._border_collapse &&
423             ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE) ||
424              (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN) ||
425              (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE) ||
426              (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN) ||
427              (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE) ||
428              (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN) ||
429              (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE) ||
430              (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
431             return StyleDifferenceLayout;
432     }
433
434     if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
435         if (inherited_flags._list_style_type != other->inherited_flags._list_style_type ||
436             inherited_flags._list_style_position != other->inherited_flags._list_style_position)
437             return StyleDifferenceLayout;
438     }
439
440     if (inherited_flags._text_align != other->inherited_flags._text_align ||
441         inherited_flags._text_transform != other->inherited_flags._text_transform ||
442         inherited_flags._direction != other->inherited_flags._direction ||
443         inherited_flags._white_space != other->inherited_flags._white_space ||
444         noninherited_flags._clear != other->noninherited_flags._clear)
445         return StyleDifferenceLayout;
446
447     // Overflow returns a layout hint.
448     if (noninherited_flags._overflowX != other->noninherited_flags._overflowX ||
449         noninherited_flags._overflowY != other->noninherited_flags._overflowY)
450         return StyleDifferenceLayout;
451
452     // If our border widths change, then we need to layout.  Other changes to borders
453     // only necessitate a repaint.
454     if (borderLeftWidth() != other->borderLeftWidth() ||
455         borderTopWidth() != other->borderTopWidth() ||
456         borderBottomWidth() != other->borderBottomWidth() ||
457         borderRightWidth() != other->borderRightWidth())
458         return StyleDifferenceLayout;
459
460     // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
461     const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
462     const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
463     if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
464         return StyleDifferenceLayout;
465     if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement ||
466         rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset)
467         return StyleDifferenceLayout;
468
469     if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) ||
470         (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
471         // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
472         return StyleDifferenceLayout;
473     }
474
475     // Make sure these left/top/right/bottom checks stay below all layout checks and above
476     // all visible checks.
477     if (position() != StaticPosition) {
478         if (surround->offset != other->surround->offset) {
479              // Optimize for the case where a positioned layer is moving but not changing size.
480             if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
481                 return StyleDifferenceLayoutPositionedMovementOnly;
482
483             // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we
484             // can stop doing a layout when relative positioned objects move.  In particular, we'll need
485             // to update scrolling positions and figure out how to do a repaint properly of the updated layer.
486             //if (other->position() == RelativePosition)
487             //    return RepaintLayer;
488             //else
489                 return StyleDifferenceLayout;
490         } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() ||
491                  visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
492             return StyleDifferenceRepaintLayer;
493     }
494
495     if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
496 #if USE(ACCELERATED_COMPOSITING)
497         changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
498         // Don't return; keep looking for another change.
499 #else
500         return StyleDifferenceRepaintLayer;
501 #endif
502     }
503
504     if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask ||
505         rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
506         return StyleDifferenceRepaintLayer;
507
508     if (inherited->color != other->inherited->color ||
509         inherited_flags._visibility != other->inherited_flags._visibility ||
510         inherited_flags._text_decorations != other->inherited_flags._text_decorations ||
511         inherited_flags._force_backgrounds_to_white != other->inherited_flags._force_backgrounds_to_white ||
512         inherited_flags._insideLink != other->inherited_flags._insideLink ||
513         surround->border != other->surround->border ||
514         *m_background.get() != *other->m_background.get() ||
515         visual->textDecoration != other->visual->textDecoration ||
516         rareInheritedData->userModify != other->rareInheritedData->userModify ||
517         rareInheritedData->userSelect != other->rareInheritedData->userSelect ||
518         rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag ||
519         rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit ||
520         rareInheritedData->textFillColor != other->rareInheritedData->textFillColor ||
521         rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor)
522         return StyleDifferenceRepaint;
523
524 #if USE(ACCELERATED_COMPOSITING)
525     if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
526         if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D ||
527             rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility ||
528             rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective ||
529             rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX ||
530             rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
531             return StyleDifferenceRecompositeLayer;
532     }
533 #endif
534
535     // Cursors are not checked, since they will be set appropriately in response to mouse events,
536     // so they don't need to cause any repaint or layout.
537
538     // Animations don't need to be checked either.  We always set the new style on the RenderObject, so we will get a chance to fire off
539     // the resulting transition properly.
540     return StyleDifferenceEqual;
541 }
542
543 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
544 {
545     StyleVisualData* data = visual.access();
546     data->clip.m_top = top;
547     data->clip.m_right = right;
548     data->clip.m_bottom = bottom;
549     data->clip.m_left = left;
550 }
551
552 void RenderStyle::addCursor(CachedImage* image, const IntPoint& hotSpot)
553 {
554     if (!rareInheritedData.access()->cursorData)
555         rareInheritedData.access()->cursorData = CursorList::create();
556     rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot));
557 }
558
559 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
560 {
561     rareInheritedData.access()->cursorData = other;
562 }
563
564 void RenderStyle::clearCursorList()
565 {
566     if (rareInheritedData->cursorData)
567         rareInheritedData.access()->cursorData = 0;
568 }
569
570 void RenderStyle::clearContent()
571 {
572     if (rareNonInheritedData->m_content)
573         rareNonInheritedData->m_content->clear();
574 }
575
576 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
577 {
578     if (!image)
579         return; // The object is null. Nothing to do. Just bail.
580
581     OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
582     ContentData* lastContent = content.get();
583     while (lastContent && lastContent->next())
584         lastContent = lastContent->next();
585
586     bool reuseContent = !add;
587     ContentData* newContentData;
588     if (reuseContent && content) {
589         content->clear();
590         newContentData = content.release();
591     } else
592         newContentData = new ContentData;
593
594     if (lastContent && !reuseContent)
595         lastContent->setNext(newContentData);
596     else
597         content.set(newContentData);
598
599     newContentData->setImage(image);
600 }
601
602 void RenderStyle::setContent(PassRefPtr<StringImpl> s, bool add)
603 {
604     if (!s)
605         return; // The string is null. Nothing to do. Just bail.
606
607     OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
608     ContentData* lastContent = content.get();
609     while (lastContent && lastContent->next())
610         lastContent = lastContent->next();
611
612     bool reuseContent = !add;
613     if (add && lastContent) {
614         if (lastContent->isText()) {
615             // We can augment the existing string and share this ContentData node.
616             String newStr = lastContent->text();
617             newStr.append(s.get());
618             lastContent->setText(newStr.impl());
619             return;
620         }
621     }
622
623     ContentData* newContentData = 0;
624     if (reuseContent && content) {
625         content->clear();
626         newContentData = content.release();
627     } else
628         newContentData = new ContentData;
629
630     if (lastContent && !reuseContent)
631         lastContent->setNext(newContentData);
632     else
633         content.set(newContentData);
634
635     newContentData->setText(s);
636 }
637
638 void RenderStyle::setContent(CounterContent* c, bool add)
639 {
640     if (!c)
641         return;
642
643     OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
644     ContentData* lastContent = content.get();
645     while (lastContent && lastContent->next())
646         lastContent = lastContent->next();
647
648     bool reuseContent = !add;
649     ContentData* newContentData = 0;
650     if (reuseContent && content) {
651         content->clear();
652         newContentData = content.release();
653     } else
654         newContentData = new ContentData;
655
656     if (lastContent && !reuseContent)
657         lastContent->setNext(newContentData);
658     else
659         content.set(newContentData);
660
661     newContentData->setCounter(c);
662 }
663
664 void RenderStyle::applyTransform(TransformationMatrix& transform, const IntSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
665 {
666     // transform-origin brackets the transform with translate operations.
667     // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
668     // in that case.
669     bool applyTransformOrigin = false;
670     unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size();
671     unsigned i;
672     if (applyOrigin == IncludeTransformOrigin) {
673         for (i = 0; i < s; i++) {
674             TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType();
675             if (type != TransformOperation::TRANSLATE_X &&
676                     type != TransformOperation::TRANSLATE_Y &&
677                     type != TransformOperation::TRANSLATE && 
678                     type != TransformOperation::TRANSLATE_Z && 
679                     type != TransformOperation::TRANSLATE_3D
680                     ) {
681                 applyTransformOrigin = true;
682                 break;
683             }
684         }
685     }
686
687     if (applyTransformOrigin) {
688         transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ());
689     }
690
691     for (i = 0; i < s; i++)
692         rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize);
693
694     if (applyTransformOrigin) {
695         transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ());
696     }
697 }
698
699 #if ENABLE(XBL)
700 void RenderStyle::addBindingURI(StringImpl* uri)
701 {
702     BindingURI* binding = new BindingURI(uri);
703     if (!bindingURIs())
704         SET_VAR(rareNonInheritedData, bindingURI, binding)
705     else
706         for (BindingURI* b = bindingURIs(); b; b = b->next()) {
707             if (!b->next())
708                 b->setNext(binding);
709         }
710 }
711 #endif
712
713 void RenderStyle::setTextShadow(ShadowData* val, bool add)
714 {
715     ASSERT(!val || (!val->spread() && val->style() == Normal));
716
717     StyleRareInheritedData* rareData = rareInheritedData.access();
718     if (!add) {
719         delete rareData->textShadow;
720         rareData->textShadow = val;
721         return;
722     }
723
724     val->setNext(rareData->textShadow);
725     rareData->textShadow = val;
726 }
727
728 void RenderStyle::setBoxShadow(ShadowData* shadowData, bool add)
729 {
730     StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
731     if (!add) {
732         rareData->m_boxShadow.set(shadowData);
733         return;
734     }
735
736     shadowData->setNext(rareData->m_boxShadow.release());
737     rareData->m_boxShadow.set(shadowData);
738 }
739
740 void RenderStyle::getBorderRadiiForRect(const IntRect& r, IntSize& topLeft, IntSize& topRight, IntSize& bottomLeft, IntSize& bottomRight) const
741 {
742     topLeft = surround->border.topLeft();
743     topRight = surround->border.topRight();
744     
745     bottomLeft = surround->border.bottomLeft();
746     bottomRight = surround->border.bottomRight();
747
748     // Constrain corner radii using CSS3 rules:
749     // http://www.w3.org/TR/css3-background/#the-border-radius
750     
751     float factor = 1;
752     unsigned radiiSum;
753
754     // top
755     radiiSum = static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()); // Casts to avoid integer overflow.
756     if (radiiSum > static_cast<unsigned>(r.width()))
757         factor = min(static_cast<float>(r.width()) / radiiSum, factor);
758
759     // bottom
760     radiiSum = static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width());
761     if (radiiSum > static_cast<unsigned>(r.width()))
762         factor = min(static_cast<float>(r.width()) / radiiSum, factor);
763     
764     // left
765     radiiSum = static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height());
766     if (radiiSum > static_cast<unsigned>(r.height()))
767         factor = min(static_cast<float>(r.height()) / radiiSum, factor);
768     
769     // right
770     radiiSum = static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height());
771     if (radiiSum > static_cast<unsigned>(r.height()))
772         factor = min(static_cast<float>(r.height()) / radiiSum, factor);
773     
774     // Scale all radii by f if necessary.
775     if (factor < 1) {
776         // If either radius on a corner becomes zero, reset both radii on that corner.
777         topLeft.scale(factor);
778         if (!topLeft.width() || !topLeft.height())
779             topLeft = IntSize();
780         topRight.scale(factor);
781         if (!topRight.width() || !topRight.height())
782             topRight = IntSize();
783         bottomLeft.scale(factor);
784         if (!bottomLeft.width() || !bottomLeft.height())
785             bottomLeft = IntSize();
786         bottomRight.scale(factor);
787         if (!bottomRight.width() || !bottomRight.height())
788             bottomRight = IntSize();
789     }
790 }
791
792 const CounterDirectiveMap* RenderStyle::counterDirectives() const
793 {
794     return rareNonInheritedData->m_counterDirectives.get();
795 }
796
797 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
798 {
799     OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
800     if (!map)
801         map.set(new CounterDirectiveMap);
802     return *map.get();
803 }
804
805 #if ENABLE(DASHBOARD_SUPPORT)
806 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
807 {
808     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
809     return emptyList;
810 }
811
812 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
813 {
814     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
815     static bool noneListInitialized = false;
816
817     if (!noneListInitialized) {
818         StyleDashboardRegion region;
819         region.label = "";
820         region.offset.m_top  = Length();
821         region.offset.m_right = Length();
822         region.offset.m_bottom = Length();
823         region.offset.m_left = Length();
824         region.type = StyleDashboardRegion::None;
825         noneList.append(region);
826         noneListInitialized = true;
827     }
828     return noneList;
829 }
830 #endif
831
832 void RenderStyle::adjustAnimations()
833 {
834     AnimationList* animationList = rareNonInheritedData->m_animations.get();
835     if (!animationList)
836         return;
837
838     // Get rid of empty animations and anything beyond them
839     for (size_t i = 0; i < animationList->size(); ++i) {
840         if (animationList->animation(i)->isEmpty()) {
841             animationList->resize(i);
842             break;
843         }
844     }
845
846     if (animationList->isEmpty()) {
847         clearAnimations();
848         return;
849     }
850
851     // Repeat patterns into layers that don't have some properties set.
852     animationList->fillUnsetProperties();
853 }
854
855 void RenderStyle::adjustTransitions()
856 {
857     AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
858     if (!transitionList)
859         return;
860
861     // Get rid of empty transitions and anything beyond them
862     for (size_t i = 0; i < transitionList->size(); ++i) {
863         if (transitionList->animation(i)->isEmpty()) {
864             transitionList->resize(i);
865             break;
866         }
867     }
868
869     if (transitionList->isEmpty()) {
870         clearTransitions();
871         return;
872     }
873
874     // Repeat patterns into layers that don't have some properties set.
875     transitionList->fillUnsetProperties();
876
877     // Make sure there are no duplicate properties. This is an O(n^2) algorithm
878     // but the lists tend to be very short, so it is probably ok
879     for (size_t i = 0; i < transitionList->size(); ++i) {
880         for (size_t j = i+1; j < transitionList->size(); ++j) {
881             if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
882                 // toss i
883                 transitionList->remove(i);
884                 j = i;
885             }
886         }
887     }
888 }
889
890 AnimationList* RenderStyle::accessAnimations()
891 {
892     if (!rareNonInheritedData.access()->m_animations)
893         rareNonInheritedData.access()->m_animations.set(new AnimationList());
894     return rareNonInheritedData->m_animations.get();
895 }
896
897 AnimationList* RenderStyle::accessTransitions()
898 {
899     if (!rareNonInheritedData.access()->m_transitions)
900         rareNonInheritedData.access()->m_transitions.set(new AnimationList());
901     return rareNonInheritedData->m_transitions.get();
902 }
903
904 const Animation* RenderStyle::transitionForProperty(int property) const
905 {
906     if (transitions()) {
907         for (size_t i = 0; i < transitions()->size(); ++i) {
908             const Animation* p = transitions()->animation(i);
909             if (p->property() == cAnimateAll || p->property() == property) {
910                 return p;
911             }
912         }
913     }
914     return 0;
915 }
916
917 void RenderStyle::setBlendedFontSize(int size)
918 {
919     FontDescription desc(fontDescription());
920     desc.setSpecifiedSize(size);
921     desc.setComputedSize(size);
922     setFontDescription(desc);
923     font().update(font().fontSelector());
924 }
925
926 void RenderStyle::getBoxShadowExtent(int &top, int &right, int &bottom, int &left) const
927 {
928     top = 0;
929     right = 0;
930     bottom = 0;
931     left = 0;
932
933     for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
934         if (boxShadow->style() == Inset)
935             continue;
936         int blurAndSpread = boxShadow->blur() + boxShadow->spread();
937
938         top = min(top, boxShadow->y() - blurAndSpread);
939         right = max(right, boxShadow->x() + blurAndSpread);
940         bottom = max(bottom, boxShadow->y() + blurAndSpread);
941         left = min(left, boxShadow->x() - blurAndSpread);
942     }
943 }
944
945 void RenderStyle::getBoxShadowHorizontalExtent(int &left, int &right) const
946 {
947     left = 0;
948     right = 0;
949
950     for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
951         if (boxShadow->style() == Inset)
952             continue;
953         int blurAndSpread = boxShadow->blur() + boxShadow->spread();
954
955         left = min(left, boxShadow->x() - blurAndSpread);
956         right = max(right, boxShadow->x() + blurAndSpread);
957     }
958 }
959
960 void RenderStyle::getBoxShadowVerticalExtent(int &top, int &bottom) const
961 {
962     top = 0;
963     bottom = 0;
964
965     for (const ShadowData* boxShadow = this->boxShadow(); boxShadow; boxShadow = boxShadow->next()) {
966         if (boxShadow->style() == Inset)
967             continue;
968         int blurAndSpread = boxShadow->blur() + boxShadow->spread();
969
970         top = min(top, boxShadow->y() - blurAndSpread);
971         bottom = max(bottom, boxShadow->y() + blurAndSpread);
972     }
973 }
974
975 static EBorderStyle borderStyleForColorProperty(const RenderStyle* style, int colorProperty)
976 {
977     EBorderStyle borderStyle;
978     switch (colorProperty) {
979     case CSSPropertyBorderLeftColor:
980         borderStyle = style->borderLeftStyle();
981         break;
982     case CSSPropertyBorderRightColor:
983         borderStyle = style->borderRightStyle();
984         break;
985     case CSSPropertyBorderTopColor:
986         borderStyle = style->borderTopStyle();
987         break;
988     case CSSPropertyBorderBottomColor:
989         borderStyle = style->borderBottomStyle();
990         break;
991     default:
992         borderStyle = BNONE;
993         break;
994     }
995     return borderStyle;
996 }
997
998 const Color RenderStyle::colorIncludingFallback(int colorProperty, EBorderStyle borderStyle) const
999 {
1000     Color result;
1001     switch (colorProperty) {
1002     case CSSPropertyBackgroundColor:
1003         return backgroundColor(); // Background color doesn't fall back.
1004     case CSSPropertyBorderLeftColor:
1005         result = borderLeftColor();
1006         borderStyle = borderLeftStyle();
1007         break;
1008     case CSSPropertyBorderRightColor:
1009         result = borderRightColor();
1010         borderStyle = borderRightStyle();
1011         break;
1012     case CSSPropertyBorderTopColor:
1013         result = borderTopColor();
1014         borderStyle = borderTopStyle();
1015         break;
1016     case CSSPropertyBorderBottomColor:
1017         result = borderBottomColor();
1018         borderStyle = borderBottomStyle();
1019         break;
1020     case CSSPropertyColor:
1021         result = color();
1022         break;
1023     case CSSPropertyOutlineColor:
1024         result = outlineColor();
1025         break;
1026     case CSSPropertyWebkitColumnRuleColor:
1027         result = columnRuleColor();
1028         break;
1029     case CSSPropertyWebkitTextFillColor:
1030         result = textFillColor();
1031         break;
1032     case CSSPropertyWebkitTextStrokeColor:
1033         result = textStrokeColor();
1034         break;
1035     default:
1036         ASSERT_NOT_REACHED();
1037         break;
1038     }
1039
1040     if (!result.isValid()) {
1041         if ((colorProperty == CSSPropertyBorderLeftColor || colorProperty == CSSPropertyBorderRightColor
1042             || colorProperty == CSSPropertyBorderTopColor || colorProperty == CSSPropertyBorderBottomColor)
1043             && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1044             result.setRGB(238, 238, 238);
1045         else
1046             result = color();
1047     }
1048
1049     return result;
1050 }
1051
1052 const Color RenderStyle::visitedDependentColor(int colorProperty) const
1053 {
1054     EBorderStyle borderStyle = borderStyleForColorProperty(this, colorProperty);
1055     Color unvisitedColor = colorIncludingFallback(colorProperty, borderStyle);
1056     if (insideLink() != InsideVisitedLink)
1057         return unvisitedColor;
1058
1059     RenderStyle* visitedStyle = getCachedPseudoStyle(VISITED_LINK);
1060     if (!visitedStyle)
1061         return unvisitedColor;
1062     Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle);
1063
1064     // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1065     return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1066 }
1067
1068 } // namespace WebCore