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