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