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