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