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 = adoptPtr(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(PassOwnPtr<ShadowData> shadowData,bool add)731 void RenderStyle::setTextShadow(PassOwnPtr<ShadowData> shadowData, bool add)
732 {
733     ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal));
734 
735     StyleRareInheritedData* rareData = rareInheritedData.access();
736     if (!add) {
737         rareData->textShadow = shadowData;
738         return;
739     }
740 
741     shadowData->setNext(rareData->textShadow.release());
742     rareData->textShadow = shadowData;
743 }
744 
setBoxShadow(PassOwnPtr<ShadowData> shadowData,bool add)745 void RenderStyle::setBoxShadow(PassOwnPtr<ShadowData> shadowData, bool add)
746 {
747     StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
748     if (!add) {
749         rareData->m_boxShadow = shadowData;
750         return;
751     }
752 
753     shadowData->setNext(rareData->m_boxShadow.release());
754     rareData->m_boxShadow = shadowData;
755 }
756 
calcRadiiFor(const BorderData & border,int width,int height)757 static RoundedIntRect::Radii calcRadiiFor(const BorderData& border, int width, int height)
758 {
759     return RoundedIntRect::Radii(IntSize(border.topLeft().width().calcValue(width),
760                                          border.topLeft().height().calcValue(height)),
761                                  IntSize(border.topRight().width().calcValue(width),
762                                          border.topRight().height().calcValue(height)),
763                                  IntSize(border.bottomLeft().width().calcValue(width),
764                                          border.bottomLeft().height().calcValue(height)),
765                                  IntSize(border.bottomRight().width().calcValue(width),
766                                          border.bottomRight().height().calcValue(height)));
767 }
768 
calcConstraintScaleFor(const IntRect & rect,const RoundedIntRect::Radii & radii)769 static float calcConstraintScaleFor(const IntRect& rect, const RoundedIntRect::Radii& radii)
770 {
771     // Constrain corner radii using CSS3 rules:
772     // http://www.w3.org/TR/css3-background/#the-border-radius
773 
774     float factor = 1;
775     unsigned radiiSum;
776 
777     // top
778     radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow.
779     if (radiiSum > static_cast<unsigned>(rect.width()))
780         factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
781 
782     // bottom
783     radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width());
784     if (radiiSum > static_cast<unsigned>(rect.width()))
785         factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
786 
787     // left
788     radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height());
789     if (radiiSum > static_cast<unsigned>(rect.height()))
790         factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
791 
792     // right
793     radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height());
794     if (radiiSum > static_cast<unsigned>(rect.height()))
795         factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
796 
797     ASSERT(factor <= 1);
798     return factor;
799 }
800 
getRoundedBorderFor(const IntRect & borderRect,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const801 RoundedIntRect RenderStyle::getRoundedBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
802 {
803     RoundedIntRect roundedRect(borderRect);
804     if (hasBorderRadius()) {
805         RoundedIntRect::Radii radii = calcRadiiFor(surround->border, borderRect.width(), borderRect.height());
806         radii.scale(calcConstraintScaleFor(borderRect, radii));
807         roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
808     }
809     return roundedRect;
810 }
811 
getRoundedInnerBorderFor(const IntRect & borderRect,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const812 RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
813 {
814     bool horizontal = isHorizontalWritingMode();
815 
816     int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
817     int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
818     int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
819     int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
820 
821     return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
822 }
823 
getRoundedInnerBorderFor(const IntRect & borderRect,int topWidth,int bottomWidth,int leftWidth,int rightWidth,bool includeLogicalLeftEdge,bool includeLogicalRightEdge) const824 RoundedIntRect RenderStyle::getRoundedInnerBorderFor(const IntRect& borderRect,
825     int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
826 {
827     IntRect innerRect(borderRect.x() + leftWidth,
828             borderRect.y() + topWidth,
829             borderRect.width() - leftWidth - rightWidth,
830             borderRect.height() - topWidth - bottomWidth);
831 
832     RoundedIntRect roundedRect(innerRect);
833 
834     if (hasBorderRadius()) {
835         RoundedIntRect::Radii radii = getRoundedBorderFor(borderRect).radii();
836         radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
837         roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
838     }
839     return roundedRect;
840 }
841 
counterDirectives() const842 const CounterDirectiveMap* RenderStyle::counterDirectives() const
843 {
844     return rareNonInheritedData->m_counterDirectives.get();
845 }
846 
accessCounterDirectives()847 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
848 {
849     OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
850     if (!map)
851         map = adoptPtr(new CounterDirectiveMap);
852     return *map;
853 }
854 
hyphenString() const855 const AtomicString& RenderStyle::hyphenString() const
856 {
857     ASSERT(hyphens() != HyphensNone);
858 
859     const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString;
860     if (!hyphenationString.isNull())
861         return hyphenationString;
862 
863     // FIXME: This should depend on locale.
864     DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1));
865     DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1));
866     return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString;
867 }
868 
textEmphasisMarkString() const869 const AtomicString& RenderStyle::textEmphasisMarkString() const
870 {
871     switch (textEmphasisMark()) {
872     case TextEmphasisMarkNone:
873         return nullAtom;
874     case TextEmphasisMarkCustom:
875         return textEmphasisCustomMark();
876     case TextEmphasisMarkDot: {
877         DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1));
878         DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1));
879         return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString;
880     }
881     case TextEmphasisMarkCircle: {
882         DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1));
883         DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1));
884         return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString;
885     }
886     case TextEmphasisMarkDoubleCircle: {
887         DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1));
888         DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1));
889         return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString;
890     }
891     case TextEmphasisMarkTriangle: {
892         DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1));
893         DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1));
894         return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString;
895     }
896     case TextEmphasisMarkSesame: {
897         DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1));
898         DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1));
899         return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString;
900     }
901     case TextEmphasisMarkAuto:
902         ASSERT_NOT_REACHED();
903         return nullAtom;
904     }
905 
906     ASSERT_NOT_REACHED();
907     return nullAtom;
908 }
909 
910 #if ENABLE(DASHBOARD_SUPPORT)
initialDashboardRegions()911 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
912 {
913     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
914     return emptyList;
915 }
916 
noneDashboardRegions()917 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
918 {
919     DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
920     static bool noneListInitialized = false;
921 
922     if (!noneListInitialized) {
923         StyleDashboardRegion region;
924         region.label = "";
925         region.offset.m_top  = Length();
926         region.offset.m_right = Length();
927         region.offset.m_bottom = Length();
928         region.offset.m_left = Length();
929         region.type = StyleDashboardRegion::None;
930         noneList.append(region);
931         noneListInitialized = true;
932     }
933     return noneList;
934 }
935 #endif
936 
adjustAnimations()937 void RenderStyle::adjustAnimations()
938 {
939     AnimationList* animationList = rareNonInheritedData->m_animations.get();
940     if (!animationList)
941         return;
942 
943     // Get rid of empty animations and anything beyond them
944     for (size_t i = 0; i < animationList->size(); ++i) {
945         if (animationList->animation(i)->isEmpty()) {
946             animationList->resize(i);
947             break;
948         }
949     }
950 
951     if (animationList->isEmpty()) {
952         clearAnimations();
953         return;
954     }
955 
956     // Repeat patterns into layers that don't have some properties set.
957     animationList->fillUnsetProperties();
958 }
959 
adjustTransitions()960 void RenderStyle::adjustTransitions()
961 {
962     AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
963     if (!transitionList)
964         return;
965 
966     // Get rid of empty transitions and anything beyond them
967     for (size_t i = 0; i < transitionList->size(); ++i) {
968         if (transitionList->animation(i)->isEmpty()) {
969             transitionList->resize(i);
970             break;
971         }
972     }
973 
974     if (transitionList->isEmpty()) {
975         clearTransitions();
976         return;
977     }
978 
979     // Repeat patterns into layers that don't have some properties set.
980     transitionList->fillUnsetProperties();
981 
982     // Make sure there are no duplicate properties. This is an O(n^2) algorithm
983     // but the lists tend to be very short, so it is probably ok
984     for (size_t i = 0; i < transitionList->size(); ++i) {
985         for (size_t j = i+1; j < transitionList->size(); ++j) {
986             if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
987                 // toss i
988                 transitionList->remove(i);
989                 j = i;
990             }
991         }
992     }
993 }
994 
accessAnimations()995 AnimationList* RenderStyle::accessAnimations()
996 {
997     if (!rareNonInheritedData.access()->m_animations)
998         rareNonInheritedData.access()->m_animations = adoptPtr(new AnimationList());
999     return rareNonInheritedData->m_animations.get();
1000 }
1001 
accessTransitions()1002 AnimationList* RenderStyle::accessTransitions()
1003 {
1004     if (!rareNonInheritedData.access()->m_transitions)
1005         rareNonInheritedData.access()->m_transitions = adoptPtr(new AnimationList());
1006     return rareNonInheritedData->m_transitions.get();
1007 }
1008 
transitionForProperty(int property) const1009 const Animation* RenderStyle::transitionForProperty(int property) const
1010 {
1011     if (transitions()) {
1012         for (size_t i = 0; i < transitions()->size(); ++i) {
1013             const Animation* p = transitions()->animation(i);
1014             if (p->property() == cAnimateAll || p->property() == property) {
1015                 return p;
1016             }
1017         }
1018     }
1019     return 0;
1020 }
1021 
setBlendedFontSize(int size)1022 void RenderStyle::setBlendedFontSize(int size)
1023 {
1024     FontSelector* currentFontSelector = font().fontSelector();
1025     FontDescription desc(fontDescription());
1026     desc.setSpecifiedSize(size);
1027     desc.setComputedSize(size);
1028     setFontDescription(desc);
1029     font().update(currentFontSelector);
1030 }
1031 
getShadowExtent(const ShadowData * shadow,int & top,int & right,int & bottom,int & left) const1032 void RenderStyle::getShadowExtent(const ShadowData* shadow, int &top, int &right, int &bottom, int &left) const
1033 {
1034     top = 0;
1035     right = 0;
1036     bottom = 0;
1037     left = 0;
1038 
1039     for ( ; shadow; shadow = shadow->next()) {
1040         if (shadow->style() == Inset)
1041             continue;
1042         int blurAndSpread = shadow->blur() + shadow->spread();
1043 
1044         top = min(top, shadow->y() - blurAndSpread);
1045         right = max(right, shadow->x() + blurAndSpread);
1046         bottom = max(bottom, shadow->y() + blurAndSpread);
1047         left = min(left, shadow->x() - blurAndSpread);
1048     }
1049 }
1050 
getShadowHorizontalExtent(const ShadowData * shadow,int & left,int & right) const1051 void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, int &left, int &right) const
1052 {
1053     left = 0;
1054     right = 0;
1055 
1056     for ( ; shadow; shadow = shadow->next()) {
1057         if (shadow->style() == Inset)
1058             continue;
1059         int blurAndSpread = shadow->blur() + shadow->spread();
1060 
1061         left = min(left, shadow->x() - blurAndSpread);
1062         right = max(right, shadow->x() + blurAndSpread);
1063     }
1064 }
1065 
getShadowVerticalExtent(const ShadowData * shadow,int & top,int & bottom) const1066 void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, int &top, int &bottom) const
1067 {
1068     top = 0;
1069     bottom = 0;
1070 
1071     for ( ; shadow; shadow = shadow->next()) {
1072         if (shadow->style() == Inset)
1073             continue;
1074         int blurAndSpread = shadow->blur() + shadow->spread();
1075 
1076         top = min(top, shadow->y() - blurAndSpread);
1077         bottom = max(bottom, shadow->y() + blurAndSpread);
1078     }
1079 }
1080 
borderStyleForColorProperty(const RenderStyle * style,int colorProperty)1081 static EBorderStyle borderStyleForColorProperty(const RenderStyle* style, int colorProperty)
1082 {
1083     EBorderStyle borderStyle;
1084     switch (colorProperty) {
1085     case CSSPropertyBorderLeftColor:
1086         borderStyle = style->borderLeftStyle();
1087         break;
1088     case CSSPropertyBorderRightColor:
1089         borderStyle = style->borderRightStyle();
1090         break;
1091     case CSSPropertyBorderTopColor:
1092         borderStyle = style->borderTopStyle();
1093         break;
1094     case CSSPropertyBorderBottomColor:
1095         borderStyle = style->borderBottomStyle();
1096         break;
1097     default:
1098         borderStyle = BNONE;
1099         break;
1100     }
1101     return borderStyle;
1102 }
1103 
colorIncludingFallback(int colorProperty,EBorderStyle borderStyle) const1104 const Color RenderStyle::colorIncludingFallback(int colorProperty, EBorderStyle borderStyle) const
1105 {
1106     Color result;
1107     switch (colorProperty) {
1108     case CSSPropertyBackgroundColor:
1109         return backgroundColor(); // Background color doesn't fall back.
1110     case CSSPropertyBorderLeftColor:
1111         result = borderLeftColor();
1112         borderStyle = borderLeftStyle();
1113         break;
1114     case CSSPropertyBorderRightColor:
1115         result = borderRightColor();
1116         borderStyle = borderRightStyle();
1117         break;
1118     case CSSPropertyBorderTopColor:
1119         result = borderTopColor();
1120         borderStyle = borderTopStyle();
1121         break;
1122     case CSSPropertyBorderBottomColor:
1123         result = borderBottomColor();
1124         borderStyle = borderBottomStyle();
1125         break;
1126     case CSSPropertyColor:
1127         result = color();
1128         break;
1129     case CSSPropertyOutlineColor:
1130         result = outlineColor();
1131         break;
1132     case CSSPropertyWebkitColumnRuleColor:
1133         result = columnRuleColor();
1134         break;
1135     case CSSPropertyWebkitTextEmphasisColor:
1136         result = textEmphasisColor();
1137         break;
1138     case CSSPropertyWebkitTextFillColor:
1139         result = textFillColor();
1140         break;
1141     case CSSPropertyWebkitTextStrokeColor:
1142         result = textStrokeColor();
1143         break;
1144     default:
1145         ASSERT_NOT_REACHED();
1146         break;
1147     }
1148 
1149     if (!result.isValid()) {
1150         if ((colorProperty == CSSPropertyBorderLeftColor || colorProperty == CSSPropertyBorderRightColor
1151             || colorProperty == CSSPropertyBorderTopColor || colorProperty == CSSPropertyBorderBottomColor)
1152             && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1153             result.setRGB(238, 238, 238);
1154         else
1155             result = color();
1156     }
1157 
1158     return result;
1159 }
1160 
visitedDependentColor(int colorProperty) const1161 const Color RenderStyle::visitedDependentColor(int colorProperty) const
1162 {
1163     EBorderStyle borderStyle = borderStyleForColorProperty(this, colorProperty);
1164     Color unvisitedColor = colorIncludingFallback(colorProperty, borderStyle);
1165     if (insideLink() != InsideVisitedLink)
1166         return unvisitedColor;
1167 
1168     RenderStyle* visitedStyle = getCachedPseudoStyle(VISITED_LINK);
1169     if (!visitedStyle)
1170         return unvisitedColor;
1171     Color visitedColor = visitedStyle->colorIncludingFallback(colorProperty, borderStyle);
1172 
1173     // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
1174     // assume that if the background color is transparent that it wasn't set. Note that it's weird that
1175     // we're returning unvisited info for a visited link, but given our restriction that the alpha values
1176     // have to match, it makes more sense to return the unvisited background color if specified than it
1177     // does to return black. This behavior matches what Firefox 4 does as well.
1178     if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent)
1179         return unvisitedColor;
1180 
1181     // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1182     return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1183 }
1184 
logicalWidth() const1185 Length RenderStyle::logicalWidth() const
1186 {
1187     if (isHorizontalWritingMode())
1188         return width();
1189     return height();
1190 }
1191 
logicalHeight() const1192 Length RenderStyle::logicalHeight() const
1193 {
1194     if (isHorizontalWritingMode())
1195         return height();
1196     return width();
1197 }
1198 
logicalMinWidth() const1199 Length RenderStyle::logicalMinWidth() const
1200 {
1201     if (isHorizontalWritingMode())
1202         return minWidth();
1203     return minHeight();
1204 }
1205 
logicalMaxWidth() const1206 Length RenderStyle::logicalMaxWidth() const
1207 {
1208     if (isHorizontalWritingMode())
1209         return maxWidth();
1210     return maxHeight();
1211 }
1212 
logicalMinHeight() const1213 Length RenderStyle::logicalMinHeight() const
1214 {
1215     if (isHorizontalWritingMode())
1216         return minHeight();
1217     return minWidth();
1218 }
1219 
logicalMaxHeight() const1220 Length RenderStyle::logicalMaxHeight() const
1221 {
1222     if (isHorizontalWritingMode())
1223         return maxHeight();
1224     return maxWidth();
1225 }
1226 
borderBefore() const1227 const BorderValue& RenderStyle::borderBefore() const
1228 {
1229     switch (writingMode()) {
1230     case TopToBottomWritingMode:
1231         return borderTop();
1232     case BottomToTopWritingMode:
1233         return borderBottom();
1234     case LeftToRightWritingMode:
1235         return borderLeft();
1236     case RightToLeftWritingMode:
1237         return borderRight();
1238     }
1239     ASSERT_NOT_REACHED();
1240     return borderTop();
1241 }
1242 
borderAfter() const1243 const BorderValue& RenderStyle::borderAfter() const
1244 {
1245     switch (writingMode()) {
1246     case TopToBottomWritingMode:
1247         return borderBottom();
1248     case BottomToTopWritingMode:
1249         return borderTop();
1250     case LeftToRightWritingMode:
1251         return borderRight();
1252     case RightToLeftWritingMode:
1253         return borderLeft();
1254     }
1255     ASSERT_NOT_REACHED();
1256     return borderBottom();
1257 }
1258 
borderStart() const1259 const BorderValue& RenderStyle::borderStart() const
1260 {
1261     if (isHorizontalWritingMode())
1262         return isLeftToRightDirection() ? borderLeft() : borderRight();
1263     return isLeftToRightDirection() ? borderTop() : borderBottom();
1264 }
1265 
borderEnd() const1266 const BorderValue& RenderStyle::borderEnd() const
1267 {
1268     if (isHorizontalWritingMode())
1269         return isLeftToRightDirection() ? borderRight() : borderLeft();
1270     return isLeftToRightDirection() ? borderBottom() : borderTop();
1271 }
1272 
borderBeforeWidth() const1273 unsigned short RenderStyle::borderBeforeWidth() const
1274 {
1275     switch (writingMode()) {
1276     case TopToBottomWritingMode:
1277         return borderTopWidth();
1278     case BottomToTopWritingMode:
1279         return borderBottomWidth();
1280     case LeftToRightWritingMode:
1281         return borderLeftWidth();
1282     case RightToLeftWritingMode:
1283         return borderRightWidth();
1284     }
1285     ASSERT_NOT_REACHED();
1286     return borderTopWidth();
1287 }
1288 
borderAfterWidth() const1289 unsigned short RenderStyle::borderAfterWidth() const
1290 {
1291     switch (writingMode()) {
1292     case TopToBottomWritingMode:
1293         return borderBottomWidth();
1294     case BottomToTopWritingMode:
1295         return borderTopWidth();
1296     case LeftToRightWritingMode:
1297         return borderRightWidth();
1298     case RightToLeftWritingMode:
1299         return borderLeftWidth();
1300     }
1301     ASSERT_NOT_REACHED();
1302     return borderBottomWidth();
1303 }
1304 
borderStartWidth() const1305 unsigned short RenderStyle::borderStartWidth() const
1306 {
1307     if (isHorizontalWritingMode())
1308         return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
1309     return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
1310 }
1311 
borderEndWidth() const1312 unsigned short RenderStyle::borderEndWidth() const
1313 {
1314     if (isHorizontalWritingMode())
1315         return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
1316     return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
1317 }
1318 
marginBefore() const1319 Length RenderStyle::marginBefore() const
1320 {
1321     switch (writingMode()) {
1322     case TopToBottomWritingMode:
1323         return marginTop();
1324     case BottomToTopWritingMode:
1325         return marginBottom();
1326     case LeftToRightWritingMode:
1327         return marginLeft();
1328     case RightToLeftWritingMode:
1329         return marginRight();
1330     }
1331     ASSERT_NOT_REACHED();
1332     return marginTop();
1333 }
1334 
marginAfter() const1335 Length RenderStyle::marginAfter() const
1336 {
1337     switch (writingMode()) {
1338     case TopToBottomWritingMode:
1339         return marginBottom();
1340     case BottomToTopWritingMode:
1341         return marginTop();
1342     case LeftToRightWritingMode:
1343         return marginRight();
1344     case RightToLeftWritingMode:
1345         return marginLeft();
1346     }
1347     ASSERT_NOT_REACHED();
1348     return marginBottom();
1349 }
1350 
marginBeforeUsing(const RenderStyle * otherStyle) const1351 Length RenderStyle::marginBeforeUsing(const RenderStyle* otherStyle) const
1352 {
1353     switch (otherStyle->writingMode()) {
1354     case TopToBottomWritingMode:
1355         return marginTop();
1356     case BottomToTopWritingMode:
1357         return marginBottom();
1358     case LeftToRightWritingMode:
1359         return marginLeft();
1360     case RightToLeftWritingMode:
1361         return marginRight();
1362     }
1363     ASSERT_NOT_REACHED();
1364     return marginTop();
1365 }
1366 
marginAfterUsing(const RenderStyle * otherStyle) const1367 Length RenderStyle::marginAfterUsing(const RenderStyle* otherStyle) const
1368 {
1369     switch (otherStyle->writingMode()) {
1370     case TopToBottomWritingMode:
1371         return marginBottom();
1372     case BottomToTopWritingMode:
1373         return marginTop();
1374     case LeftToRightWritingMode:
1375         return marginRight();
1376     case RightToLeftWritingMode:
1377         return marginLeft();
1378     }
1379     ASSERT_NOT_REACHED();
1380     return marginBottom();
1381 }
1382 
marginStart() const1383 Length RenderStyle::marginStart() const
1384 {
1385     if (isHorizontalWritingMode())
1386         return isLeftToRightDirection() ? marginLeft() : marginRight();
1387     return isLeftToRightDirection() ? marginTop() : marginBottom();
1388 }
1389 
marginEnd() const1390 Length RenderStyle::marginEnd() const
1391 {
1392     if (isHorizontalWritingMode())
1393         return isLeftToRightDirection() ? marginRight() : marginLeft();
1394     return isLeftToRightDirection() ? marginBottom() : marginTop();
1395 }
1396 
marginStartUsing(const RenderStyle * otherStyle) const1397 Length RenderStyle::marginStartUsing(const RenderStyle* otherStyle) const
1398 {
1399     if (otherStyle->isHorizontalWritingMode())
1400         return otherStyle->isLeftToRightDirection() ? marginLeft() : marginRight();
1401     return otherStyle->isLeftToRightDirection() ? marginTop() : marginBottom();
1402 }
1403 
marginEndUsing(const RenderStyle * otherStyle) const1404 Length RenderStyle::marginEndUsing(const RenderStyle* otherStyle) const
1405 {
1406     if (otherStyle->isHorizontalWritingMode())
1407         return otherStyle->isLeftToRightDirection() ? marginRight() : marginLeft();
1408     return otherStyle->isLeftToRightDirection() ? marginBottom() : marginTop();
1409 }
1410 
setMarginStart(Length margin)1411 void RenderStyle::setMarginStart(Length margin)
1412 {
1413     if (isHorizontalWritingMode()) {
1414         if (isLeftToRightDirection())
1415             setMarginLeft(margin);
1416         else
1417             setMarginRight(margin);
1418     } else {
1419         if (isLeftToRightDirection())
1420             setMarginTop(margin);
1421         else
1422             setMarginBottom(margin);
1423     }
1424 }
1425 
setMarginEnd(Length margin)1426 void RenderStyle::setMarginEnd(Length margin)
1427 {
1428     if (isHorizontalWritingMode()) {
1429         if (isLeftToRightDirection())
1430             setMarginRight(margin);
1431         else
1432             setMarginLeft(margin);
1433     } else {
1434         if (isLeftToRightDirection())
1435             setMarginBottom(margin);
1436         else
1437             setMarginTop(margin);
1438     }
1439 }
1440 
paddingBefore() const1441 Length RenderStyle::paddingBefore() const
1442 {
1443     switch (writingMode()) {
1444     case TopToBottomWritingMode:
1445         return paddingTop();
1446     case BottomToTopWritingMode:
1447         return paddingBottom();
1448     case LeftToRightWritingMode:
1449         return paddingLeft();
1450     case RightToLeftWritingMode:
1451         return paddingRight();
1452     }
1453     ASSERT_NOT_REACHED();
1454     return paddingTop();
1455 }
1456 
paddingAfter() const1457 Length RenderStyle::paddingAfter() const
1458 {
1459     switch (writingMode()) {
1460     case TopToBottomWritingMode:
1461         return paddingBottom();
1462     case BottomToTopWritingMode:
1463         return paddingTop();
1464     case LeftToRightWritingMode:
1465         return paddingRight();
1466     case RightToLeftWritingMode:
1467         return paddingLeft();
1468     }
1469     ASSERT_NOT_REACHED();
1470     return paddingBottom();
1471 }
1472 
paddingStart() const1473 Length RenderStyle::paddingStart() const
1474 {
1475     if (isHorizontalWritingMode())
1476         return isLeftToRightDirection() ? paddingLeft() : paddingRight();
1477     return isLeftToRightDirection() ? paddingTop() : paddingBottom();
1478 }
1479 
paddingEnd() const1480 Length RenderStyle::paddingEnd() const
1481 {
1482     if (isHorizontalWritingMode())
1483         return isLeftToRightDirection() ? paddingRight() : paddingLeft();
1484     return isLeftToRightDirection() ? paddingBottom() : paddingTop();
1485 }
1486 
textEmphasisMark() const1487 TextEmphasisMark RenderStyle::textEmphasisMark() const
1488 {
1489     TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark);
1490     if (mark != TextEmphasisMarkAuto)
1491         return mark;
1492 
1493     if (isHorizontalWritingMode())
1494         return TextEmphasisMarkDot;
1495 
1496     return TextEmphasisMarkSesame;
1497 }
1498 
1499 } // namespace WebCore
1500