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 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
24 #include "RenderStyle.h"
26 #include "ContentData.h"
27 #include "CursorList.h"
28 #include "CSSPropertyNames.h"
30 #include "FontSelector.h"
31 #include "QuotesData.h"
32 #include "RenderArena.h"
33 #include "RenderObject.h"
34 #include "ScaleTransformOperation.h"
35 #include "ShadowData.h"
36 #include "StyleImage.h"
37 #include "StyleInheritedData.h"
38 #include "StyleResolver.h"
39 #if ENABLE(TOUCH_EVENTS)
40 #include "RenderTheme.h"
42 #include "WebCoreMemoryInstrumentation.h"
43 #include <wtf/MathExtras.h>
44 #include <wtf/MemoryInstrumentationVector.h>
45 #include <wtf/MemoryObjectInfo.h>
46 #include <wtf/StdLibExtras.h>
49 #if ENABLE(TEXT_AUTOSIZING)
50 #include "TextAutosizer.h"
57 struct SameSizeAsBorderValue {
62 COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow);
64 struct SameSizeAsRenderStyle : public RefCounted<SameSizeAsRenderStyle> {
68 void* dataRefSvgStyle;
70 struct InheritedFlags {
71 unsigned m_bitfields[2];
74 struct NonInheritedFlags {
75 unsigned m_bitfields[2];
79 COMPILE_ASSERT(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), RenderStyle_should_stay_small);
81 inline RenderStyle* defaultStyle()
83 static RenderStyle* s_defaultStyle = RenderStyle::createDefaultStyle().leakRef();
84 return s_defaultStyle;
87 PassRefPtr<RenderStyle> RenderStyle::create()
89 return adoptRef(new RenderStyle());
92 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
94 return adoptRef(new RenderStyle(true));
97 PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay display)
99 RefPtr<RenderStyle> newStyle = RenderStyle::create();
100 newStyle->inheritFrom(parentStyle);
101 newStyle->inheritUnicodeBidiFrom(parentStyle);
102 newStyle->setDisplay(display);
106 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
108 return adoptRef(new RenderStyle(*other));
111 ALWAYS_INLINE RenderStyle::RenderStyle()
112 : m_box(defaultStyle()->m_box)
113 , visual(defaultStyle()->visual)
114 , m_background(defaultStyle()->m_background)
115 , surround(defaultStyle()->surround)
116 , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
117 , rareInheritedData(defaultStyle()->rareInheritedData)
118 , inherited(defaultStyle()->inherited)
120 , m_svgStyle(defaultStyle()->m_svgStyle)
123 setBitDefaults(); // Would it be faster to copy this from the default style?
124 COMPILE_ASSERT((sizeof(InheritedFlags) <= 8), InheritedFlags_does_not_grow);
125 COMPILE_ASSERT((sizeof(NonInheritedFlags) <= 8), NonInheritedFlags_does_not_grow);
128 ALWAYS_INLINE RenderStyle::RenderStyle(bool)
136 rareNonInheritedData.init();
137 rareNonInheritedData.access()->m_deprecatedFlexibleBox.init();
138 rareNonInheritedData.access()->m_flexibleBox.init();
139 rareNonInheritedData.access()->m_marquee.init();
140 rareNonInheritedData.access()->m_multiCol.init();
141 rareNonInheritedData.access()->m_transform.init();
142 #if ENABLE(CSS_FILTERS)
143 rareNonInheritedData.access()->m_filter.init();
145 rareNonInheritedData.access()->m_grid.init();
146 rareNonInheritedData.access()->m_gridItem.init();
147 rareInheritedData.init();
154 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
155 : RefCounted<RenderStyle>()
158 , m_background(o.m_background)
159 , surround(o.surround)
160 , rareNonInheritedData(o.rareNonInheritedData)
161 , rareInheritedData(o.rareInheritedData)
162 , inherited(o.inherited)
164 , m_svgStyle(o.m_svgStyle)
166 , inherited_flags(o.inherited_flags)
167 , noninherited_flags(o.noninherited_flags)
171 void RenderStyle::inheritFrom(const RenderStyle* inheritParent, IsAtShadowBoundary isAtShadowBoundary)
173 if (isAtShadowBoundary == AtShadowBoundary) {
174 // Even if surrounding content is user-editable, shadow DOM should act as a single unit, and not necessarily be editable
175 EUserModify currentUserModify = userModify();
176 rareInheritedData = inheritParent->rareInheritedData;
177 setUserModify(currentUserModify);
179 rareInheritedData = inheritParent->rareInheritedData;
180 inherited = inheritParent->inherited;
181 inherited_flags = inheritParent->inherited_flags;
183 if (m_svgStyle != inheritParent->m_svgStyle)
184 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
188 void RenderStyle::copyNonInheritedFrom(const RenderStyle* other)
190 m_box = other->m_box;
191 visual = other->visual;
192 m_background = other->m_background;
193 surround = other->surround;
194 rareNonInheritedData = other->rareNonInheritedData;
195 // The flags are copied one-by-one because noninherited_flags contains a bunch of stuff other than real style data.
196 noninherited_flags._effectiveDisplay = other->noninherited_flags._effectiveDisplay;
197 noninherited_flags._originalDisplay = other->noninherited_flags._originalDisplay;
198 noninherited_flags._overflowX = other->noninherited_flags._overflowX;
199 noninherited_flags._overflowY = other->noninherited_flags._overflowY;
200 noninherited_flags._vertical_align = other->noninherited_flags._vertical_align;
201 noninherited_flags._clear = other->noninherited_flags._clear;
202 noninherited_flags._position = other->noninherited_flags._position;
203 noninherited_flags._floating = other->noninherited_flags._floating;
204 noninherited_flags._table_layout = other->noninherited_flags._table_layout;
205 noninherited_flags._unicodeBidi = other->noninherited_flags._unicodeBidi;
206 noninherited_flags._page_break_before = other->noninherited_flags._page_break_before;
207 noninherited_flags._page_break_after = other->noninherited_flags._page_break_after;
208 noninherited_flags._page_break_inside = other->noninherited_flags._page_break_inside;
209 noninherited_flags.explicitInheritance = other->noninherited_flags.explicitInheritance;
211 if (m_svgStyle != other->m_svgStyle)
212 m_svgStyle.access()->copyNonInheritedFrom(other->m_svgStyle.get());
214 ASSERT(zoom() == initialZoom());
217 bool RenderStyle::operator==(const RenderStyle& o) const
219 // compare everything except the pseudoStyle pointer
220 return inherited_flags == o.inherited_flags
221 && noninherited_flags == o.noninherited_flags
223 && visual == o.visual
224 && m_background == o.m_background
225 && surround == o.surround
226 && rareNonInheritedData == o.rareNonInheritedData
227 && rareInheritedData == o.rareInheritedData
228 && inherited == o.inherited
230 && m_svgStyle == o.m_svgStyle
235 bool RenderStyle::isStyleAvailable() const
237 return this != StyleResolver::styleNotYetAvailable();
240 static inline int pseudoBit(PseudoId pseudo)
242 return 1 << (pseudo - 1);
245 bool RenderStyle::hasAnyPublicPseudoStyles() const
247 return PUBLIC_PSEUDOID_MASK & noninherited_flags._pseudoBits;
250 bool RenderStyle::hasPseudoStyle(PseudoId pseudo) const
252 ASSERT(pseudo > NOPSEUDO);
253 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
254 return pseudoBit(pseudo) & noninherited_flags._pseudoBits;
257 void RenderStyle::setHasPseudoStyle(PseudoId pseudo)
259 ASSERT(pseudo > NOPSEUDO);
260 ASSERT(pseudo < FIRST_INTERNAL_PSEUDOID);
261 noninherited_flags._pseudoBits |= pseudoBit(pseudo);
264 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
266 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
269 if (styleType() != NOPSEUDO)
272 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
273 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
274 if (pseudoStyle->styleType() == pid)
281 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
286 ASSERT(pseudo->styleType() > NOPSEUDO);
288 RenderStyle* result = pseudo.get();
290 if (!m_cachedPseudoStyles)
291 m_cachedPseudoStyles = adoptPtr(new PseudoStyleCache);
293 m_cachedPseudoStyles->append(pseudo);
298 void RenderStyle::removeCachedPseudoStyle(PseudoId pid)
300 if (!m_cachedPseudoStyles)
302 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
303 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
304 if (pseudoStyle->styleType() == pid) {
305 m_cachedPseudoStyles->remove(i);
311 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
313 return inherited_flags != other->inherited_flags
314 || inherited != other->inherited
316 || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get())
318 || rareInheritedData != other->rareInheritedData;
321 bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
323 // This is a fast check that only looks if the data structures are shared.
324 return inherited_flags == other->inherited_flags
325 && inherited.get() == other->inherited.get()
327 && m_svgStyle.get() == other->m_svgStyle.get()
329 && rareInheritedData.get() == other->rareInheritedData.get();
332 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
334 // If any unit types are different, then we can't guarantee
335 // that this was just a movement.
336 if (a.left().type() != b.left().type()
337 || a.right().type() != b.right().type()
338 || a.top().type() != b.top().type()
339 || a.bottom().type() != b.bottom().type())
342 // Only one unit can be non-auto in the horizontal direction and
343 // in the vertical direction. Otherwise the adjustment of values
344 // is changing the size of the box.
345 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
347 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
350 // One of the units is fixed or percent in both directions and stayed
351 // that way in the new style. Therefore all we are doing is moving.
355 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
357 changedContextSensitiveProperties = ContextSensitivePropertyNone;
360 StyleDifference svgChange = StyleDifferenceEqual;
361 if (m_svgStyle != other->m_svgStyle) {
362 svgChange = m_svgStyle->diff(other->m_svgStyle.get());
363 if (svgChange == StyleDifferenceLayout)
368 if (m_box->width() != other->m_box->width()
369 || m_box->minWidth() != other->m_box->minWidth()
370 || m_box->maxWidth() != other->m_box->maxWidth()
371 || m_box->height() != other->m_box->height()
372 || m_box->minHeight() != other->m_box->minHeight()
373 || m_box->maxHeight() != other->m_box->maxHeight())
374 return StyleDifferenceLayout;
376 if (m_box->verticalAlign() != other->m_box->verticalAlign() || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
377 return StyleDifferenceLayout;
379 if (m_box->boxSizing() != other->m_box->boxSizing())
380 return StyleDifferenceLayout;
382 if (surround->margin != other->surround->margin)
383 return StyleDifferenceLayout;
385 if (surround->padding != other->surround->padding)
386 return StyleDifferenceLayout;
388 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
389 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance
390 || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse
391 || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse
392 || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp
393 || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow)
394 return StyleDifferenceLayout;
396 if (rareNonInheritedData->m_regionOverflow != other->rareNonInheritedData->m_regionOverflow)
397 return StyleDifferenceLayout;
399 if (rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow
400 || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough
401 || rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin
402 || rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding)
403 return StyleDifferenceLayout;
405 if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get()
406 && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get())
407 return StyleDifferenceLayout;
409 if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get()
410 && *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get())
411 return StyleDifferenceLayout;
412 if (rareNonInheritedData->m_order != other->rareNonInheritedData->m_order
413 || rareNonInheritedData->m_alignContent != other->rareNonInheritedData->m_alignContent
414 || rareNonInheritedData->m_alignItems != other->rareNonInheritedData->m_alignItems
415 || rareNonInheritedData->m_alignSelf != other->rareNonInheritedData->m_alignSelf
416 || rareNonInheritedData->m_justifyContent != other->rareNonInheritedData->m_justifyContent)
417 return StyleDifferenceLayout;
419 // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
420 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
421 return StyleDifferenceLayout;
423 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
424 return StyleDifferenceLayout;
426 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get()
427 && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
428 return StyleDifferenceLayout;
430 if (rareNonInheritedData->m_transform.get() != other->rareNonInheritedData->m_transform.get()
431 && *rareNonInheritedData->m_transform.get() != *other->rareNonInheritedData->m_transform.get()) {
432 #if USE(ACCELERATED_COMPOSITING)
433 changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
434 // Don't return; keep looking for another change
436 return StyleDifferenceLayout;
440 if (rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get()
441 || rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get())
442 return StyleDifferenceLayout;
444 #if !USE(ACCELERATED_COMPOSITING)
445 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
446 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
447 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility
448 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
449 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
450 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
451 return StyleDifferenceLayout;
455 #if ENABLE(DASHBOARD_SUPPORT)
456 // If regions change, trigger a relayout to re-calc regions.
457 if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions)
458 return StyleDifferenceLayout;
461 #if ENABLE(CSS_EXCLUSIONS)
462 if (rareNonInheritedData->m_shapeInside != other->rareNonInheritedData->m_shapeInside)
463 return StyleDifferenceLayout;
467 if (rareInheritedData.get() != other->rareInheritedData.get()) {
468 if (rareInheritedData->highlight != other->rareInheritedData->highlight
469 || rareInheritedData->indent != other->rareInheritedData->indent
470 || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom
471 || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust
472 || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak
473 || rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap
474 || rareInheritedData->nbspMode != other->rareInheritedData->nbspMode
475 || rareInheritedData->lineBreak != other->rareInheritedData->lineBreak
476 || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity
477 || rareInheritedData->hyphens != other->rareInheritedData->hyphens
478 || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore
479 || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter
480 || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString
481 || rareInheritedData->locale != other->rareInheritedData->locale
482 || rareInheritedData->m_rubyPosition != other->rareInheritedData->m_rubyPosition
483 || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark
484 || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition
485 || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark
486 || rareInheritedData->m_textOrientation != other->rareInheritedData->m_textOrientation
487 || rareInheritedData->m_tabSize != other->rareInheritedData->m_tabSize
488 || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain
489 || rareInheritedData->m_lineGrid != other->rareInheritedData->m_lineGrid
490 #if ENABLE(CSS_IMAGE_RESOLUTION)
491 || rareInheritedData->m_imageResolutionSource != other->rareInheritedData->m_imageResolutionSource
492 || rareInheritedData->m_imageResolutionSnap != other->rareInheritedData->m_imageResolutionSnap
493 || rareInheritedData->m_imageResolution != other->rareInheritedData->m_imageResolution
495 || rareInheritedData->m_lineSnap != other->rareInheritedData->m_lineSnap
496 || rareInheritedData->m_lineAlign != other->rareInheritedData->m_lineAlign
497 || rareInheritedData->listStyleImage != other->rareInheritedData->listStyleImage)
498 return StyleDifferenceLayout;
500 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
501 return StyleDifferenceLayout;
503 if (textStrokeWidth() != other->textStrokeWidth())
504 return StyleDifferenceLayout;
507 #if ENABLE(TEXT_AUTOSIZING)
508 if (visual->m_textAutosizingMultiplier != other->visual->m_textAutosizingMultiplier)
509 return StyleDifferenceLayout;
512 if (inherited->line_height != other->inherited->line_height
513 || inherited->font != other->inherited->font
514 || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing
515 || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing
516 || inherited_flags._box_direction != other->inherited_flags._box_direction
517 || inherited_flags.m_rtlOrdering != other->inherited_flags.m_rtlOrdering
518 || noninherited_flags._position != other->noninherited_flags._position
519 || noninherited_flags._floating != other->noninherited_flags._floating
520 || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay)
521 return StyleDifferenceLayout;
524 if (((int)noninherited_flags._effectiveDisplay) >= TABLE) {
525 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse
526 || inherited_flags._empty_cells != other->inherited_flags._empty_cells
527 || inherited_flags._caption_side != other->inherited_flags._caption_side
528 || noninherited_flags._table_layout != other->noninherited_flags._table_layout)
529 return StyleDifferenceLayout;
531 // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
532 // does not, so these style differences can be width differences.
533 if (inherited_flags._border_collapse
534 && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE)
535 || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN)
536 || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE)
537 || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN)
538 || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE)
539 || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN)
540 || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE)
541 || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
542 return StyleDifferenceLayout;
545 if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
546 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type
547 || inherited_flags._list_style_position != other->inherited_flags._list_style_position)
548 return StyleDifferenceLayout;
551 if (inherited_flags._text_align != other->inherited_flags._text_align
552 || inherited_flags._text_transform != other->inherited_flags._text_transform
553 || inherited_flags._direction != other->inherited_flags._direction
554 || inherited_flags._white_space != other->inherited_flags._white_space
555 || noninherited_flags._clear != other->noninherited_flags._clear
556 || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi)
557 return StyleDifferenceLayout;
559 // Check block flow direction.
560 if (inherited_flags.m_writingMode != other->inherited_flags.m_writingMode)
561 return StyleDifferenceLayout;
563 // Check text combine mode.
564 if (rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine)
565 return StyleDifferenceLayout;
567 // Overflow returns a layout hint.
568 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX
569 || noninherited_flags._overflowY != other->noninherited_flags._overflowY)
570 return StyleDifferenceLayout;
572 // If our border widths change, then we need to layout. Other changes to borders
573 // only necessitate a repaint.
574 if (borderLeftWidth() != other->borderLeftWidth()
575 || borderTopWidth() != other->borderTopWidth()
576 || borderBottomWidth() != other->borderBottomWidth()
577 || borderRightWidth() != other->borderRightWidth())
578 return StyleDifferenceLayout;
580 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
581 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
582 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
583 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
584 return StyleDifferenceLayout;
586 if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
587 return StyleDifferenceLayout;
589 if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1)
590 || (rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
591 // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
592 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
593 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
594 // In addition we need to solve the floating object issue when layers come and go. Right now
595 // a full layout is necessary to keep floating object lists sane.
596 return StyleDifferenceLayout;
599 if (!QuotesData::equals(rareInheritedData->quotes.get(), other->rareInheritedData->quotes.get()))
600 return StyleDifferenceLayout;
603 // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
604 // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
605 // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches
606 // that are relevant for SVG and might return StyleDifferenceLayout.
607 if (svgChange != StyleDifferenceEqual)
611 // Make sure these left/top/right/bottom checks stay below all layout checks and above
612 // all visible checks.
613 if (position() != StaticPosition) {
614 if (surround->offset != other->surround->offset) {
615 // Optimize for the case where a positioned layer is moving but not changing size.
616 if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
617 return StyleDifferenceLayoutPositionedMovementOnly;
619 // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
620 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
621 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
622 return StyleDifferenceLayout;
623 } else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex()
624 || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
625 return StyleDifferenceRepaintLayer;
628 #if ENABLE(CSS_COMPOSITING)
629 if (rareNonInheritedData->m_effectiveBlendMode != other->rareNonInheritedData->m_effectiveBlendMode)
630 return StyleDifferenceRepaintLayer;
633 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
634 #if USE(ACCELERATED_COMPOSITING)
635 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
636 // Don't return; keep looking for another change.
638 return StyleDifferenceRepaintLayer;
642 #if ENABLE(CSS_FILTERS)
643 if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get()
644 && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) {
645 #if USE(ACCELERATED_COMPOSITING)
646 changedContextSensitiveProperties |= ContextSensitivePropertyFilter;
647 // Don't return; keep looking for another change.
649 return StyleDifferenceRepaintLayer;
654 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask
655 || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
656 return StyleDifferenceRepaintLayer;
658 if (inherited->color != other->inherited->color
659 || inherited_flags._visibility != other->inherited_flags._visibility
660 || inherited_flags._text_decorations != other->inherited_flags._text_decorations
661 || inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust
662 || inherited_flags._insideLink != other->inherited_flags._insideLink
663 || surround->border != other->surround->border
664 || *m_background.get() != *other->m_background.get()
665 || visual->textDecoration != other->visual->textDecoration
666 || rareInheritedData->userModify != other->rareInheritedData->userModify
667 || rareInheritedData->userSelect != other->rareInheritedData->userSelect
668 || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag
669 || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit
670 #if ENABLE(CSS3_TEXT)
671 || rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle
673 || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor
674 || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor
675 || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor
676 || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill
677 || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering)
678 return StyleDifferenceRepaint;
680 // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected
681 // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout
682 // the parent container. For sure, I will have to revisit this code, but for now I've added this in order
683 // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ.
684 // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991
685 if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside)
686 return StyleDifferenceRepaint;
688 if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath)
689 return StyleDifferenceRepaint;
692 #if USE(ACCELERATED_COMPOSITING)
693 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
694 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
695 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility
696 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
697 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
698 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
699 return StyleDifferenceRecompositeLayer;
703 // Cursors are not checked, since they will be set appropriately in response to mouse events,
704 // so they don't need to cause any repaint or layout.
706 // 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
707 // the resulting transition properly.
708 return StyleDifferenceEqual;
711 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
713 StyleVisualData* data = visual.access();
714 data->clip.m_top = top;
715 data->clip.m_right = right;
716 data->clip.m_bottom = bottom;
717 data->clip.m_left = left;
720 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot)
722 if (!rareInheritedData.access()->cursorData)
723 rareInheritedData.access()->cursorData = CursorList::create();
724 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot));
727 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
729 rareInheritedData.access()->cursorData = other;
732 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
734 if (QuotesData::equals(rareInheritedData->quotes.get(), q.get()))
736 rareInheritedData.access()->quotes = q;
739 void RenderStyle::clearCursorList()
741 if (rareInheritedData->cursorData)
742 rareInheritedData.access()->cursorData = 0;
745 void RenderStyle::clearContent()
747 if (rareNonInheritedData->m_content)
748 rareNonInheritedData.access()->m_content = nullptr;
751 void RenderStyle::appendContent(PassOwnPtr<ContentData> contentData)
753 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
754 ContentData* lastContent = content.get();
755 while (lastContent && lastContent->next())
756 lastContent = lastContent->next();
759 lastContent->setNext(contentData);
761 content = contentData;
764 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
770 appendContent(ContentData::create(image));
774 rareNonInheritedData.access()->m_content = ContentData::create(image);
777 void RenderStyle::setContent(const String& string, bool add)
779 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
781 ContentData* lastContent = content.get();
782 while (lastContent && lastContent->next())
783 lastContent = lastContent->next();
786 // We attempt to merge with the last ContentData if possible.
787 if (lastContent->isText()) {
788 TextContentData* textContent = static_cast<TextContentData*>(lastContent);
789 textContent->setText(textContent->text() + string);
791 lastContent->setNext(ContentData::create(string));
797 content = ContentData::create(string);
800 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
806 appendContent(ContentData::create(counter));
810 rareNonInheritedData.access()->m_content = ContentData::create(counter);
813 void RenderStyle::setContent(QuoteType quote, bool add)
816 appendContent(ContentData::create(quote));
820 rareNonInheritedData.access()->m_content = ContentData::create(quote);
823 inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
825 // transform-origin brackets the transform with translate operations.
826 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
828 if (applyOrigin != RenderStyle::IncludeTransformOrigin)
831 unsigned size = transformOperations.size();
832 for (unsigned i = 0; i < size; ++i) {
833 TransformOperation::OperationType type = transformOperations[i]->getOperationType();
834 if (type != TransformOperation::TRANSLATE_X
835 && type != TransformOperation::TRANSLATE_Y
836 && type != TransformOperation::TRANSLATE
837 && type != TransformOperation::TRANSLATE_Z
838 && type != TransformOperation::TRANSLATE_3D)
845 void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
847 // FIXME: when subpixel layout is supported (bug 71143) the body of this function could be replaced by
848 // applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin);
850 const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
851 bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
853 if (applyTransformOrigin)
854 transform.translate3d(floatValueForLength(transformOriginX(), borderBoxSize.width()), floatValueForLength(transformOriginY(), borderBoxSize.height()), transformOriginZ());
856 unsigned size = transformOperations.size();
857 for (unsigned i = 0; i < size; ++i)
858 transformOperations[i]->apply(transform, borderBoxSize);
860 if (applyTransformOrigin)
861 transform.translate3d(-floatValueForLength(transformOriginX(), borderBoxSize.width()), -floatValueForLength(transformOriginY(), borderBoxSize.height()), -transformOriginZ());
864 void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const
866 const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
867 bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
869 float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0;
870 float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0;
872 if (applyTransformOrigin) {
873 transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX,
874 floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY,
878 unsigned size = transformOperations.size();
879 for (unsigned i = 0; i < size; ++i)
880 transformOperations[i]->apply(transform, boundingBox.size());
882 if (applyTransformOrigin) {
883 transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX,
884 -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY,
885 -transformOriginZ());
889 void RenderStyle::setPageScaleTransform(float scale)
893 TransformOperations transform;
894 transform.operations().append(ScaleTransformOperation::create(scale, scale, ScaleTransformOperation::SCALE));
895 setTransform(transform);
896 setTransformOriginX(Length(0, Fixed));
897 setTransformOriginY(Length(0, Fixed));
900 void RenderStyle::setTextShadow(PassOwnPtr<ShadowData> shadowData, bool add)
902 ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal));
904 StyleRareInheritedData* rareData = rareInheritedData.access();
906 rareData->textShadow = shadowData;
910 shadowData->setNext(rareData->textShadow.release());
911 rareData->textShadow = shadowData;
914 void RenderStyle::setBoxShadow(PassOwnPtr<ShadowData> shadowData, bool add)
916 StyleRareNonInheritedData* rareData = rareNonInheritedData.access();
918 rareData->m_boxShadow = shadowData;
922 shadowData->setNext(rareData->m_boxShadow.release());
923 rareData->m_boxShadow = shadowData;
926 static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size, RenderView* renderView)
928 return RoundedRect::Radii(
929 IntSize(valueForLength(border.topLeft().width(), size.width(), renderView),
930 valueForLength(border.topLeft().height(), size.height(), renderView)),
931 IntSize(valueForLength(border.topRight().width(), size.width(), renderView),
932 valueForLength(border.topRight().height(), size.height(), renderView)),
933 IntSize(valueForLength(border.bottomLeft().width(), size.width(), renderView),
934 valueForLength(border.bottomLeft().height(), size.height(), renderView)),
935 IntSize(valueForLength(border.bottomRight().width(), size.width(), renderView),
936 valueForLength(border.bottomRight().height(), size.height(), renderView)));
939 static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radii& radii)
941 // Constrain corner radii using CSS3 rules:
942 // http://www.w3.org/TR/css3-background/#the-border-radius
948 radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow.
949 if (radiiSum > static_cast<unsigned>(rect.width()))
950 factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
953 radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width());
954 if (radiiSum > static_cast<unsigned>(rect.width()))
955 factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
958 radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height());
959 if (radiiSum > static_cast<unsigned>(rect.height()))
960 factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
963 radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height());
964 if (radiiSum > static_cast<unsigned>(rect.height()))
965 factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
971 StyleImage* RenderStyle::listStyleImage() const { return rareInheritedData->listStyleImage.get(); }
972 void RenderStyle::setListStyleImage(PassRefPtr<StyleImage> v)
974 if (rareInheritedData->listStyleImage != v)
975 rareInheritedData.access()->listStyleImage = v;
978 Color RenderStyle::color() const { return inherited->color; }
979 Color RenderStyle::visitedLinkColor() const { return inherited->visitedLinkColor; }
980 void RenderStyle::setColor(const Color& v) { SET_VAR(inherited, color, v); }
981 void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(inherited, visitedLinkColor, v); }
983 short RenderStyle::horizontalBorderSpacing() const { return inherited->horizontal_border_spacing; }
984 short RenderStyle::verticalBorderSpacing() const { return inherited->vertical_border_spacing; }
985 void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v); }
986 void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v); }
988 RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, RenderView* renderView, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
990 IntRect snappedBorderRect(pixelSnappedIntRect(borderRect));
991 RoundedRect roundedRect(snappedBorderRect);
992 if (hasBorderRadius()) {
993 RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size(), renderView);
994 radii.scale(calcConstraintScaleFor(snappedBorderRect, radii));
995 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
1000 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
1002 bool horizontal = isHorizontalWritingMode();
1004 int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
1005 int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
1006 int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
1007 int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
1009 return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
1012 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
1013 int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
1015 LayoutRect innerRect(borderRect.x() + leftWidth,
1016 borderRect.y() + topWidth,
1017 borderRect.width() - leftWidth - rightWidth,
1018 borderRect.height() - topWidth - bottomWidth);
1020 RoundedRect roundedRect(pixelSnappedIntRect(innerRect));
1022 if (hasBorderRadius()) {
1023 RoundedRect::Radii radii = getRoundedBorderFor(borderRect).radii();
1024 radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
1025 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
1030 static bool allLayersAreFixed(const FillLayer* layer)
1032 bool allFixed = true;
1034 for (const FillLayer* currLayer = layer; currLayer; currLayer = currLayer->next())
1035 allFixed &= (currLayer->image() && currLayer->attachment() == FixedBackgroundAttachment);
1037 return layer && allFixed;
1040 bool RenderStyle::hasEntirelyFixedBackground() const
1042 return allLayersAreFixed(backgroundLayers());
1045 const CounterDirectiveMap* RenderStyle::counterDirectives() const
1047 return rareNonInheritedData->m_counterDirectives.get();
1050 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
1052 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
1054 map = adoptPtr(new CounterDirectiveMap);
1058 const CounterDirectives RenderStyle::getCounterDirectives(const AtomicString& identifier) const
1060 if (const CounterDirectiveMap* directives = counterDirectives())
1061 return directives->get(identifier);
1062 return CounterDirectives();
1065 const AtomicString& RenderStyle::hyphenString() const
1067 ASSERT(hyphens() != HyphensNone);
1069 const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString;
1070 if (!hyphenationString.isNull())
1071 return hyphenationString;
1073 // FIXME: This should depend on locale.
1074 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1));
1075 DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1));
1076 return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString;
1079 const AtomicString& RenderStyle::textEmphasisMarkString() const
1081 switch (textEmphasisMark()) {
1082 case TextEmphasisMarkNone:
1084 case TextEmphasisMarkCustom:
1085 return textEmphasisCustomMark();
1086 case TextEmphasisMarkDot: {
1087 DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1));
1088 DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1));
1089 return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString;
1091 case TextEmphasisMarkCircle: {
1092 DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1));
1093 DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1));
1094 return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString;
1096 case TextEmphasisMarkDoubleCircle: {
1097 DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1));
1098 DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1));
1099 return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString;
1101 case TextEmphasisMarkTriangle: {
1102 DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1));
1103 DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1));
1104 return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString;
1106 case TextEmphasisMarkSesame: {
1107 DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1));
1108 DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1));
1109 return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString;
1111 case TextEmphasisMarkAuto:
1112 ASSERT_NOT_REACHED();
1116 ASSERT_NOT_REACHED();
1120 #if ENABLE(DASHBOARD_SUPPORT)
1121 const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
1123 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, emptyList, ());
1127 const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
1129 DEFINE_STATIC_LOCAL(Vector<StyleDashboardRegion>, noneList, ());
1130 static bool noneListInitialized = false;
1132 if (!noneListInitialized) {
1133 StyleDashboardRegion region;
1135 region.offset.m_top = Length();
1136 region.offset.m_right = Length();
1137 region.offset.m_bottom = Length();
1138 region.offset.m_left = Length();
1139 region.type = StyleDashboardRegion::None;
1140 noneList.append(region);
1141 noneListInitialized = true;
1147 void RenderStyle::adjustAnimations()
1149 AnimationList* animationList = rareNonInheritedData->m_animations.get();
1153 // Get rid of empty animations and anything beyond them
1154 for (size_t i = 0; i < animationList->size(); ++i) {
1155 if (animationList->animation(i)->isEmpty()) {
1156 animationList->resize(i);
1161 if (animationList->isEmpty()) {
1166 // Repeat patterns into layers that don't have some properties set.
1167 animationList->fillUnsetProperties();
1170 void RenderStyle::adjustTransitions()
1172 AnimationList* transitionList = rareNonInheritedData->m_transitions.get();
1173 if (!transitionList)
1176 // Get rid of empty transitions and anything beyond them
1177 for (size_t i = 0; i < transitionList->size(); ++i) {
1178 if (transitionList->animation(i)->isEmpty()) {
1179 transitionList->resize(i);
1184 if (transitionList->isEmpty()) {
1189 // Repeat patterns into layers that don't have some properties set.
1190 transitionList->fillUnsetProperties();
1192 // Make sure there are no duplicate properties. This is an O(n^2) algorithm
1193 // but the lists tend to be very short, so it is probably ok
1194 for (size_t i = 0; i < transitionList->size(); ++i) {
1195 for (size_t j = i+1; j < transitionList->size(); ++j) {
1196 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
1198 transitionList->remove(i);
1205 AnimationList* RenderStyle::accessAnimations()
1207 if (!rareNonInheritedData.access()->m_animations)
1208 rareNonInheritedData.access()->m_animations = adoptPtr(new AnimationList());
1209 return rareNonInheritedData->m_animations.get();
1212 AnimationList* RenderStyle::accessTransitions()
1214 if (!rareNonInheritedData.access()->m_transitions)
1215 rareNonInheritedData.access()->m_transitions = adoptPtr(new AnimationList());
1216 return rareNonInheritedData->m_transitions.get();
1219 const Animation* RenderStyle::transitionForProperty(CSSPropertyID property) const
1221 if (transitions()) {
1222 for (size_t i = 0; i < transitions()->size(); ++i) {
1223 const Animation* p = transitions()->animation(i);
1224 if (p->animationMode() == Animation::AnimateAll || p->property() == property) {
1232 const Font& RenderStyle::font() const { return inherited->font; }
1233 const FontMetrics& RenderStyle::fontMetrics() const { return inherited->font.fontMetrics(); }
1234 const FontDescription& RenderStyle::fontDescription() const { return inherited->font.fontDescription(); }
1235 float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); }
1236 float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); }
1237 int RenderStyle::fontSize() const { return inherited->font.pixelSize(); }
1239 int RenderStyle::wordSpacing() const { return inherited->font.wordSpacing(); }
1240 int RenderStyle::letterSpacing() const { return inherited->font.letterSpacing(); }
1242 bool RenderStyle::setFontDescription(const FontDescription& v)
1244 if (inherited->font.fontDescription() != v) {
1245 inherited.access()->font = Font(v, inherited->font.letterSpacing(), inherited->font.wordSpacing());
1251 Length RenderStyle::specifiedLineHeight() const { return inherited->line_height; }
1252 Length RenderStyle::lineHeight() const
1254 const Length& lh = inherited->line_height;
1255 #if ENABLE(TEXT_AUTOSIZING)
1256 // Unlike fontDescription().computedSize() and hence fontSize(), this is
1257 // recalculated on demand as we only store the specified line height.
1258 // FIXME: Should consider scaling the fixed part of any calc expressions
1259 // too, though this involves messily poking into CalcExpressionLength.
1260 float multiplier = textAutosizingMultiplier();
1261 if (multiplier > 1 && lh.isFixed())
1262 return Length(TextAutosizer::computeAutosizedFontSize(lh.value(), multiplier), Fixed);
1266 void RenderStyle::setLineHeight(Length specifiedLineHeight) { SET_VAR(inherited, line_height, specifiedLineHeight); }
1268 int RenderStyle::computedLineHeight(RenderView* renderView) const
1270 const Length& lh = lineHeight();
1272 // Negative value means the line height is not set. Use the font's built-in spacing.
1273 if (lh.isNegative())
1274 return fontMetrics().lineSpacing();
1277 return minimumValueForLength(lh, fontSize());
1279 if (lh.isViewportPercentage())
1280 return valueForLength(lh, 0, renderView);
1285 void RenderStyle::setWordSpacing(int v) { inherited.access()->font.setWordSpacing(v); }
1286 void RenderStyle::setLetterSpacing(int v) { inherited.access()->font.setLetterSpacing(v); }
1288 void RenderStyle::setFontSize(float size)
1290 // size must be specifiedSize if Text Autosizing is enabled, but computedSize if text
1291 // zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
1293 ASSERT(isfinite(size));
1294 if (!isfinite(size) || size < 0)
1297 size = min(maximumAllowedFontSize, size);
1299 FontSelector* currentFontSelector = font().fontSelector();
1300 FontDescription desc(fontDescription());
1301 desc.setSpecifiedSize(size);
1302 desc.setComputedSize(size);
1304 #if ENABLE(TEXT_AUTOSIZING)
1305 float multiplier = textAutosizingMultiplier();
1306 if (multiplier > 1) {
1307 float autosizedFontSize = TextAutosizer::computeAutosizedFontSize(size, multiplier);
1308 desc.setComputedSize(min(maximumAllowedFontSize, autosizedFontSize));
1312 setFontDescription(desc);
1313 font().update(currentFontSelector);
1316 void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const
1323 for ( ; shadow; shadow = shadow->next()) {
1324 if (shadow->style() == Inset)
1326 int blurAndSpread = shadow->blur() + shadow->spread();
1328 top = min<LayoutUnit>(top, shadow->y() - blurAndSpread);
1329 right = max<LayoutUnit>(right, shadow->x() + blurAndSpread);
1330 bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread);
1331 left = min<LayoutUnit>(left, shadow->x() - blurAndSpread);
1335 LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowData* shadow) const
1338 LayoutUnit right = 0;
1339 LayoutUnit bottom = 0;
1340 LayoutUnit left = 0;
1342 for ( ; shadow; shadow = shadow->next()) {
1343 if (shadow->style() == Normal)
1345 int blurAndSpread = shadow->blur() + shadow->spread();
1346 top = max<LayoutUnit>(top, shadow->y() + blurAndSpread);
1347 right = min<LayoutUnit>(right, shadow->x() - blurAndSpread);
1348 bottom = min<LayoutUnit>(bottom, shadow->y() - blurAndSpread);
1349 left = max<LayoutUnit>(left, shadow->x() + blurAndSpread);
1352 return LayoutBoxExtent(top, right, bottom, left);
1355 void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit &left, LayoutUnit &right) const
1360 for ( ; shadow; shadow = shadow->next()) {
1361 if (shadow->style() == Inset)
1363 int blurAndSpread = shadow->blur() + shadow->spread();
1365 left = min<LayoutUnit>(left, shadow->x() - blurAndSpread);
1366 right = max<LayoutUnit>(right, shadow->x() + blurAndSpread);
1370 void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &bottom) const
1375 for ( ; shadow; shadow = shadow->next()) {
1376 if (shadow->style() == Inset)
1378 int blurAndSpread = shadow->blur() + shadow->spread();
1380 top = min<LayoutUnit>(top, shadow->y() - blurAndSpread);
1381 bottom = max<LayoutUnit>(bottom, shadow->y() + blurAndSpread);
1385 Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const
1388 EBorderStyle borderStyle = BNONE;
1389 switch (colorProperty) {
1390 case CSSPropertyBackgroundColor:
1391 return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back.
1392 case CSSPropertyBorderLeftColor:
1393 result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor();
1394 borderStyle = borderLeftStyle();
1396 case CSSPropertyBorderRightColor:
1397 result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor();
1398 borderStyle = borderRightStyle();
1400 case CSSPropertyBorderTopColor:
1401 result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor();
1402 borderStyle = borderTopStyle();
1404 case CSSPropertyBorderBottomColor:
1405 result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor();
1406 borderStyle = borderBottomStyle();
1408 case CSSPropertyColor:
1409 result = visitedLink ? visitedLinkColor() : color();
1411 case CSSPropertyOutlineColor:
1412 result = visitedLink ? visitedLinkOutlineColor() : outlineColor();
1414 case CSSPropertyWebkitColumnRuleColor:
1415 result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor();
1417 case CSSPropertyWebkitTextEmphasisColor:
1418 result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor();
1420 case CSSPropertyWebkitTextFillColor:
1421 result = visitedLink ? visitedLinkTextFillColor() : textFillColor();
1423 case CSSPropertyWebkitTextStrokeColor:
1424 result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor();
1427 ASSERT_NOT_REACHED();
1431 if (!result.isValid()) {
1432 if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1433 result.setRGB(238, 238, 238);
1435 result = visitedLink ? visitedLinkColor() : color();
1440 Color RenderStyle::visitedDependentColor(int colorProperty) const
1442 Color unvisitedColor = colorIncludingFallback(colorProperty, false);
1443 if (insideLink() != InsideVisitedLink)
1444 return unvisitedColor;
1446 Color visitedColor = colorIncludingFallback(colorProperty, true);
1448 // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
1449 // assume that if the background color is transparent that it wasn't set. Note that it's weird that
1450 // we're returning unvisited info for a visited link, but given our restriction that the alpha values
1451 // have to match, it makes more sense to return the unvisited background color if specified than it
1452 // does to return black. This behavior matches what Firefox 4 does as well.
1453 if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent)
1454 return unvisitedColor;
1456 // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1457 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1460 const BorderValue& RenderStyle::borderBefore() const
1462 switch (writingMode()) {
1463 case TopToBottomWritingMode:
1465 case BottomToTopWritingMode:
1466 return borderBottom();
1467 case LeftToRightWritingMode:
1468 return borderLeft();
1469 case RightToLeftWritingMode:
1470 return borderRight();
1472 ASSERT_NOT_REACHED();
1476 const BorderValue& RenderStyle::borderAfter() const
1478 switch (writingMode()) {
1479 case TopToBottomWritingMode:
1480 return borderBottom();
1481 case BottomToTopWritingMode:
1483 case LeftToRightWritingMode:
1484 return borderRight();
1485 case RightToLeftWritingMode:
1486 return borderLeft();
1488 ASSERT_NOT_REACHED();
1489 return borderBottom();
1492 const BorderValue& RenderStyle::borderStart() const
1494 if (isHorizontalWritingMode())
1495 return isLeftToRightDirection() ? borderLeft() : borderRight();
1496 return isLeftToRightDirection() ? borderTop() : borderBottom();
1499 const BorderValue& RenderStyle::borderEnd() const
1501 if (isHorizontalWritingMode())
1502 return isLeftToRightDirection() ? borderRight() : borderLeft();
1503 return isLeftToRightDirection() ? borderBottom() : borderTop();
1506 unsigned short RenderStyle::borderBeforeWidth() const
1508 switch (writingMode()) {
1509 case TopToBottomWritingMode:
1510 return borderTopWidth();
1511 case BottomToTopWritingMode:
1512 return borderBottomWidth();
1513 case LeftToRightWritingMode:
1514 return borderLeftWidth();
1515 case RightToLeftWritingMode:
1516 return borderRightWidth();
1518 ASSERT_NOT_REACHED();
1519 return borderTopWidth();
1522 unsigned short RenderStyle::borderAfterWidth() const
1524 switch (writingMode()) {
1525 case TopToBottomWritingMode:
1526 return borderBottomWidth();
1527 case BottomToTopWritingMode:
1528 return borderTopWidth();
1529 case LeftToRightWritingMode:
1530 return borderRightWidth();
1531 case RightToLeftWritingMode:
1532 return borderLeftWidth();
1534 ASSERT_NOT_REACHED();
1535 return borderBottomWidth();
1538 unsigned short RenderStyle::borderStartWidth() const
1540 if (isHorizontalWritingMode())
1541 return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
1542 return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
1545 unsigned short RenderStyle::borderEndWidth() const
1547 if (isHorizontalWritingMode())
1548 return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
1549 return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
1552 void RenderStyle::setMarginStart(Length margin)
1554 if (isHorizontalWritingMode()) {
1555 if (isLeftToRightDirection())
1556 setMarginLeft(margin);
1558 setMarginRight(margin);
1560 if (isLeftToRightDirection())
1561 setMarginTop(margin);
1563 setMarginBottom(margin);
1567 void RenderStyle::setMarginEnd(Length margin)
1569 if (isHorizontalWritingMode()) {
1570 if (isLeftToRightDirection())
1571 setMarginRight(margin);
1573 setMarginLeft(margin);
1575 if (isLeftToRightDirection())
1576 setMarginBottom(margin);
1578 setMarginTop(margin);
1582 TextEmphasisMark RenderStyle::textEmphasisMark() const
1584 TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark);
1585 if (mark != TextEmphasisMarkAuto)
1588 if (isHorizontalWritingMode())
1589 return TextEmphasisMarkDot;
1591 return TextEmphasisMarkSesame;
1594 #if ENABLE(TOUCH_EVENTS)
1595 Color RenderStyle::initialTapHighlightColor()
1597 return RenderTheme::tapHighlightColor();
1601 LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const
1603 return LayoutBoxExtent(NinePieceImage::computeOutset(image.outset().top(), borderTopWidth()),
1604 NinePieceImage::computeOutset(image.outset().right(), borderRightWidth()),
1605 NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth()),
1606 NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth()));
1609 void RenderStyle::setBorderImageSource(PassRefPtr<StyleImage> image)
1611 if (surround->border.m_image.image() == image.get())
1613 surround.access()->border.m_image.setImage(image);
1616 void RenderStyle::setBorderImageSlices(LengthBox slices)
1618 if (surround->border.m_image.imageSlices() == slices)
1620 surround.access()->border.m_image.setImageSlices(slices);
1623 void RenderStyle::setBorderImageWidth(LengthBox slices)
1625 if (surround->border.m_image.borderSlices() == slices)
1627 surround.access()->border.m_image.setBorderSlices(slices);
1630 void RenderStyle::setBorderImageOutset(LengthBox outset)
1632 if (surround->border.m_image.outset() == outset)
1634 surround.access()->border.m_image.setOutset(outset);
1637 void RenderStyle::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
1639 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
1640 info.addMember(m_box, "box");
1641 info.addMember(visual, "visual");
1642 // FIXME: m_background contains RefPtr<StyleImage> that might need to be instrumented.
1643 info.addMember(m_background, "background");
1644 // FIXME: surrond contains some fields e.g. BorderData that might need to be instrumented.
1645 info.addMember(surround, "surround");
1646 info.addMember(rareNonInheritedData, "rareNonInheritedData");
1647 info.addMember(rareInheritedData, "rareInheritedData");
1648 // FIXME: inherited contains StyleImage and Font fields that might need to be instrumented.
1649 info.addMember(inherited, "inherited");
1650 info.addMember(m_cachedPseudoStyles, "cachedPseudoStyles");
1652 info.addMember(m_svgStyle, "svgStyle");
1654 info.addMember(inherited_flags, "inherited_flags");
1655 info.addMember(noninherited_flags, "noninherited_flags");
1658 } // namespace WebCore