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