• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
39 using namespace std;
40 
41 namespace WebCore {
42 
defaultStyle()43 inline RenderStyle* defaultStyle()
44 {
45     static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().releaseRef();
46     return s_defaultStyle;
47 }
48 
create()49 PassRefPtr<RenderStyle> RenderStyle::create()
50 {
51     return adoptRef(new RenderStyle());
52 }
53 
createDefaultStyle()54 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
55 {
56     return adoptRef(new RenderStyle(true));
57 }
58 
createAnonymousStyle(const RenderStyle * parentStyle)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 
clone(const RenderStyle * other)67 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
68 {
69     return adoptRef(new RenderStyle(*other));
70 }
71 
RenderStyle()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 
RenderStyle(bool)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 
RenderStyle(const RenderStyle & o)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 
inheritFrom(const RenderStyle * inheritParent)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 
~RenderStyle()172 RenderStyle::~RenderStyle()
173 {
174 }
175 
operator ==(const RenderStyle & o) const176 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 
isStyleAvailable() const194 bool RenderStyle::isStyleAvailable() const
195 {
196     return this != CSSStyleSelector::styleNotYetAvailable();
197 }
198 
pseudoBit(PseudoId pseudo)199 static inline int pseudoBit(PseudoId pseudo)
200 {
201     return 1 << (pseudo - 1);
202 }
203 
hasAnyPublicPseudoStyles() const204 bool RenderStyle::hasAnyPublicPseudoStyles() const
205 {
206     return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
207 }
208 
hasPseudoStyle(PseudoId pseudo) const209 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 
setHasPseudoStyle(PseudoId pseudo)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 
getCachedPseudoStyle(PseudoId pid) const223 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 
addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)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 
removeCachedPseudoStyle(PseudoId pid)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 
inheritedNotEqual(const RenderStyle * other) const273 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 
positionedObjectMoved(const LengthBox & a,const LengthBox & b)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 
diff(const RenderStyle * other,unsigned & changedContextSensitiveProperties) const306 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 
setClip(Length top,Length right,Length bottom,Length left)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 
addCursor(PassRefPtr<StyleImage> image,const IntPoint & hotSpot)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 
setCursorList(PassRefPtr<CursorList> other)601 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
602 {
603     rareInheritedData.access()->cursorData = other;
604 }
605 
setQuotes(PassRefPtr<QuotesData> q)606 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
607 {
608     if (*rareInheritedData->quotes.get() == *q.get())
609         return;
610     rareInheritedData.access()->quotes = q;
611 }
612 
clearCursorList()613 void RenderStyle::clearCursorList()
614 {
615     if (rareInheritedData->cursorData)
616         rareInheritedData.access()->cursorData = 0;
617 }
618 
clearContent()619 void RenderStyle::clearContent()
620 {
621     if (rareNonInheritedData->m_content)
622         rareNonInheritedData->m_content->clear();
623 }
624 
prepareToSetContent(StringImpl * string,bool add)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 
setContent(PassRefPtr<StyleImage> image,bool add)658 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
659 {
660     if (!image)
661         return;
662     prepareToSetContent(0, add)->setImage(image);
663 }
664 
setContent(PassRefPtr<StringImpl> string,bool add)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 
setContent(PassOwnPtr<CounterContent> counter,bool add)673 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
674 {
675     if (!counter)
676         return;
677     prepareToSetContent(0, add)->setCounter(counter);
678 }
679 
setContent(QuoteType quote,bool add)680 void RenderStyle::setContent(QuoteType quote, bool add)
681 {
682     prepareToSetContent(0, add)->setQuote(quote);
683 }
684 
applyTransform(TransformationMatrix & transform,const IntSize & borderBoxSize,ApplyTransformOrigin applyOrigin) const685 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 
setPageScaleTransform(float scale)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 
setTextShadow(ShadowData * val,bool add)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 
setBoxShadow(ShadowData * shadowData,bool add)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 
calcRadiiFor(const BorderData & border,int width,int height)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 
calcConstraintScaleFor(const IntRect & rect,const RoundedIntRect::Radii & radii)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 
getRoundedBorderFor(const IntRect & borderRect,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const802 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 
getRoundedInnerBorderFor(const IntRect & borderRect,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const813 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 
getRoundedInnerBorderFor(const IntRect & borderRect,int topWidth,int bottomWidth,int leftWidth,int rightWidth,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const825 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 
counterDirectives() const843 const CounterDirectiveMap* RenderStyle::counterDirectives() const
844 {
845     return rareNonInheritedData->m_counterDirectives.get();
846 }
847 
accessCounterDirectives()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 
hyphenString() const856 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 
textEmphasisMarkString() const870 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)
initialDashboardRegions()912 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
913 {
914     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
915     return emptyList;
916 }
917 
noneDashboardRegions()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 
adjustAnimations()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 
adjustTransitions()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 
accessAnimations()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 
accessTransitions()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 
transitionForProperty(int property) const1010 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 
setBlendedFontSize(int size)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 
getShadowExtent(const ShadowData * shadow,int & top,int & right,int & bottom,int & left) const1033 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 
getShadowHorizontalExtent(const ShadowData * shadow,int & left,int & right) const1052 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 
getShadowVerticalExtent(const ShadowData * shadow,int & top,int & bottom) const1067 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 
borderStyleForColorProperty(const RenderStyle * style,int colorProperty)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 
colorIncludingFallback(int colorProperty,EBorderStyle borderStyle) const1105 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 
visitedDependentColor(int colorProperty) const1162 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 
logicalWidth() const1186 Length RenderStyle::logicalWidth() const
1187 {
1188     if (isHorizontalWritingMode())
1189         return width();
1190     return height();
1191 }
1192 
logicalHeight() const1193 Length RenderStyle::logicalHeight() const
1194 {
1195     if (isHorizontalWritingMode())
1196         return height();
1197     return width();
1198 }
1199 
logicalMinWidth() const1200 Length RenderStyle::logicalMinWidth() const
1201 {
1202     if (isHorizontalWritingMode())
1203         return minWidth();
1204     return minHeight();
1205 }
1206 
logicalMaxWidth() const1207 Length RenderStyle::logicalMaxWidth() const
1208 {
1209     if (isHorizontalWritingMode())
1210         return maxWidth();
1211     return maxHeight();
1212 }
1213 
logicalMinHeight() const1214 Length RenderStyle::logicalMinHeight() const
1215 {
1216     if (isHorizontalWritingMode())
1217         return minHeight();
1218     return minWidth();
1219 }
1220 
logicalMaxHeight() const1221 Length RenderStyle::logicalMaxHeight() const
1222 {
1223     if (isHorizontalWritingMode())
1224         return maxHeight();
1225     return maxWidth();
1226 }
1227 
borderBefore() const1228 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 
borderAfter() const1244 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 
borderStart() const1260 const BorderValue& RenderStyle::borderStart() const
1261 {
1262     if (isHorizontalWritingMode())
1263         return isLeftToRightDirection() ? borderLeft() : borderRight();
1264     return isLeftToRightDirection() ? borderTop() : borderBottom();
1265 }
1266 
borderEnd() const1267 const BorderValue& RenderStyle::borderEnd() const
1268 {
1269     if (isHorizontalWritingMode())
1270         return isLeftToRightDirection() ? borderRight() : borderLeft();
1271     return isLeftToRightDirection() ? borderBottom() : borderTop();
1272 }
1273 
borderBeforeWidth() const1274 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 
borderAfterWidth() const1290 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 
borderStartWidth() const1306 unsigned short RenderStyle::borderStartWidth() const
1307 {
1308     if (isHorizontalWritingMode())
1309         return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
1310     return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
1311 }
1312 
borderEndWidth() const1313 unsigned short RenderStyle::borderEndWidth() const
1314 {
1315     if (isHorizontalWritingMode())
1316         return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
1317     return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
1318 }
1319 
marginBefore() const1320 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 
marginAfter() const1336 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 
marginBeforeUsing(const RenderStyle * otherStyle) const1352 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 
marginAfterUsing(const RenderStyle * otherStyle) const1368 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 
marginStart() const1384 Length RenderStyle::marginStart() const
1385 {
1386     if (isHorizontalWritingMode())
1387         return isLeftToRightDirection() ? marginLeft() : marginRight();
1388     return isLeftToRightDirection() ? marginTop() : marginBottom();
1389 }
1390 
marginEnd() const1391 Length RenderStyle::marginEnd() const
1392 {
1393     if (isHorizontalWritingMode())
1394         return isLeftToRightDirection() ? marginRight() : marginLeft();
1395     return isLeftToRightDirection() ? marginBottom() : marginTop();
1396 }
1397 
marginStartUsing(const RenderStyle * otherStyle) const1398 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 
marginEndUsing(const RenderStyle * otherStyle) const1405 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 
setMarginStart(Length margin)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 
setMarginEnd(Length margin)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 
paddingBefore() const1442 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 
paddingAfter() const1458 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 
paddingStart() const1474 Length RenderStyle::paddingStart() const
1475 {
1476     if (isHorizontalWritingMode())
1477         return isLeftToRightDirection() ? paddingLeft() : paddingRight();
1478     return isLeftToRightDirection() ? paddingTop() : paddingBottom();
1479 }
1480 
paddingEnd() const1481 Length RenderStyle::paddingEnd() const
1482 {
1483     if (isHorizontalWritingMode())
1484         return isLeftToRightDirection() ? paddingRight() : paddingLeft();
1485     return isLeftToRightDirection() ? paddingBottom() : paddingTop();
1486 }
1487 
textEmphasisMark() const1488 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