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