SVG should support transform-origin and relative values
[WebKit-https.git] / Source / WebCore / rendering / style / RenderStyle.cpp
1 /*
2  * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
4  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "RenderStyle.h"
25
26 #include "ContentData.h"
27 #include "CursorList.h"
28 #include "CSSPropertyNames.h"
29 #include "CSSStyleSelector.h"
30 #include "CSSWrapShapes.h"
31 #include "FontSelector.h"
32 #include "QuotesData.h"
33 #include "RenderArena.h"
34 #include "RenderObject.h"
35 #include "ScaleTransformOperation.h"
36 #include "ShadowData.h"
37 #include "StyleImage.h"
38 #if ENABLE(TOUCH_EVENTS)
39 #include "RenderTheme.h"
40 #endif
41 #include <wtf/StdLibExtras.h>
42 #include <algorithm>
43
44 using namespace std;
45
46 namespace WebCore {
47
48 struct SameSizeAsBorderValue {
49     Color m_color;
50     unsigned m_width;
51 };
52
53 COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow);
54
55 struct SameSizeAsRenderStyle : public RefCounted<SameSizeAsRenderStyle> {
56     unsigned m_bitfields;
57
58     void* dataRefs[7];
59     void* ownPtrs[1];
60 #if ENABLE(SVG)
61     void* dataRefSvgStyle;
62 #endif
63     struct InheritedFlags {
64         unsigned m_bitfields[2];
65     } inherited_flags;
66
67     struct NonInheritedFlags {
68         unsigned m_bitfields[2];
69     } noninherited_flags;
70 };
71
72 COMPILE_ASSERT(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), RenderStyle_should_stay_small);
73
74 inline RenderStyle* defaultStyle()
75 {
76     static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().leakRef();
77     return s_defaultStyle;
78 }
79
80 PassRefPtr<RenderStyle> RenderStyle::create()
81 {
82     return adoptRef(new RenderStyle());
83 }
84
85 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
86 {
87     return adoptRef(new RenderStyle(true));
88 }
89
90 PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyle(const RenderStyle* parentStyle)
91 {
92     RefPtr<RenderStyle> newStyle = RenderStyle::create();
93     newStyle->inheritFrom(parentStyle);
94     newStyle->inheritUnicodeBidiFrom(parentStyle);
95     return newStyle;
96 }
97
98 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
99 {
100     return adoptRef(new RenderStyle(*other));
101 }
102
103 ALWAYS_INLINE RenderStyle::RenderStyle()
104     : m_box(defaultStyle()->m_box)
105     , visual(defaultStyle()->visual)
106     , m_background(defaultStyle()->m_background)
107     , surround(defaultStyle()->surround)
108     , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
109     , rareInheritedData(defaultStyle()->rareInheritedData)
110     , inherited(defaultStyle()->inherited)
111 #if ENABLE(SVG)
112     , m_svgStyle(defaultStyle()->m_svgStyle)
113 #endif
114 {
115     setBitDefaults(); // Would it be faster to copy this from the default style?
116     COMPILE_ASSERT((sizeof(InheritedFlags) <= 8), InheritedFlags_does_not_grow);
117     COMPILE_ASSERT((sizeof(NonInheritedFlags) <= 8), NonInheritedFlags_does_not_grow);
118 }
119
120 ALWAYS_INLINE RenderStyle::RenderStyle(bool)
121 {
122     setBitDefaults();
123
124     m_box.init();
125     visual.init();
126     m_background.init();
127     surround.init();
128     rareNonInheritedData.init();
129     rareNonInheritedData.access()->m_deprecatedFlexibleBox.init();
130     rareNonInheritedData.access()->m_flexibleBox.init();
131     rareNonInheritedData.access()->m_marquee.init();
132     rareNonInheritedData.access()->m_multiCol.init();
133     rareNonInheritedData.access()->m_transform.init();
134 #if ENABLE(CSS_FILTERS)
135     rareNonInheritedData.access()->m_filter.init();
136 #endif
137 #if ENABLE(CSS_GRID_LAYOUT)
138     rareNonInheritedData.access()->m_grid.init();
139     rareNonInheritedData.access()->m_gridItem.init();
140 #endif
141     rareInheritedData.init();
142     inherited.init();
143
144 #if ENABLE(SVG)
145     m_svgStyle.init();
146 #endif
147 }
148
149 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
150     : RefCounted<RenderStyle>()
151     , m_box(o.m_box)
152     , visual(o.visual)
153     , m_background(o.m_background)
154     , surround(o.surround)
155     , rareNonInheritedData(o.rareNonInheritedData)
156     , rareInheritedData(o.rareInheritedData)
157     , inherited(o.inherited)
158 #if ENABLE(SVG)
159     , m_svgStyle(o.m_svgStyle)
160 #endif
161     , inherited_flags(o.inherited_flags)
162     , noninherited_flags(o.noninherited_flags)
163 {
164 }
165
166 void RenderStyle::inheritFrom(const RenderStyle* inheritParent)
167 {
168     rareInheritedData = inheritParent->rareInheritedData;
169     inherited = inheritParent->inherited;
170     inherited_flags = inheritParent->inherited_flags;
171 #if ENABLE(SVG)
172     if (m_svgStyle != inheritParent->m_svgStyle)
173         m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
174 #endif
175 }
176
177 void RenderStyle::copyNonInheritedFrom(const RenderStyle* other)
178 {
179     m_box = other->m_box;
180     visual = other->visual;
181     m_background = other->m_background;
182     surround = other->surround;
183     rareNonInheritedData = other->rareNonInheritedData;
184     // The flags are copied one-by-one because noninherited_flags contains a bunch of stuff other than real style data.
185     noninherited_flags._effectiveDisplay = other->noninherited_flags._effectiveDisplay;
186     noninherited_flags._originalDisplay = other->noninherited_flags._originalDisplay;
187     noninherited_flags._overflowX = other->noninherited_flags._overflowX;
188     noninherited_flags._overflowY = other->noninherited_flags._overflowY;
189     noninherited_flags._vertical_align = other->noninherited_flags._vertical_align;
190     noninherited_flags._clear = other->noninherited_flags._clear;
191     noninherited_flags._position = other->noninherited_flags._position;
192     noninherited_flags._floating = other->noninherited_flags._floating;
193     noninherited_flags._table_layout = other->noninherited_flags._table_layout;
194     noninherited_flags._unicodeBidi = other->noninherited_flags._unicodeBidi;
195     noninherited_flags._page_break_before = other->noninherited_flags._page_break_before;
196     noninherited_flags._page_break_after = other->noninherited_flags._page_break_after;
197     noninherited_flags._page_break_inside = other->noninherited_flags._page_break_inside;
198 #if ENABLE(SVG)
199     if (m_svgStyle != other->m_svgStyle)
200         m_svgStyle.access()->copyNonInheritedFrom(other->m_svgStyle.get());
201 #endif
202     ASSERT(zoom() == initialZoom());
203 }
204
205 bool RenderStyle::operator==(const RenderStyle& o) const
206 {
207     // compare everything except the pseudoStyle pointer
208     return inherited_flags == o.inherited_flags
209         && noninherited_flags == o.noninherited_flags
210         && m_box == o.m_box
211         && visual == o.visual
212         && m_background == o.m_background
213         && surround == o.surround
214         && rareNonInheritedData == o.rareNonInheritedData
215         && rareInheritedData == o.rareInheritedData
216         && inherited == o.inherited
217 #if ENABLE(SVG)
218         && m_svgStyle == o.m_svgStyle
219 #endif
220             ;
221 }
222
223 bool RenderStyle::isStyleAvailable() const
224 {
225     return this != CSSStyleSelector::styleNotYetAvailable();
226 }
227
228 static inline int pseudoBit(PseudoId pseudo)
229 {
230     return 1 << (pseudo - 1);
231 }
232
233 bool RenderStyle::hasAnyPublicPseudoStyles() const
234 {
235     return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
236 }
237
238 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
239 {
240     ASSERT(pseudo > NOPSEUDO);
241     ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
242     return pseudoBit(pseudo) & noninherited_flags._pseudoBits;
243 }
244
245 void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
246 {
247     ASSERT(pseudo > NOPSEUDO);
248     ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
249     noninherited_flags._pseudoBits |= pseudoBit(pseudo);
250 }
251
252 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
253 {
254     if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
255         return 0;
256
257     if (styleType() != NOPSEUDO) 
258         return 0;
259
260     for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
261         RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
262         if (pseudoStyle->styleType() == pid)
263             return pseudoStyle;
264     }
265
266     return 0;
267 }
268
269 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
270 {
271     if (!pseudo)
272         return 0;
273
274     ASSERT(pseudo->styleType() > NOPSEUDO);
275
276     RenderStyle* result = pseudo.get();
277
278     if (!m_cachedPseudoStyles)
279         m_cachedPseudoStyles = adoptPtr(new PseudoStyleCache);
280
281     m_cachedPseudoStyles->append(pseudo);
282
283     return result;
284 }
285
286 void RenderStyle::removeCachedPseudoStyle(PseudoId pid)
287 {
288     if (!m_cachedPseudoStyles)
289         return;
290     for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
291         RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
292         if (pseudoStyle->styleType() == pid) {
293             m_cachedPseudoStyles->remove(i);
294             return;
295         }
296     }
297 }
298
299 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
300 {
301     return inherited_flags != other->inherited_flags
302            || inherited != other->inherited
303 #if ENABLE(SVG)
304            || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get())
305 #endif
306            || rareInheritedData != other->rareInheritedData;
307 }
308
309 bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
310 {
311     // This is a fast check that only looks if the data structures are shared.
312     return inherited_flags == other->inherited_flags
313         && inherited.get() == other->inherited.get()
314 #if ENABLE(SVG)
315         && m_svgStyle.get() == other->m_svgStyle.get()
316 #endif
317         && rareInheritedData.get() == other->rareInheritedData.get();
318 }
319
320 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
321 {
322     // If any unit types are different, then we can't guarantee
323     // that this was just a movement.
324     if (a.left().type() != b.left().type()
325         || a.right().type() != b.right().type()
326         || a.top().type() != b.top().type()
327         || a.bottom().type() != b.bottom().type())
328         return false;
329
330     // Only one unit can be non-auto in the horizontal direction and
331     // in the vertical direction.  Otherwise the adjustment of values
332     // is changing the size of the box.
333     if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
334         return false;
335     if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
336         return false;
337
338     // One of the units is fixed or percent in both directions and stayed
339     // that way in the new style.  Therefore all we are doing is moving.
340     return true;
341 }
342
343 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
344 {
345     changedContextSensitiveProperties = ContextSensitivePropertyNone;
346
347 #if ENABLE(SVG)
348     StyleDifference svgChange = StyleDifferenceEqual;
349     if (m_svgStyle != other->m_svgStyle) {
350         svgChange = m_svgStyle->diff(other->m_svgStyle.get());
351         if (svgChange == StyleDifferenceLayout)
352             return svgChange;
353     }
354 #endif
355
356     if (m_box->width() != other->m_box->width()
357         || m_box->minWidth() != other->m_box->minWidth()
358         || m_box->maxWidth() != other->m_box->maxWidth()
359         || m_box->height() != other->m_box->height()
360         || m_box->minHeight() != other->m_box->minHeight()
361         || m_box->maxHeight() != other->m_box->maxHeight())
362         return StyleDifferenceLayout;
363
364     if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
365         return StyleDifferenceLayout;
366
367     if (m_box->boxSizing() != other->m_box->boxSizing())
368         return StyleDifferenceLayout;
369
370     if (surround->margin != other->surround->margin)
371         return StyleDifferenceLayout;
372
373     if (surround->padding != other->surround->padding)
374         return StyleDifferenceLayout;
375
376     if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
377         if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance 
378             || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse
379             || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse
380             || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp
381             || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
382             return StyleDifferenceLayout;
383
384         if (rareNonInheritedData->m_regionOverflow != other->rareNonInheritedData->m_regionOverflow)
385             return StyleDifferenceLayout;
386
387         if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow
388             || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough
389             || rareNonInheritedData->m_wrapMargin != other->rareNonInheritedData->m_wrapMargin
390             || rareNonInheritedData->m_wrapPadding != other->rareNonInheritedData->m_wrapPadding)
391             return StyleDifferenceLayout;
392
393         if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get()
394             && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get())
395             return StyleDifferenceLayout;
396
397         if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get()
398             && *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get())
399             return StyleDifferenceLayout;
400
401         // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
402         if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
403             return StyleDifferenceLayout;
404
405         if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
406             return StyleDifferenceLayout;
407
408         if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get()
409             && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
410             return StyleDifferenceLayout;
411
412         if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get()
413             && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) {
414 #if USE(ACCELERATED_COMPOSITING)
415             changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
416             // Don't return; keep looking for another change
417 #else
418             return StyleDifferenceLayout;
419 #endif
420         }
421
422 #if ENABLE(CSS_FILTERS)
423         if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get()
424             && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) {
425             return StyleDifferenceLayout;
426         }
427 #endif
428 #if ENABLE(CSS_GRID_LAYOUT)
429         if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get()
430             && rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get())
431             return StyleDifferenceLayout;
432 #endif
433
434 #if !USE(ACCELERATED_COMPOSITING)
435         if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
436             if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
437                 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility
438                 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
439                 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
440                 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
441                 return StyleDifferenceLayout;
442         }
443 #endif
444
445 #if ENABLE(DASHBOARD_SUPPORT)
446         // If regions change, trigger a relayout to re-calc regions.
447         if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
448             return StyleDifferenceLayout;
449 #endif
450     }
451
452     if (rareInheritedData.get() != other->rareInheritedData.get()) {
453         if (rareInheritedData->highlight != other->rareInheritedData->highlight
454             || rareInheritedData->indent != other->rareInheritedData->indent
455             || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom
456             || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust
457             || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak
458             || rareInheritedData->wordWrap != other->rareInheritedData->wordWrap
459             || rareInheritedData->nbspMode != other->rareInheritedData->nbspMode
460             || rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak
461             || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity
462             || rareInheritedData->hyphens != other->rareInheritedData->hyphens
463             || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore
464             || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter
465             || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString
466             || rareInheritedData->locale != other->rareInheritedData->locale
467             || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark
468             || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition
469             || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark
470             || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain
471             || rareInheritedData->m_lineGrid != other->rareInheritedData->m_lineGrid
472             || rareInheritedData->m_lineSnap != other->rareInheritedData->m_lineSnap
473             || rareInheritedData->m_lineAlign != other->rareInheritedData->m_lineAlign)
474             return StyleDifferenceLayout;
475
476         if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
477             return StyleDifferenceLayout;
478
479         if (textStrokeWidth() != other->textStrokeWidth())
480             return StyleDifferenceLayout;
481     }
482
483     if (inherited->line_height != other->inherited->line_height
484         || inherited->list_style_image != other->inherited->list_style_image
485         || inherited->font != other->inherited->font
486         || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing
487         || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing
488         || inherited_flags._box_direction != other->inherited_flags._box_direction
489         || inherited_flags.m_rtlOrdering != other->inherited_flags.m_rtlOrdering
490         || noninherited_flags._position != other->noninherited_flags._position
491         || noninherited_flags._floating != other->noninherited_flags._floating
492         || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
493         return StyleDifferenceLayout;
494
495
496     if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
497         if (inherited_flags._border_collapse != other->inherited_flags._border_collapse
498             || inherited_flags._empty_cells != other->inherited_flags._empty_cells
499             || inherited_flags._caption_side != other->inherited_flags._caption_side
500             || noninherited_flags._table_layout != other->noninherited_flags._table_layout)
501             return StyleDifferenceLayout;
502
503         // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
504         // does not, so these style differences can be width differences.
505         if (inherited_flags._border_collapse
506             && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE)
507                 || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN)
508                 || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE)
509                 || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN)
510                 || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE)
511                 || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN)
512                 || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE)
513                 || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
514             return StyleDifferenceLayout;
515     }
516
517     if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
518         if (inherited_flags._list_style_type != other->inherited_flags._list_style_type
519             || inherited_flags._list_style_position != other->inherited_flags._list_style_position)
520             return StyleDifferenceLayout;
521     }
522
523     if (inherited_flags._text_align != other->inherited_flags._text_align
524         || inherited_flags._text_transform != other->inherited_flags._text_transform
525         || inherited_flags._direction != other->inherited_flags._direction
526         || inherited_flags._white_space != other->inherited_flags._white_space
527         || noninherited_flags._clear != other->noninherited_flags._clear
528         || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi)
529         return StyleDifferenceLayout;
530
531     // Check block flow direction.
532     if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode)
533         return StyleDifferenceLayout;
534
535     // Check text combine mode.
536     if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine)
537         return StyleDifferenceLayout;
538
539     // Overflow returns a layout hint.
540     if (noninherited_flags._overflowX != other->noninherited_flags._overflowX
541         || noninherited_flags._overflowY != other->noninherited_flags._overflowY)
542         return StyleDifferenceLayout;
543
544     // If our border widths change, then we need to layout.  Other changes to borders
545     // only necessitate a repaint.
546     if (borderLeftWidth() != other->borderLeftWidth()
547         || borderTopWidth() != other->borderTopWidth()
548         || borderBottomWidth() != other->borderBottomWidth()
549         || borderRightWidth() != other->borderRightWidth())
550         return StyleDifferenceLayout;
551
552     // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
553     const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
554     const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
555     if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
556         return StyleDifferenceLayout;
557     if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement
558         || rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset)
559         return StyleDifferenceLayout;
560
561     if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
562         return StyleDifferenceLayout;
563
564     if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1)
565         || (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
566         // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
567         // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
568         // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
569         // In addition we need to solve the floating object issue when layers come and go. Right now
570         // a full layout is necessary to keep floating object lists sane.
571         return StyleDifferenceLayout;
572     }
573
574 #if ENABLE(SVG)
575     // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
576     // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
577     // but have to return StyleDifferenceLayout, that's why  this if branch comes after all branches
578     // that are relevant for SVG and might return StyleDifferenceLayout.
579     if (svgChange != StyleDifferenceEqual)
580         return svgChange;
581 #endif
582
583     // Make sure these left/top/right/bottom checks stay below all layout checks and above
584     // all visible checks.
585     if (position() != StaticPosition) {
586         if (surround->offset != other->surround->offset) {
587              // Optimize for the case where a positioned layer is moving but not changing size.
588             if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
589                 return StyleDifferenceLayoutPositionedMovementOnly;
590
591             // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
592             // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
593             // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
594             return StyleDifferenceLayout;
595         } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex()
596                  || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
597             return StyleDifferenceRepaintLayer;
598     }
599
600     if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
601 #if USE(ACCELERATED_COMPOSITING)
602         changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
603         // Don't return; keep looking for another change.
604 #else
605         return StyleDifferenceRepaintLayer;
606 #endif
607     }
608
609     if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask
610         || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
611         return StyleDifferenceRepaintLayer;
612
613     if (inherited->color != other->inherited->color
614         || inherited_flags._visibility != other->inherited_flags._visibility
615         || inherited_flags._text_decorations != other->inherited_flags._text_decorations
616         || inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust
617         || inherited_flags._insideLink != other->inherited_flags._insideLink
618         || surround->border != other->surround->border
619         || *m_background.get() != *other->m_background.get()
620         || visual->textDecoration != other->visual->textDecoration
621         || rareInheritedData->userModify != other->rareInheritedData->userModify
622         || rareInheritedData->userSelect != other->rareInheritedData->userSelect
623         || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag
624         || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit
625         || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor
626         || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor
627         || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor
628         || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill
629         || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering)
630         return StyleDifferenceRepaint;
631         
632         // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected 
633         // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout 
634         // the parent container. For sure, I will have to revisit this code, but for now I've added this in order 
635         // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ.
636         // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991
637         if (rareNonInheritedData->m_wrapShapeInside != other->rareNonInheritedData->m_wrapShapeInside
638             || rareNonInheritedData->m_wrapShapeOutside != other->rareNonInheritedData->m_wrapShapeOutside)
639             return StyleDifferenceRepaint;
640
641 #if USE(ACCELERATED_COMPOSITING)
642     if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
643         if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
644             || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility
645             || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
646             || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
647             || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
648             return StyleDifferenceRecompositeLayer;
649     }
650 #endif
651
652     // Cursors are not checked, since they will be set appropriately in response to mouse events,
653     // so they don't need to cause any repaint or layout.
654
655     // 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
656     // the resulting transition properly.
657     return StyleDifferenceEqual;
658 }
659
660 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
661 {
662     StyleVisualData* data = visual.access();
663     data->clip.m_top = top;
664     data->clip.m_right = right;
665     data->clip.m_bottom = bottom;
666     data->clip.m_left = left;
667 }
668
669 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot)
670 {
671     if (!rareInheritedData.access()->cursorData)
672         rareInheritedData.access()->cursorData = CursorList::create();
673     rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot));
674 }
675
676 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
677 {
678     rareInheritedData.access()->cursorData = other;
679 }
680
681 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
682 {
683     if (QuotesData::equal(rareInheritedData->quotes.get(), q.get()))
684         return;
685     rareInheritedData.access()->quotes = q;
686 }
687
688 void RenderStyle::clearCursorList()
689 {
690     if (rareInheritedData->cursorData)
691         rareInheritedData.access()->cursorData = 0;
692 }
693
694 void RenderStyle::clearContent()
695 {
696     if (rareNonInheritedData->m_content)
697         rareNonInheritedData.access()->m_content = nullptr;
698 }
699
700 void RenderStyle::appendContent(PassOwnPtr<ContentData> contentData)
701 {
702     OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
703     ContentData* lastContent = content.get();
704     while (lastContent && lastContent->next())
705         lastContent = lastContent->next();
706
707     if (lastContent)
708         lastContent->setNext(contentData);
709     else
710         content = contentData;
711 }
712
713 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
714 {
715     if (!image)
716         return;
717         
718     if (add) {
719         appendContent(ContentData::create(image));
720         return;
721     }
722
723     rareNonInheritedData.access()->m_content = ContentData::create(image);
724 }
725
726 void RenderStyle::setContent(const String& string, bool add)
727 {
728     OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
729     if (add) {
730         ContentData* lastContent = content.get();
731         while (lastContent && lastContent->next())
732             lastContent = lastContent->next();
733
734         if (lastContent) {
735             // We attempt to merge with the last ContentData if possible.
736             if (lastContent->isText()) {
737                 TextContentData* textContent = static_cast<TextContentData*>(lastContent);
738                 String text = textContent->text();
739                 text += string;
740                 textContent->setText(text);
741             } else
742                 lastContent->setNext(ContentData::create(string));
743
744             return;
745         }
746     }
747
748     content = ContentData::create(string);
749 }
750
751 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
752 {
753     if (!counter)
754         return;
755
756     if (add) {
757         appendContent(ContentData::create(counter));
758         return;
759     }
760
761     rareNonInheritedData.access()->m_content = ContentData::create(counter);
762 }
763
764 void RenderStyle::setContent(QuoteType quote, bool add)
765 {
766     if (add) {
767         appendContent(ContentData::create(quote));
768         return;
769     }
770
771     rareNonInheritedData.access()->m_content = ContentData::create(quote);
772 }
773     
774 inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
775 {
776     // transform-origin brackets the transform with translate operations.
777     // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
778     // in that case.
779     if (applyOrigin != RenderStyle::IncludeTransformOrigin)
780         return false;
781
782     unsigned size = transformOperations.size();
783     for (unsigned i = 0; i < size; ++i) {
784         TransformOperation::OperationType type = transformOperations[i]->getOperationType();
785         if (type != TransformOperation::TRANSLATE_X
786             && type != TransformOperation::TRANSLATE_Y
787             && type != TransformOperation::TRANSLATE 
788             && type != TransformOperation::TRANSLATE_Z
789             && type != TransformOperation::TRANSLATE_3D)
790             return true;
791     }
792     
793     return false;
794 }
795
796 void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
797 {
798     // FIXME: when subpixel layout is supported (bug 71143) the body of this function could be replaced by
799     // applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin);
800     
801     const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
802     bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
803
804     if (applyTransformOrigin)
805         transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ());
806
807     unsigned size = transformOperations.size();
808     for (unsigned i = 0; i < size; ++i)
809         transformOperations[i]->apply(transform, borderBoxSize);
810
811     if (applyTransformOrigin)
812         transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); 
813 }
814
815 void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const
816 {
817     const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
818     bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
819     
820     float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0;
821     float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0;
822     
823     if (applyTransformOrigin) {
824         transform.translate3d(transformOriginX().calcFloatValue(boundingBox.width()) + offsetX,
825                               transformOriginY().calcFloatValue(boundingBox.height()) + offsetY,
826                               transformOriginZ());
827     }
828     
829     unsigned size = transformOperations.size();
830     for (unsigned i = 0; i < size; ++i)
831         transformOperations[i]->apply(transform, boundingBox.size());
832     
833     if (applyTransformOrigin) {
834         transform.translate3d(-transformOriginX().calcFloatValue(boundingBox.width()) - offsetX,
835                               -transformOriginY().calcFloatValue(boundingBox.height()) - offsetY,
836                               -transformOriginZ());
837     }
838 }
839
840 void RenderStyle::setPageScaleTransform(float scale)
841 {
842     if (scale == 1)
843         return;
844     TransformOperations transform;
845     transform.operations().append(ScaleTransformOperation::create(scale, scale, ScaleTransformOperation::SCALE));
846     setTransform(transform);
847     setTransformOriginX(Length(0, Fixed));
848     setTransformOriginY(Length(0, Fixed));
849 }
850
851 void RenderStyle::setTextShadow(PassOwnPtr<ShadowData> shadowData, bool add)
852 {
853     ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal));
854
855     StyleRareInheritedData* rareData = rareInheritedData.access();
856     if (!add) {
857         rareData->textShadow = shadowData;
858         return;
859     }
860
861     shadowData->setNext(rareData->textShadow.release());
862     rareData->textShadow = shadowData;
863 }
864
865 void RenderStyle::setBoxShadow(PassOwnPtr<ShadowData> shadowData, bool add)
866 {
867     StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
868     if (!add) {
869         rareData->m_boxShadow = shadowData;
870         return;
871     }
872
873     shadowData->setNext(rareData->m_boxShadow.release());
874     rareData->m_boxShadow = shadowData;
875 }
876
877 static RoundedRect::Radii calcRadiiFor(const BorderData& border, LayoutSize size)
878 {
879     return RoundedRect::Radii(
880         IntSize(border.topLeft().width().calcValue(size.width()), 
881                 border.topLeft().height().calcValue(size.height())),
882         IntSize(border.topRight().width().calcValue(size.width()),
883                 border.topRight().height().calcValue(size.height())),
884         IntSize(border.bottomLeft().width().calcValue(size.width()), 
885                 border.bottomLeft().height().calcValue(size.height())),
886         IntSize(border.bottomRight().width().calcValue(size.width()), 
887                 border.bottomRight().height().calcValue(size.height())));
888 }
889
890 static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radii& radii)
891 {
892     // Constrain corner radii using CSS3 rules:
893     // http://www.w3.org/TR/css3-background/#the-border-radius
894     
895     float factor = 1;
896     unsigned radiiSum;
897
898     // top
899     radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow.
900     if (radiiSum > static_cast<unsigned>(rect.width()))
901         factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
902
903     // bottom
904     radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width());
905     if (radiiSum > static_cast<unsigned>(rect.width()))
906         factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
907     
908     // left
909     radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height());
910     if (radiiSum > static_cast<unsigned>(rect.height()))
911         factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
912     
913     // right
914     radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height());
915     if (radiiSum > static_cast<unsigned>(rect.height()))
916         factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
917     
918     ASSERT(factor <= 1);
919     return factor;
920 }
921
922 RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
923 {
924     RoundedRect roundedRect(pixelSnappedIntRect(borderRect));
925     if (hasBorderRadius()) {
926         RoundedRect::Radii radii = calcRadiiFor(surround->border, borderRect.size());
927         radii.scale(calcConstraintScaleFor(borderRect, radii));
928         roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
929     }
930     return roundedRect;
931 }
932
933 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
934 {
935     bool horizontal = isHorizontalWritingMode();
936
937     LayoutUnit leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
938     LayoutUnit rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
939     LayoutUnit topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
940     LayoutUnit bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
941
942     return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
943 }
944
945 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
946     LayoutUnit topWidth, LayoutUnit bottomWidth, LayoutUnit leftWidth, LayoutUnit rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
947 {
948     LayoutRect innerRect(borderRect.x() + leftWidth, 
949                borderRect.y() + topWidth, 
950                borderRect.width() - leftWidth - rightWidth, 
951                borderRect.height() - topWidth - bottomWidth);
952
953     RoundedRect roundedRect(pixelSnappedIntRect(innerRect));
954
955     if (hasBorderRadius()) {
956         RoundedRect::Radii radii = getRoundedBorderFor(borderRect).radii();
957         radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
958         roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
959     }
960     return roundedRect;
961 }
962
963 const CounterDirectiveMap* RenderStyle::counterDirectives() const
964 {
965     return rareNonInheritedData->m_counterDirectives.get();
966 }
967
968 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
969 {
970     OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
971     if (!map)
972         map = adoptPtr(new CounterDirectiveMap);
973     return *map;
974 }
975
976 const AtomicString& RenderStyle::hyphenString() const
977 {
978     ASSERT(hyphens() != HyphensNone);
979
980     const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString;
981     if (!hyphenationString.isNull())
982         return hyphenationString;
983
984     // FIXME: This should depend on locale.
985     DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1));
986     DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1));
987     return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString;
988 }
989
990 const AtomicString& RenderStyle::textEmphasisMarkString() const
991 {
992     switch (textEmphasisMark()) {
993     case TextEmphasisMarkNone:
994         return nullAtom;
995     case TextEmphasisMarkCustom:
996         return textEmphasisCustomMark();
997     case TextEmphasisMarkDot: {
998         DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1));
999         DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1));
1000         return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString;
1001     }
1002     case TextEmphasisMarkCircle: {
1003         DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1));
1004         DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1));
1005         return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString;
1006     }
1007     case TextEmphasisMarkDoubleCircle: {
1008         DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1));
1009         DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1));
1010         return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString;
1011     }
1012     case TextEmphasisMarkTriangle: {
1013         DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1));
1014         DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1));
1015         return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString;
1016     }
1017     case TextEmphasisMarkSesame: {
1018         DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1));
1019         DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1));
1020         return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString;
1021     }
1022     case TextEmphasisMarkAuto:
1023         ASSERT_NOT_REACHED();
1024         return nullAtom;
1025     }
1026
1027     ASSERT_NOT_REACHED();
1028     return nullAtom;
1029 }
1030
1031 #if ENABLE(DASHBOARD_SUPPORT)
1032 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
1033 {
1034     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
1035     return emptyList;
1036 }
1037
1038 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
1039 {
1040     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
1041     static bool noneListInitialized = false;
1042
1043     if (!noneListInitialized) {
1044         StyleDashboardRegion region;
1045         region.label = "";
1046         region.offset.m_top  = Length();
1047         region.offset.m_right = Length();
1048         region.offset.m_bottom = Length();
1049         region.offset.m_left = Length();
1050         region.type = StyleDashboardRegion::None;
1051         noneList.append(region);
1052         noneListInitialized = true;
1053     }
1054     return noneList;
1055 }
1056 #endif
1057
1058 void RenderStyle::adjustAnimations()
1059 {
1060     AnimationList* animationList = rareNonInheritedData->m_animations.get();
1061     if (!animationList)
1062         return;
1063
1064     // Get rid of empty animations and anything beyond them
1065     for (size_t i = 0; i < animationList->size(); ++i) {
1066         if (animationList->animation(i)->isEmpty()) {
1067             animationList->resize(i);
1068             break;
1069         }
1070     }
1071
1072     if (animationList->isEmpty()) {
1073         clearAnimations();
1074         return;
1075     }
1076
1077     // Repeat patterns into layers that don't have some properties set.
1078     animationList->fillUnsetProperties();
1079 }
1080
1081 void RenderStyle::adjustTransitions()
1082 {
1083     AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
1084     if (!transitionList)
1085         return;
1086
1087     // Get rid of empty transitions and anything beyond them
1088     for (size_t i = 0; i < transitionList->size(); ++i) {
1089         if (transitionList->animation(i)->isEmpty()) {
1090             transitionList->resize(i);
1091             break;
1092         }
1093     }
1094
1095     if (transitionList->isEmpty()) {
1096         clearTransitions();
1097         return;
1098     }
1099
1100     // Repeat patterns into layers that don't have some properties set.
1101     transitionList->fillUnsetProperties();
1102
1103     // Make sure there are no duplicate properties. This is an O(n^2) algorithm
1104     // but the lists tend to be very short, so it is probably ok
1105     for (size_t i = 0; i < transitionList->size(); ++i) {
1106         for (size_t j = i+1; j < transitionList->size(); ++j) {
1107             if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
1108                 // toss i
1109                 transitionList->remove(i);
1110                 j = i;
1111             }
1112         }
1113     }
1114 }
1115
1116 AnimationList* RenderStyle::accessAnimations()
1117 {
1118     if (!rareNonInheritedData.access()->m_animations)
1119         rareNonInheritedData.access()->m_animations = adoptPtr(new AnimationList());
1120     return rareNonInheritedData->m_animations.get();
1121 }
1122
1123 AnimationList* RenderStyle::accessTransitions()
1124 {
1125     if (!rareNonInheritedData.access()->m_transitions)
1126         rareNonInheritedData.access()->m_transitions = adoptPtr(new AnimationList());
1127     return rareNonInheritedData->m_transitions.get();
1128 }
1129
1130 const Animation* RenderStyle::transitionForProperty(int property) const
1131 {
1132     if (transitions()) {
1133         for (size_t i = 0; i < transitions()->size(); ++i) {
1134             const Animation* p = transitions()->animation(i);
1135             if (p->property() == cAnimateAll || p->property() == property) {
1136                 return p;
1137             }
1138         }
1139     }
1140     return 0;
1141 }
1142
1143 void RenderStyle::setBlendedFontSize(int size)
1144 {
1145     FontSelector* currentFontSelector = font().fontSelector();
1146     FontDescription desc(fontDescription());
1147     desc.setSpecifiedSize(size);
1148     desc.setComputedSize(size);
1149     setFontDescription(desc);
1150     font().update(currentFontSelector);
1151 }
1152
1153 void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const
1154 {
1155     top = 0;
1156     right = 0;
1157     bottom = 0;
1158     left = 0;
1159
1160     for ( ; shadow; shadow = shadow->next()) {
1161         if (shadow->style() == Inset)
1162             continue;
1163         int blurAndSpread = shadow->blur() + shadow->spread();
1164
1165         top = min(top, shadow->y() - blurAndSpread);
1166         right = max(right, shadow->x() + blurAndSpread);
1167         bottom = max(bottom, shadow->y() + blurAndSpread);
1168         left = min(left, shadow->x() - blurAndSpread);
1169     }
1170 }
1171
1172 void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit &left, LayoutUnit &right) const
1173 {
1174     left = 0;
1175     right = 0;
1176
1177     for ( ; shadow; shadow = shadow->next()) {
1178         if (shadow->style() == Inset)
1179             continue;
1180         int blurAndSpread = shadow->blur() + shadow->spread();
1181
1182         left = min(left, shadow->x() - blurAndSpread);
1183         right = max(right, shadow->x() + blurAndSpread);
1184     }
1185 }
1186
1187 void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &bottom) const
1188 {
1189     top = 0;
1190     bottom = 0;
1191
1192     for ( ; shadow; shadow = shadow->next()) {
1193         if (shadow->style() == Inset)
1194             continue;
1195         int blurAndSpread = shadow->blur() + shadow->spread();
1196
1197         top = min(top, shadow->y() - blurAndSpread);
1198         bottom = max(bottom, shadow->y() + blurAndSpread);
1199     }
1200 }
1201
1202 Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const
1203 {
1204     Color result;
1205     EBorderStyle borderStyle = BNONE;
1206     switch (colorProperty) {
1207     case CSSPropertyBackgroundColor:
1208         return visitedLink ? rareNonInheritedData->m_visitedLinkBackgroundColor : backgroundColor(); // Background color doesn't fall back.
1209     case CSSPropertyBorderLeftColor:
1210         result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderLeftColor : borderLeftColor();
1211         borderStyle = borderLeftStyle();
1212         break;
1213     case CSSPropertyBorderRightColor:
1214         result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderRightColor : borderRightColor();
1215         borderStyle = borderRightStyle();
1216         break;
1217     case CSSPropertyBorderTopColor:
1218         result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderTopColor : borderTopColor();
1219         borderStyle = borderTopStyle();
1220         break;
1221     case CSSPropertyBorderBottomColor:
1222         result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderBottomColor : borderBottomColor();
1223         borderStyle = borderBottomStyle();
1224         break;
1225     case CSSPropertyColor:
1226         result = visitedLink ? inherited->visitedLinkColor : color();
1227         break;
1228     case CSSPropertyOutlineColor:
1229         result = visitedLink ? rareNonInheritedData->m_visitedLinkOutlineColor : outlineColor();
1230         break;
1231     case CSSPropertyWebkitColumnRuleColor:
1232         result = visitedLink ? rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor : columnRuleColor();
1233         break;
1234     case CSSPropertyWebkitTextEmphasisColor:
1235         result = visitedLink ? rareInheritedData->visitedLinkTextEmphasisColor : textEmphasisColor();
1236         break;
1237     case CSSPropertyWebkitTextFillColor:
1238         result = visitedLink ? rareInheritedData->visitedLinkTextFillColor : textFillColor();
1239         break;
1240     case CSSPropertyWebkitTextStrokeColor:
1241         result = visitedLink ? rareInheritedData->visitedLinkTextStrokeColor : textStrokeColor();
1242         break;
1243     default:
1244         ASSERT_NOT_REACHED();
1245         break;
1246     }
1247
1248     if (!result.isValid()) {
1249         if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1250             result.setRGB(238, 238, 238);
1251         else
1252             result = visitedLink ? inherited->visitedLinkColor : color();
1253     }
1254     return result;
1255 }
1256
1257 Color RenderStyle::visitedDependentColor(int colorProperty) const
1258 {
1259     Color unvisitedColor = colorIncludingFallback(colorProperty, false);
1260     if (insideLink() != InsideVisitedLink)
1261         return unvisitedColor;
1262
1263     Color visitedColor = colorIncludingFallback(colorProperty, true);
1264
1265     // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
1266     // assume that if the background color is transparent that it wasn't set. Note that it's weird that
1267     // we're returning unvisited info for a visited link, but given our restriction that the alpha values
1268     // have to match, it makes more sense to return the unvisited background color if specified than it
1269     // does to return black. This behavior matches what Firefox 4 does as well.
1270     if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent)
1271         return unvisitedColor;
1272
1273     // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1274     return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1275 }
1276
1277 Length RenderStyle::logicalWidth() const
1278 {
1279     if (isHorizontalWritingMode())
1280         return width();
1281     return height();
1282 }
1283
1284 Length RenderStyle::logicalHeight() const
1285 {
1286     if (isHorizontalWritingMode())
1287         return height();
1288     return width();
1289 }
1290
1291 Length RenderStyle::logicalMinWidth() const
1292 {
1293     if (isHorizontalWritingMode())
1294         return minWidth();
1295     return minHeight();
1296 }
1297
1298 Length RenderStyle::logicalMaxWidth() const
1299 {
1300     if (isHorizontalWritingMode())
1301         return maxWidth();
1302     return maxHeight();
1303 }
1304
1305 Length RenderStyle::logicalMinHeight() const
1306 {
1307     if (isHorizontalWritingMode())
1308         return minHeight();
1309     return minWidth();
1310 }
1311
1312 Length RenderStyle::logicalMaxHeight() const
1313 {
1314     if (isHorizontalWritingMode())
1315         return maxHeight();
1316     return maxWidth();
1317 }
1318
1319 const BorderValue& RenderStyle::borderBefore() const
1320 {
1321     switch (writingMode()) {
1322     case TopToBottomWritingMode:
1323         return borderTop();
1324     case BottomToTopWritingMode:
1325         return borderBottom();
1326     case LeftToRightWritingMode:
1327         return borderLeft();
1328     case RightToLeftWritingMode:
1329         return borderRight();
1330     }
1331     ASSERT_NOT_REACHED();
1332     return borderTop();
1333 }
1334
1335 const BorderValue& RenderStyle::borderAfter() const
1336 {
1337     switch (writingMode()) {
1338     case TopToBottomWritingMode:
1339         return borderBottom();
1340     case BottomToTopWritingMode:
1341         return borderTop();
1342     case LeftToRightWritingMode:
1343         return borderRight();
1344     case RightToLeftWritingMode:
1345         return borderLeft();
1346     }
1347     ASSERT_NOT_REACHED();
1348     return borderBottom();
1349 }
1350
1351 const BorderValue& RenderStyle::borderStart() const
1352 {
1353     if (isHorizontalWritingMode())
1354         return isLeftToRightDirection() ? borderLeft() : borderRight();
1355     return isLeftToRightDirection() ? borderTop() : borderBottom();
1356 }
1357
1358 const BorderValue& RenderStyle::borderEnd() const
1359 {
1360     if (isHorizontalWritingMode())
1361         return isLeftToRightDirection() ? borderRight() : borderLeft();
1362     return isLeftToRightDirection() ? borderBottom() : borderTop();
1363 }
1364
1365 unsigned short RenderStyle::borderBeforeWidth() const
1366 {
1367     switch (writingMode()) {
1368     case TopToBottomWritingMode:
1369         return borderTopWidth();
1370     case BottomToTopWritingMode:
1371         return borderBottomWidth();
1372     case LeftToRightWritingMode:
1373         return borderLeftWidth();
1374     case RightToLeftWritingMode:
1375         return borderRightWidth();
1376     }
1377     ASSERT_NOT_REACHED();
1378     return borderTopWidth();
1379 }
1380
1381 unsigned short RenderStyle::borderAfterWidth() const
1382 {
1383     switch (writingMode()) {
1384     case TopToBottomWritingMode:
1385         return borderBottomWidth();
1386     case BottomToTopWritingMode:
1387         return borderTopWidth();
1388     case LeftToRightWritingMode:
1389         return borderRightWidth();
1390     case RightToLeftWritingMode:
1391         return borderLeftWidth();
1392     }
1393     ASSERT_NOT_REACHED();
1394     return borderBottomWidth();
1395 }
1396
1397 unsigned short RenderStyle::borderStartWidth() const
1398 {
1399     if (isHorizontalWritingMode())
1400         return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
1401     return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
1402 }
1403
1404 unsigned short RenderStyle::borderEndWidth() const
1405 {
1406     if (isHorizontalWritingMode())
1407         return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
1408     return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
1409 }
1410     
1411 Length RenderStyle::marginBefore() const
1412 {
1413     switch (writingMode()) {
1414     case TopToBottomWritingMode:
1415         return marginTop();
1416     case BottomToTopWritingMode:
1417         return marginBottom();
1418     case LeftToRightWritingMode:
1419         return marginLeft();
1420     case RightToLeftWritingMode:
1421         return marginRight();
1422     }
1423     ASSERT_NOT_REACHED();
1424     return marginTop();
1425 }
1426
1427 Length RenderStyle::marginAfter() const
1428 {
1429     switch (writingMode()) {
1430     case TopToBottomWritingMode:
1431         return marginBottom();
1432     case BottomToTopWritingMode:
1433         return marginTop();
1434     case LeftToRightWritingMode:
1435         return marginRight();
1436     case RightToLeftWritingMode:
1437         return marginLeft();
1438     }
1439     ASSERT_NOT_REACHED();
1440     return marginBottom();
1441 }
1442
1443 Length RenderStyle::marginBeforeUsing(const RenderStyle* otherStyle) const
1444 {
1445     switch (otherStyle->writingMode()) {
1446     case TopToBottomWritingMode:
1447         return marginTop();
1448     case BottomToTopWritingMode:
1449         return marginBottom();
1450     case LeftToRightWritingMode:
1451         return marginLeft();
1452     case RightToLeftWritingMode:
1453         return marginRight();
1454     }
1455     ASSERT_NOT_REACHED();
1456     return marginTop();
1457 }
1458
1459 Length RenderStyle::marginAfterUsing(const RenderStyle* otherStyle) const
1460 {
1461     switch (otherStyle->writingMode()) {
1462     case TopToBottomWritingMode:
1463         return marginBottom();
1464     case BottomToTopWritingMode:
1465         return marginTop();
1466     case LeftToRightWritingMode:
1467         return marginRight();
1468     case RightToLeftWritingMode:
1469         return marginLeft();
1470     }
1471     ASSERT_NOT_REACHED();
1472     return marginBottom();
1473 }
1474
1475 Length RenderStyle::marginStart() const
1476 {
1477     if (isHorizontalWritingMode())
1478         return isLeftToRightDirection() ? marginLeft() : marginRight();
1479     return isLeftToRightDirection() ? marginTop() : marginBottom();
1480 }
1481
1482 Length RenderStyle::marginEnd() const
1483 {
1484     if (isHorizontalWritingMode())
1485         return isLeftToRightDirection() ? marginRight() : marginLeft();
1486     return isLeftToRightDirection() ? marginBottom() : marginTop();
1487 }
1488     
1489 Length RenderStyle::marginStartUsing(const RenderStyle* otherStyle) const
1490 {
1491     if (otherStyle->isHorizontalWritingMode())
1492         return otherStyle->isLeftToRightDirection() ? marginLeft() : marginRight();
1493     return otherStyle->isLeftToRightDirection() ? marginTop() : marginBottom();
1494 }
1495
1496 Length RenderStyle::marginEndUsing(const RenderStyle* otherStyle) const
1497 {
1498     if (otherStyle->isHorizontalWritingMode())
1499         return otherStyle->isLeftToRightDirection() ? marginRight() : marginLeft();
1500     return otherStyle->isLeftToRightDirection() ? marginBottom() : marginTop();
1501 }
1502
1503 void RenderStyle::setMarginStart(Length margin)
1504 {
1505     if (isHorizontalWritingMode()) {
1506         if (isLeftToRightDirection())
1507             setMarginLeft(margin);
1508         else
1509             setMarginRight(margin);
1510     } else {
1511         if (isLeftToRightDirection())
1512             setMarginTop(margin);
1513         else
1514             setMarginBottom(margin);
1515     }
1516 }
1517
1518 void RenderStyle::setMarginEnd(Length margin)
1519 {
1520     if (isHorizontalWritingMode()) {
1521         if (isLeftToRightDirection())
1522             setMarginRight(margin);
1523         else
1524             setMarginLeft(margin);
1525     } else {
1526         if (isLeftToRightDirection())
1527             setMarginBottom(margin);
1528         else
1529             setMarginTop(margin);
1530     }
1531 }
1532
1533 Length RenderStyle::paddingBefore() const
1534 {
1535     switch (writingMode()) {
1536     case TopToBottomWritingMode:
1537         return paddingTop();
1538     case BottomToTopWritingMode:
1539         return paddingBottom();
1540     case LeftToRightWritingMode:
1541         return paddingLeft();
1542     case RightToLeftWritingMode:
1543         return paddingRight();
1544     }
1545     ASSERT_NOT_REACHED();
1546     return paddingTop();
1547 }
1548
1549 Length RenderStyle::paddingAfter() const
1550 {
1551     switch (writingMode()) {
1552     case TopToBottomWritingMode:
1553         return paddingBottom();
1554     case BottomToTopWritingMode:
1555         return paddingTop();
1556     case LeftToRightWritingMode:
1557         return paddingRight();
1558     case RightToLeftWritingMode:
1559         return paddingLeft();
1560     }
1561     ASSERT_NOT_REACHED();
1562     return paddingBottom();
1563 }
1564
1565 Length RenderStyle::paddingStart() const
1566 {
1567     if (isHorizontalWritingMode())
1568         return isLeftToRightDirection() ? paddingLeft() : paddingRight();
1569     return isLeftToRightDirection() ? paddingTop() : paddingBottom();
1570 }
1571
1572 Length RenderStyle::paddingEnd() const
1573 {
1574     if (isHorizontalWritingMode())
1575         return isLeftToRightDirection() ? paddingRight() : paddingLeft();
1576     return isLeftToRightDirection() ? paddingBottom() : paddingTop();
1577 }
1578
1579 TextEmphasisMark RenderStyle::textEmphasisMark() const
1580 {
1581     TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark);
1582     if (mark != TextEmphasisMarkAuto)
1583         return mark;
1584
1585     if (isHorizontalWritingMode())
1586         return TextEmphasisMarkDot;
1587
1588     return TextEmphasisMarkSesame;
1589 }
1590
1591 #if ENABLE(TOUCH_EVENTS)
1592 Color RenderStyle::initialTapHighlightColor()
1593 {
1594     return RenderTheme::tapHighlightColor();
1595 }
1596 #endif
1597
1598 void RenderStyle::getImageOutsets(const NinePieceImage& image, LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const
1599 {
1600     top = NinePieceImage::computeOutset(image.outset().top(), borderTopWidth());
1601     right = NinePieceImage::computeOutset(image.outset().right(), borderRightWidth());
1602     bottom = NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth());
1603     left = NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth());
1604 }
1605
1606 void RenderStyle::getImageHorizontalOutsets(const NinePieceImage& image, LayoutUnit& left, LayoutUnit& right) const
1607 {
1608     right = NinePieceImage::computeOutset(image.outset().right(), borderRightWidth());
1609     left = NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth());
1610 }
1611
1612 void RenderStyle::getImageVerticalOutsets(const NinePieceImage& image, LayoutUnit& top, LayoutUnit& bottom) const
1613 {
1614     top = NinePieceImage::computeOutset(image.outset().top(), borderTopWidth());
1615     bottom = NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth());
1616 }
1617
1618 } // namespace WebCore