Home | History | Annotate | Download | only in style
      1 /*
      2  * Copyright (C) 1999 Antti Koivisto (koivisto (at) 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 
     39 using namespace std;
     40 
     41 namespace WebCore {
     42 
     43 inline RenderStyle* defaultStyle()
     44 {
     45     static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef();
     46     return s_defaultStyle;
     47 }
     48 
     49 PassRefPtr<RenderStyle> RenderStyle::create()
     50 {
     51     return adoptRef(new RenderStyle());
     52 }
     53 
     54 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
     55 {
     56     return adoptRef(new RenderStyle(true));
     57 }
     58 
     59 PassRefPtr<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 
     67 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
     68 {
     69     return adoptRef(new RenderStyle(*other));
     70 }
     71 
     72 ALWAYS_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 
     99 ALWAYS_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 
    132 ALWAYS_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 
    161 void 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 
    172 RenderStyle::~RenderStyle()
    173 {
    174 }
    175 
    176 bool 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 
    194 bool RenderStyle::isStyleAvailable() const
    195 {
    196     return this != CSSStyleSelector::styleNotYetAvailable();
    197 }
    198 
    199 static inline int pseudoBit(PseudoId pseudo)
    200 {
    201     return 1 << (pseudo - 1);
    202 }
    203 
    204 bool RenderStyle::hasAnyPublicPseudoStyles() const
    205 {
    206     return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
    207 }
    208 
    209 bool 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 
    216 void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
    217 {
    218     ASSERT(pseudo > NOPSEUDO);
    219     ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
    220     noninherited_flags._pseudoBits |= pseudoBit(pseudo);
    221 }
    222 
    223 RenderStyle* 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 
    245 RenderStyle* 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 
    260 void 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 
    273 bool 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 
    283 static 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 
    306 StyleDifference 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 
    585 void 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 
    594 void 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 
    601 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
    602 {
    603     rareInheritedData.access()->cursorData = other;
    604 }
    605 
    606 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
    607 {
    608     if (*rareInheritedData->quotes.get() == *q.get())
    609         return;
    610     rareInheritedData.access()->quotes = q;
    611 }
    612 
    613 void RenderStyle::clearCursorList()
    614 {
    615     if (rareInheritedData->cursorData)
    616         rareInheritedData.access()->cursorData = 0;
    617 }
    618 
    619 void RenderStyle::clearContent()
    620 {
    621     if (rareNonInheritedData->m_content)
    622         rareNonInheritedData->m_content->clear();
    623 }
    624 
    625 ContentData* 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 
    658 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
    659 {
    660     if (!image)
    661         return;
    662     prepareToSetContent(0, add)->setImage(image);
    663 }
    664 
    665 void 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 
    673 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
    674 {
    675     if (!counter)
    676         return;
    677     prepareToSetContent(0, add)->setCounter(counter);
    678 }
    679 
    680 void RenderStyle::setContent(QuoteType quote, bool add)
    681 {
    682     prepareToSetContent(0, add)->setQuote(quote);
    683 }
    684 
    685 void 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 
    720 void 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 
    731 void 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 
    746 void 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 
    758 static 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 
    770 static 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 
    802 RoundedIntRect 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 
    813 RoundedIntRect 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 
    825 RoundedIntRect 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 
    843 const CounterDirectiveMap* RenderStyle::counterDirectives() const
    844 {
    845     return rareNonInheritedData->m_counterDirectives.get();
    846 }
    847 
    848 CounterDirectiveMap& 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 
    856 const 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 
    870 const 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)
    912 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
    913 {
    914     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
    915     return emptyList;
    916 }
    917 
    918 const 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 
    938 void 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 
    961 void 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 
    996 AnimationList* 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 
   1003 AnimationList* 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 
   1010 const 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 
   1023 void 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 
   1033 void 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 
   1052 void 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 
   1067 void 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 
   1082 static 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 
   1105 const 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 
   1162 const 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 
   1186 Length RenderStyle::logicalWidth() const
   1187 {
   1188     if (isHorizontalWritingMode())
   1189         return width();
   1190     return height();
   1191 }
   1192 
   1193 Length RenderStyle::logicalHeight() const
   1194 {
   1195     if (isHorizontalWritingMode())
   1196         return height();
   1197     return width();
   1198 }
   1199 
   1200 Length RenderStyle::logicalMinWidth() const
   1201 {
   1202     if (isHorizontalWritingMode())
   1203         return minWidth();
   1204     return minHeight();
   1205 }
   1206 
   1207 Length RenderStyle::logicalMaxWidth() const
   1208 {
   1209     if (isHorizontalWritingMode())
   1210         return maxWidth();
   1211     return maxHeight();
   1212 }
   1213 
   1214 Length RenderStyle::logicalMinHeight() const
   1215 {
   1216     if (isHorizontalWritingMode())
   1217         return minHeight();
   1218     return minWidth();
   1219 }
   1220 
   1221 Length RenderStyle::logicalMaxHeight() const
   1222 {
   1223     if (isHorizontalWritingMode())
   1224         return maxHeight();
   1225     return maxWidth();
   1226 }
   1227 
   1228 const 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 
   1244 const 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 
   1260 const BorderValue& RenderStyle::borderStart() const
   1261 {
   1262     if (isHorizontalWritingMode())
   1263         return isLeftToRightDirection() ? borderLeft() : borderRight();
   1264     return isLeftToRightDirection() ? borderTop() : borderBottom();
   1265 }
   1266 
   1267 const BorderValue& RenderStyle::borderEnd() const
   1268 {
   1269     if (isHorizontalWritingMode())
   1270         return isLeftToRightDirection() ? borderRight() : borderLeft();
   1271     return isLeftToRightDirection() ? borderBottom() : borderTop();
   1272 }
   1273 
   1274 unsigned 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 
   1290 unsigned 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 
   1306 unsigned short RenderStyle::borderStartWidth() const
   1307 {
   1308     if (isHorizontalWritingMode())
   1309         return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
   1310     return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
   1311 }
   1312 
   1313 unsigned short RenderStyle::borderEndWidth() const
   1314 {
   1315     if (isHorizontalWritingMode())
   1316         return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
   1317     return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
   1318 }
   1319 
   1320 Length 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 
   1336 Length 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 
   1352 Length 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 
   1368 Length 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 
   1384 Length RenderStyle::marginStart() const
   1385 {
   1386     if (isHorizontalWritingMode())
   1387         return isLeftToRightDirection() ? marginLeft() : marginRight();
   1388     return isLeftToRightDirection() ? marginTop() : marginBottom();
   1389 }
   1390 
   1391 Length RenderStyle::marginEnd() const
   1392 {
   1393     if (isHorizontalWritingMode())
   1394         return isLeftToRightDirection() ? marginRight() : marginLeft();
   1395     return isLeftToRightDirection() ? marginBottom() : marginTop();
   1396 }
   1397 
   1398 Length 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 
   1405 Length 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 
   1412 void 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 
   1427 void 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 
   1442 Length 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 
   1458 Length 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 
   1474 Length RenderStyle::paddingStart() const
   1475 {
   1476     if (isHorizontalWritingMode())
   1477         return isLeftToRightDirection() ? paddingLeft() : paddingRight();
   1478     return isLeftToRightDirection() ? paddingTop() : paddingBottom();
   1479 }
   1480 
   1481 Length RenderStyle::paddingEnd() const
   1482 {
   1483     if (isHorizontalWritingMode())
   1484         return isLeftToRightDirection() ? paddingRight() : paddingLeft();
   1485     return isLeftToRightDirection() ? paddingBottom() : paddingTop();
   1486 }
   1487 
   1488 TextEmphasisMark 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