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 "core/rendering/style/RenderStyle.h"
27 #include "RuntimeEnabledFeatures.h"
28 #include "core/css/resolver/StyleResolver.h"
29 #include "core/rendering/RenderTheme.h"
30 #include "core/rendering/TextAutosizer.h"
31 #include "core/rendering/style/ContentData.h"
32 #include "core/rendering/style/CursorList.h"
33 #include "core/rendering/style/QuotesData.h"
34 #include "core/rendering/style/ShadowList.h"
35 #include "core/rendering/style/StyleImage.h"
36 #include "core/rendering/style/StyleInheritedData.h"
37 #include "platform/LengthFunctions.h"
38 #include "platform/fonts/Font.h"
39 #include "platform/fonts/FontSelector.h"
40 #include "wtf/MathExtras.h"
46 struct SameSizeAsBorderValue {
51 COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow);
53 struct SameSizeAsRenderStyle : public RefCounted<SameSizeAsRenderStyle> {
56 void* dataRefSvgStyle;
58 struct InheritedFlags {
59 unsigned m_bitfields[2];
62 struct NonInheritedFlags {
63 unsigned m_bitfields[2];
67 COMPILE_ASSERT(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), RenderStyle_should_stay_small);
69 inline RenderStyle* defaultStyle()
71 DEFINE_STATIC_REF(RenderStyle, s_defaultStyle, (RenderStyle::createDefaultStyle()));
72 return s_defaultStyle;
75 PassRefPtr<RenderStyle> RenderStyle::create()
77 return adoptRef(new RenderStyle());
80 PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
82 return adoptRef(new RenderStyle(DefaultStyle));
85 PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle* parentStyle, EDisplay display)
87 RefPtr<RenderStyle> newStyle = RenderStyle::create();
88 newStyle->inheritFrom(parentStyle);
89 newStyle->inheritUnicodeBidiFrom(parentStyle);
90 newStyle->setDisplay(display);
94 PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
96 return adoptRef(new RenderStyle(*other));
99 ALWAYS_INLINE RenderStyle::RenderStyle()
100 : m_box(defaultStyle()->m_box)
101 , visual(defaultStyle()->visual)
102 , m_background(defaultStyle()->m_background)
103 , surround(defaultStyle()->surround)
104 , rareNonInheritedData(defaultStyle()->rareNonInheritedData)
105 , rareInheritedData(defaultStyle()->rareInheritedData)
106 , inherited(defaultStyle()->inherited)
107 , m_svgStyle(defaultStyle()->m_svgStyle)
109 setBitDefaults(); // Would it be faster to copy this from the default style?
110 COMPILE_ASSERT((sizeof(InheritedFlags) <= 8), InheritedFlags_does_not_grow);
111 COMPILE_ASSERT((sizeof(NonInheritedFlags) <= 8), NonInheritedFlags_does_not_grow);
114 ALWAYS_INLINE RenderStyle::RenderStyle(DefaultStyleTag)
122 rareNonInheritedData.init();
123 rareNonInheritedData.access()->m_deprecatedFlexibleBox.init();
124 rareNonInheritedData.access()->m_flexibleBox.init();
125 rareNonInheritedData.access()->m_marquee.init();
126 rareNonInheritedData.access()->m_multiCol.init();
127 rareNonInheritedData.access()->m_transform.init();
128 rareNonInheritedData.access()->m_filter.init();
129 rareNonInheritedData.access()->m_grid.init();
130 rareNonInheritedData.access()->m_gridItem.init();
131 rareInheritedData.init();
136 ALWAYS_INLINE RenderStyle::RenderStyle(const RenderStyle& o)
137 : RefCounted<RenderStyle>()
140 , m_background(o.m_background)
141 , surround(o.surround)
142 , rareNonInheritedData(o.rareNonInheritedData)
143 , rareInheritedData(o.rareInheritedData)
144 , inherited(o.inherited)
145 , m_svgStyle(o.m_svgStyle)
146 , inherited_flags(o.inherited_flags)
147 , noninherited_flags(o.noninherited_flags)
151 static StyleRecalcChange comparePseudoStyles(const RenderStyle* oldStyle, const RenderStyle* newStyle)
153 // If the pseudoStyles have changed, we want any StyleRecalcChange that is not NoChange
154 // because setStyle will do the right thing with anything else.
155 if (!oldStyle->hasAnyPublicPseudoStyles())
157 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < FIRST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
158 if (!oldStyle->hasPseudoStyle(pseudoId))
160 RenderStyle* newPseudoStyle = newStyle->getCachedPseudoStyle(pseudoId);
163 RenderStyle* oldPseudoStyle = oldStyle->getCachedPseudoStyle(pseudoId);
164 if (oldPseudoStyle && *oldPseudoStyle != *newPseudoStyle)
170 StyleRecalcChange RenderStyle::compare(const RenderStyle* oldStyle, const RenderStyle* newStyle)
172 if ((!oldStyle && newStyle) || (oldStyle && !newStyle))
175 if (!oldStyle && !newStyle)
178 if (oldStyle->display() != newStyle->display()
179 || oldStyle->hasPseudoStyle(FIRST_LETTER) != newStyle->hasPseudoStyle(FIRST_LETTER)
180 || oldStyle->columnSpan() != newStyle->columnSpan()
181 || oldStyle->specifiesAutoColumns() != newStyle->specifiesAutoColumns()
182 || !oldStyle->contentDataEquivalent(newStyle)
183 || oldStyle->hasTextCombine() != newStyle->hasTextCombine())
186 if (*oldStyle == *newStyle)
187 return comparePseudoStyles(oldStyle, newStyle);
189 if (oldStyle->inheritedNotEqual(newStyle)
190 || oldStyle->hasExplicitlyInheritedProperties()
191 || newStyle->hasExplicitlyInheritedProperties())
197 void RenderStyle::inheritFrom(const RenderStyle* inheritParent, IsAtShadowBoundary isAtShadowBoundary)
199 if (isAtShadowBoundary == AtShadowBoundary) {
200 // Even if surrounding content is user-editable, shadow DOM should act as a single unit, and not necessarily be editable
201 EUserModify currentUserModify = userModify();
202 rareInheritedData = inheritParent->rareInheritedData;
203 setUserModify(currentUserModify);
205 rareInheritedData = inheritParent->rareInheritedData;
206 inherited = inheritParent->inherited;
207 inherited_flags = inheritParent->inherited_flags;
208 if (m_svgStyle != inheritParent->m_svgStyle)
209 m_svgStyle.access()->inheritFrom(inheritParent->m_svgStyle.get());
212 void RenderStyle::copyNonInheritedFrom(const RenderStyle* other)
214 m_box = other->m_box;
215 visual = other->visual;
216 m_background = other->m_background;
217 surround = other->surround;
218 rareNonInheritedData = other->rareNonInheritedData;
219 // The flags are copied one-by-one because noninherited_flags contains a bunch of stuff other than real style data.
220 noninherited_flags._effectiveDisplay = other->noninherited_flags._effectiveDisplay;
221 noninherited_flags._originalDisplay = other->noninherited_flags._originalDisplay;
222 noninherited_flags._overflowX = other->noninherited_flags._overflowX;
223 noninherited_flags._overflowY = other->noninherited_flags._overflowY;
224 noninherited_flags._vertical_align = other->noninherited_flags._vertical_align;
225 noninherited_flags._clear = other->noninherited_flags._clear;
226 noninherited_flags._position = other->noninherited_flags._position;
227 noninherited_flags._floating = other->noninherited_flags._floating;
228 noninherited_flags._table_layout = other->noninherited_flags._table_layout;
229 noninherited_flags._unicodeBidi = other->noninherited_flags._unicodeBidi;
230 noninherited_flags._page_break_before = other->noninherited_flags._page_break_before;
231 noninherited_flags._page_break_after = other->noninherited_flags._page_break_after;
232 noninherited_flags._page_break_inside = other->noninherited_flags._page_break_inside;
233 noninherited_flags.explicitInheritance = other->noninherited_flags.explicitInheritance;
234 noninherited_flags.currentColor = other->noninherited_flags.currentColor;
235 noninherited_flags.hasViewportUnits = other->noninherited_flags.hasViewportUnits;
236 if (m_svgStyle != other->m_svgStyle)
237 m_svgStyle.access()->copyNonInheritedFrom(other->m_svgStyle.get());
238 ASSERT(zoom() == initialZoom());
241 bool RenderStyle::operator==(const RenderStyle& o) const
243 // compare everything except the pseudoStyle pointer
244 return inherited_flags == o.inherited_flags
245 && noninherited_flags == o.noninherited_flags
247 && visual == o.visual
248 && m_background == o.m_background
249 && surround == o.surround
250 && rareNonInheritedData == o.rareNonInheritedData
251 && rareInheritedData == o.rareInheritedData
252 && inherited == o.inherited
253 && m_svgStyle == o.m_svgStyle;
256 bool RenderStyle::isStyleAvailable() const
258 return this != StyleResolver::styleNotYetAvailable();
261 bool RenderStyle::hasUniquePseudoStyle() const
263 if (!m_cachedPseudoStyles || styleType() != NOPSEUDO)
266 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
267 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
268 if (pseudoStyle->unique())
275 RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
277 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
280 if (styleType() != NOPSEUDO)
283 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
284 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
285 if (pseudoStyle->styleType() == pid)
292 RenderStyle* RenderStyle::addCachedPseudoStyle(PassRefPtr<RenderStyle> pseudo)
297 ASSERT(pseudo->styleType() > NOPSEUDO);
299 RenderStyle* result = pseudo.get();
301 if (!m_cachedPseudoStyles)
302 m_cachedPseudoStyles = adoptPtr(new PseudoStyleCache);
304 m_cachedPseudoStyles->append(pseudo);
309 void RenderStyle::removeCachedPseudoStyle(PseudoId pid)
311 if (!m_cachedPseudoStyles)
313 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
314 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
315 if (pseudoStyle->styleType() == pid) {
316 m_cachedPseudoStyles->remove(i);
322 bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
324 return inherited_flags != other->inherited_flags
325 || inherited != other->inherited
326 || m_svgStyle->inheritedNotEqual(other->m_svgStyle.get())
327 || rareInheritedData != other->rareInheritedData;
330 bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
332 // This is a fast check that only looks if the data structures are shared.
333 return inherited_flags == other->inherited_flags
334 && inherited.get() == other->inherited.get()
335 && m_svgStyle.get() == other->m_svgStyle.get()
336 && rareInheritedData.get() == other->rareInheritedData.get();
339 static bool positionedObjectMovedOnly(const LengthBox& a, const LengthBox& b, const Length& width)
341 // If any unit types are different, then we can't guarantee
342 // that this was just a movement.
343 if (a.left().type() != b.left().type()
344 || a.right().type() != b.right().type()
345 || a.top().type() != b.top().type()
346 || a.bottom().type() != b.bottom().type())
349 // Only one unit can be non-auto in the horizontal direction and
350 // in the vertical direction. Otherwise the adjustment of values
351 // is changing the size of the box.
352 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
354 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
356 // If our width is auto and left or right is specified and changed then this
357 // is not just a movement - we need to resize to our container.
358 if (width.isIntrinsicOrAuto()
359 && ((!a.left().isIntrinsicOrAuto() && a.left() != b.left())
360 || (!a.right().isIntrinsicOrAuto() && a.right() != b.right())))
363 // One of the units is fixed or percent in both directions and stayed
364 // that way in the new style. Therefore all we are doing is moving.
368 StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
370 changedContextSensitiveProperties = ContextSensitivePropertyNone;
372 // Note, we use .get() on each DataRef below because DataRef::operator== will do a deep
373 // compare, which is duplicate work when we're going to compare each property inside
374 // this function anyway.
376 StyleDifference svgChange = StyleDifferenceEqual;
377 if (m_svgStyle.get() != other->m_svgStyle.get()) {
378 svgChange = m_svgStyle->diff(other->m_svgStyle.get());
379 if (svgChange == StyleDifferenceLayout)
383 if (m_box.get() != other->m_box.get()) {
384 if (m_box->width() != other->m_box->width()
385 || m_box->minWidth() != other->m_box->minWidth()
386 || m_box->maxWidth() != other->m_box->maxWidth()
387 || m_box->height() != other->m_box->height()
388 || m_box->minHeight() != other->m_box->minHeight()
389 || m_box->maxHeight() != other->m_box->maxHeight())
390 return StyleDifferenceLayout;
392 if (m_box->verticalAlign() != other->m_box->verticalAlign())
393 return StyleDifferenceLayout;
395 if (m_box->boxSizing() != other->m_box->boxSizing())
396 return StyleDifferenceLayout;
399 if (surround.get() != other->surround.get()) {
400 if (surround->margin != other->surround->margin)
401 return StyleDifferenceLayout;
403 if (surround->padding != other->surround->padding)
404 return StyleDifferenceLayout;
406 // If our border widths change, then we need to layout. Other changes to borders only necessitate a repaint.
407 if (borderLeftWidth() != other->borderLeftWidth()
408 || borderTopWidth() != other->borderTopWidth()
409 || borderBottomWidth() != other->borderBottomWidth()
410 || borderRightWidth() != other->borderRightWidth())
411 return StyleDifferenceLayout;
414 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
415 if (rareNonInheritedData->m_appearance != other->rareNonInheritedData->m_appearance
416 || rareNonInheritedData->marginBeforeCollapse != other->rareNonInheritedData->marginBeforeCollapse
417 || rareNonInheritedData->marginAfterCollapse != other->rareNonInheritedData->marginAfterCollapse
418 || rareNonInheritedData->lineClamp != other->rareNonInheritedData->lineClamp
419 || rareNonInheritedData->textOverflow != other->rareNonInheritedData->textOverflow
420 || rareNonInheritedData->m_wrapFlow != other->rareNonInheritedData->m_wrapFlow
421 || rareNonInheritedData->m_wrapThrough != other->rareNonInheritedData->m_wrapThrough
422 || rareNonInheritedData->m_shapeMargin != other->rareNonInheritedData->m_shapeMargin
423 || rareNonInheritedData->m_shapePadding != other->rareNonInheritedData->m_shapePadding
424 || rareNonInheritedData->m_order != other->rareNonInheritedData->m_order
425 || rareNonInheritedData->m_alignContent != other->rareNonInheritedData->m_alignContent
426 || rareNonInheritedData->m_alignItems != other->rareNonInheritedData->m_alignItems
427 || rareNonInheritedData->m_alignSelf != other->rareNonInheritedData->m_alignSelf
428 || rareNonInheritedData->m_justifyContent != other->rareNonInheritedData->m_justifyContent
429 || rareNonInheritedData->m_grid.get() != other->rareNonInheritedData->m_grid.get()
430 || rareNonInheritedData->m_gridItem.get() != other->rareNonInheritedData->m_gridItem.get()
431 || rareNonInheritedData->m_shapeInside != other->rareNonInheritedData->m_shapeInside
432 || rareNonInheritedData->m_textCombine != other->rareNonInheritedData->m_textCombine
433 || rareNonInheritedData->hasFilters() != other->rareNonInheritedData->hasFilters())
434 return StyleDifferenceLayout;
436 if (rareNonInheritedData->m_deprecatedFlexibleBox.get() != other->rareNonInheritedData->m_deprecatedFlexibleBox.get()
437 && *rareNonInheritedData->m_deprecatedFlexibleBox.get() != *other->rareNonInheritedData->m_deprecatedFlexibleBox.get())
438 return StyleDifferenceLayout;
440 if (rareNonInheritedData->m_flexibleBox.get() != other->rareNonInheritedData->m_flexibleBox.get()
441 && *rareNonInheritedData->m_flexibleBox.get() != *other->rareNonInheritedData->m_flexibleBox.get())
442 return StyleDifferenceLayout;
444 // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
445 if (!rareNonInheritedData->shadowDataEquivalent(*other->rareNonInheritedData.get()))
446 return StyleDifferenceLayout;
448 if (!rareNonInheritedData->reflectionDataEquivalent(*other->rareNonInheritedData.get()))
449 return StyleDifferenceLayout;
451 if (rareNonInheritedData->m_multiCol.get() != other->rareNonInheritedData->m_multiCol.get()
452 && *rareNonInheritedData->m_multiCol.get() != *other->rareNonInheritedData->m_multiCol.get())
453 return StyleDifferenceLayout;
455 if (!transformDataEquivalent(other)) {
456 // Don't return early here; instead take note of the type of
457 // change, and deal with it when looking at compositing.
458 changedContextSensitiveProperties |= ContextSensitivePropertyTransform;
461 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
462 const CounterDirectiveMap* mapA = rareNonInheritedData->m_counterDirectives.get();
463 const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get();
464 if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB)))
465 return StyleDifferenceLayout;
467 // We only need do layout for opacity changes if adding or losing opacity could trigger a change
468 // in us being a stacking context.
469 if (hasAutoZIndex() != other->hasAutoZIndex() && rareNonInheritedData->hasOpacity() != other->rareNonInheritedData->hasOpacity()) {
470 // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
471 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
472 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
473 // In addition we need to solve the floating object issue when layers come and go. Right now
474 // a full layout is necessary to keep floating object lists sane.
475 return StyleDifferenceLayout;
479 if (rareInheritedData.get() != other->rareInheritedData.get()) {
480 if (rareInheritedData->highlight != other->rareInheritedData->highlight
481 || rareInheritedData->indent != other->rareInheritedData->indent
482 || rareInheritedData->m_textAlignLast != other->rareInheritedData->m_textAlignLast
483 || rareInheritedData->m_textIndentLine != other->rareInheritedData->m_textIndentLine
484 || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom
485 || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak
486 || rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap
487 || rareInheritedData->lineBreak != other->rareInheritedData->lineBreak
488 || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity
489 || rareInheritedData->hyphens != other->rareInheritedData->hyphens
490 || rareInheritedData->hyphenationLimitBefore != other->rareInheritedData->hyphenationLimitBefore
491 || rareInheritedData->hyphenationLimitAfter != other->rareInheritedData->hyphenationLimitAfter
492 || rareInheritedData->hyphenationString != other->rareInheritedData->hyphenationString
493 || rareInheritedData->locale != other->rareInheritedData->locale
494 || rareInheritedData->m_rubyPosition != other->rareInheritedData->m_rubyPosition
495 || rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark
496 || rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition
497 || rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark
498 || rareInheritedData->m_textJustify != other->rareInheritedData->m_textJustify
499 || rareInheritedData->m_textOrientation != other->rareInheritedData->m_textOrientation
500 || rareInheritedData->m_tabSize != other->rareInheritedData->m_tabSize
501 || rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain
502 || rareInheritedData->listStyleImage != other->rareInheritedData->listStyleImage
503 || rareInheritedData->textStrokeWidth != other->rareInheritedData->textStrokeWidth)
504 return StyleDifferenceLayout;
506 if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
507 return StyleDifferenceLayout;
509 if (!QuotesData::equals(rareInheritedData->quotes.get(), other->rareInheritedData->quotes.get()))
510 return StyleDifferenceLayout;
513 if (visual->m_textAutosizingMultiplier != other->visual->m_textAutosizingMultiplier)
514 return StyleDifferenceLayout;
516 if (inherited.get() != other->inherited.get()) {
517 if (inherited->line_height != other->inherited->line_height
518 || inherited->font != other->inherited->font
519 || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing
520 || inherited->vertical_border_spacing != other->inherited->vertical_border_spacing)
521 return StyleDifferenceLayout;
524 if (inherited_flags._box_direction != other->inherited_flags._box_direction
525 || inherited_flags.m_rtlOrdering != other->inherited_flags.m_rtlOrdering
526 || inherited_flags._text_align != other->inherited_flags._text_align
527 || inherited_flags._text_transform != other->inherited_flags._text_transform
528 || inherited_flags._direction != other->inherited_flags._direction
529 || inherited_flags._white_space != other->inherited_flags._white_space
530 || inherited_flags.m_writingMode != other->inherited_flags.m_writingMode)
531 return StyleDifferenceLayout;
533 if (noninherited_flags._overflowX != other->noninherited_flags._overflowX
534 || noninherited_flags._overflowY != other->noninherited_flags._overflowY
535 || noninherited_flags._clear != other->noninherited_flags._clear
536 || noninherited_flags._unicodeBidi != other->noninherited_flags._unicodeBidi
537 || noninherited_flags._position != other->noninherited_flags._position
538 || noninherited_flags._floating != other->noninherited_flags._floating
539 || noninherited_flags._originalDisplay != other->noninherited_flags._originalDisplay
540 || noninherited_flags._vertical_align != other->noninherited_flags._vertical_align)
541 return StyleDifferenceLayout;
543 if (noninherited_flags._effectiveDisplay >= FIRST_TABLE_DISPLAY && noninherited_flags._effectiveDisplay <= LAST_TABLE_DISPLAY) {
544 if (inherited_flags._border_collapse != other->inherited_flags._border_collapse
545 || inherited_flags._empty_cells != other->inherited_flags._empty_cells
546 || inherited_flags._caption_side != other->inherited_flags._caption_side
547 || noninherited_flags._table_layout != other->noninherited_flags._table_layout)
548 return StyleDifferenceLayout;
550 // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
551 // does not, so these style differences can be width differences.
552 if (inherited_flags._border_collapse
553 && ((borderTopStyle() == BHIDDEN && other->borderTopStyle() == BNONE)
554 || (borderTopStyle() == BNONE && other->borderTopStyle() == BHIDDEN)
555 || (borderBottomStyle() == BHIDDEN && other->borderBottomStyle() == BNONE)
556 || (borderBottomStyle() == BNONE && other->borderBottomStyle() == BHIDDEN)
557 || (borderLeftStyle() == BHIDDEN && other->borderLeftStyle() == BNONE)
558 || (borderLeftStyle() == BNONE && other->borderLeftStyle() == BHIDDEN)
559 || (borderRightStyle() == BHIDDEN && other->borderRightStyle() == BNONE)
560 || (borderRightStyle() == BNONE && other->borderRightStyle() == BHIDDEN)))
561 return StyleDifferenceLayout;
562 } else if (noninherited_flags._effectiveDisplay == LIST_ITEM) {
563 if (inherited_flags._list_style_type != other->inherited_flags._list_style_type
564 || inherited_flags._list_style_position != other->inherited_flags._list_style_position)
565 return StyleDifferenceLayout;
568 if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
569 return StyleDifferenceLayout;
571 // SVGRenderStyle::diff() might have returned StyleDifferenceRepaint, eg. if fill changes.
572 // If eg. the font-size changed at the same time, we're not allowed to return StyleDifferenceRepaint,
573 // but have to return StyleDifferenceLayout, that's why this if branch comes after all branches
574 // that are relevant for SVG and might return StyleDifferenceLayout.
575 if (svgChange != StyleDifferenceEqual)
578 // NOTE: This block must be last in this function for the StyleDifferenceLayoutPositionedMovementOnly
579 // optimization to work properly.
580 if (position() != StaticPosition && surround->offset != other->surround->offset) {
581 // Optimize for the case where a positioned layer is moving but not changing size.
582 if ((position() == AbsolutePosition || position() == FixedPosition)
583 && positionedObjectMovedOnly(surround->offset, other->surround->offset, m_box->width())
584 && repaintOnlyDiff(other, changedContextSensitiveProperties) == StyleDifferenceEqual)
585 return StyleDifferenceLayoutPositionedMovementOnly;
586 // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
587 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
588 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
589 return StyleDifferenceLayout;
592 return repaintOnlyDiff(other, changedContextSensitiveProperties);
595 StyleDifference RenderStyle::repaintOnlyDiff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
597 if (position() != StaticPosition && (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex()
598 || visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip))
599 return StyleDifferenceRepaintLayer;
601 if (RuntimeEnabledFeatures::cssCompositingEnabled() && (rareNonInheritedData->m_effectiveBlendMode != other->rareNonInheritedData->m_effectiveBlendMode
602 || rareNonInheritedData->m_isolation != other->rareNonInheritedData->m_isolation))
603 return StyleDifferenceRepaintLayer;
605 if (rareNonInheritedData->opacity != other->rareNonInheritedData->opacity) {
606 // Don't return early here; instead take note of the type of change,
607 // and deal with it when looking at compositing.
608 changedContextSensitiveProperties |= ContextSensitivePropertyOpacity;
611 if (rareNonInheritedData->m_filter.get() != other->rareNonInheritedData->m_filter.get()
612 && *rareNonInheritedData->m_filter.get() != *other->rareNonInheritedData->m_filter.get()) {
613 // Don't return early here; instead take note of the type of change,
614 // and deal with it when looking at compositing.
615 changedContextSensitiveProperties |= ContextSensitivePropertyFilter;
618 if (rareNonInheritedData->m_mask != other->rareNonInheritedData->m_mask
619 || rareNonInheritedData->m_maskBoxImage != other->rareNonInheritedData->m_maskBoxImage)
620 return StyleDifferenceRepaintLayer;
622 if (inherited_flags._visibility != other->inherited_flags._visibility
623 || inherited_flags.m_printColorAdjust != other->inherited_flags.m_printColorAdjust
624 || inherited_flags._insideLink != other->inherited_flags._insideLink
625 || surround->border != other->surround->border
626 || *m_background.get() != *other->m_background.get()
627 || rareInheritedData->userModify != other->rareInheritedData->userModify
628 || rareInheritedData->userSelect != other->rareInheritedData->userSelect
629 || rareNonInheritedData->userDrag != other->rareNonInheritedData->userDrag
630 || rareNonInheritedData->m_borderFit != other->rareNonInheritedData->m_borderFit
631 || rareNonInheritedData->m_objectFit != other->rareNonInheritedData->m_objectFit
632 || rareNonInheritedData->m_objectPosition != other->rareNonInheritedData->m_objectPosition
633 || rareInheritedData->m_imageRendering != other->rareInheritedData->m_imageRendering)
634 return StyleDifferenceRepaint;
636 // FIXME: The current spec is being reworked to remove dependencies between exclusions and affected
637 // content. There's a proposal to use floats instead. In that case, wrap-shape should actually relayout
638 // the parent container. For sure, I will have to revisit this code, but for now I've added this in order
639 // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ.
640 // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991
641 if (rareNonInheritedData->m_shapeOutside != other->rareNonInheritedData->m_shapeOutside)
642 return StyleDifferenceRepaint;
644 if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath)
645 return StyleDifferenceRepaint;
647 if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) {
648 if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D
649 || rareNonInheritedData->m_backfaceVisibility != other->rareNonInheritedData->m_backfaceVisibility
650 || rareNonInheritedData->m_perspective != other->rareNonInheritedData->m_perspective
651 || rareNonInheritedData->m_perspectiveOriginX != other->rareNonInheritedData->m_perspectiveOriginX
652 || rareNonInheritedData->m_perspectiveOriginY != other->rareNonInheritedData->m_perspectiveOriginY)
653 return StyleDifferenceRecompositeLayer;
656 if (inherited->color != other->inherited->color
657 || inherited_flags._text_decorations != other->inherited_flags._text_decorations
658 || visual->textDecoration != other->visual->textDecoration
659 || rareNonInheritedData->m_textDecorationStyle != other->rareNonInheritedData->m_textDecorationStyle
660 || rareNonInheritedData->m_textDecorationColor != other->rareNonInheritedData->m_textDecorationColor
661 || rareInheritedData->textFillColor != other->rareInheritedData->textFillColor
662 || rareInheritedData->textStrokeColor != other->rareInheritedData->textStrokeColor
663 || rareInheritedData->textEmphasisColor != other->rareInheritedData->textEmphasisColor
664 || rareInheritedData->textEmphasisFill != other->rareInheritedData->textEmphasisFill)
665 return StyleDifferenceRepaintIfTextOrColorChange;
667 // Cursors are not checked, since they will be set appropriately in response to mouse events,
668 // so they don't need to cause any repaint or layout.
670 // 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
671 // the resulting transition properly.
672 return StyleDifferenceEqual;
675 void RenderStyle::setClip(Length top, Length right, Length bottom, Length left)
677 StyleVisualData* data = visual.access();
678 data->clip.m_top = top;
679 data->clip.m_right = right;
680 data->clip.m_bottom = bottom;
681 data->clip.m_left = left;
684 void RenderStyle::addCursor(PassRefPtr<StyleImage> image, const IntPoint& hotSpot)
686 if (!rareInheritedData.access()->cursorData)
687 rareInheritedData.access()->cursorData = CursorList::create();
688 rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot));
691 void RenderStyle::setCursorList(PassRefPtr<CursorList> other)
693 rareInheritedData.access()->cursorData = other;
696 void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
698 if (QuotesData::equals(rareInheritedData->quotes.get(), q.get()))
700 rareInheritedData.access()->quotes = q;
703 void RenderStyle::clearCursorList()
705 if (rareInheritedData->cursorData)
706 rareInheritedData.access()->cursorData = 0;
709 void RenderStyle::addCallbackSelector(const String& selector)
711 if (!rareNonInheritedData->m_callbackSelectors.contains(selector))
712 rareNonInheritedData.access()->m_callbackSelectors.append(selector);
715 void RenderStyle::clearContent()
717 if (rareNonInheritedData->m_content)
718 rareNonInheritedData.access()->m_content = nullptr;
721 void RenderStyle::appendContent(PassOwnPtr<ContentData> contentData)
723 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
724 ContentData* lastContent = content.get();
725 while (lastContent && lastContent->next())
726 lastContent = lastContent->next();
729 lastContent->setNext(contentData);
731 content = contentData;
734 void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add)
740 appendContent(ContentData::create(image));
744 rareNonInheritedData.access()->m_content = ContentData::create(image);
747 void RenderStyle::setContent(const String& string, bool add)
749 OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content;
751 ContentData* lastContent = content.get();
752 while (lastContent && lastContent->next())
753 lastContent = lastContent->next();
756 // We attempt to merge with the last ContentData if possible.
757 if (lastContent->isText()) {
758 TextContentData* textContent = static_cast<TextContentData*>(lastContent);
759 textContent->setText(textContent->text() + string);
761 lastContent->setNext(ContentData::create(string));
767 content = ContentData::create(string);
770 void RenderStyle::setContent(PassOwnPtr<CounterContent> counter, bool add)
776 appendContent(ContentData::create(counter));
780 rareNonInheritedData.access()->m_content = ContentData::create(counter);
783 void RenderStyle::setContent(QuoteType quote, bool add)
786 appendContent(ContentData::create(quote));
790 rareNonInheritedData.access()->m_content = ContentData::create(quote);
793 blink::WebBlendMode RenderStyle::blendMode() const
795 if (RuntimeEnabledFeatures::cssCompositingEnabled())
796 return static_cast<blink::WebBlendMode>(rareNonInheritedData->m_effectiveBlendMode);
797 return blink::WebBlendModeNormal;
800 void RenderStyle::setBlendMode(blink::WebBlendMode v)
802 if (RuntimeEnabledFeatures::cssCompositingEnabled())
803 rareNonInheritedData.access()->m_effectiveBlendMode = v;
806 bool RenderStyle::hasBlendMode() const
808 if (RuntimeEnabledFeatures::cssCompositingEnabled())
809 return static_cast<blink::WebBlendMode>(rareNonInheritedData->m_effectiveBlendMode) != blink::WebBlendModeNormal;
813 EIsolation RenderStyle::isolation() const
815 if (RuntimeEnabledFeatures::cssCompositingEnabled())
816 return static_cast<EIsolation>(rareNonInheritedData->m_isolation);
817 return IsolationAuto;
820 void RenderStyle::setIsolation(EIsolation v)
822 if (RuntimeEnabledFeatures::cssCompositingEnabled())
823 rareNonInheritedData.access()->m_isolation = v;
826 bool RenderStyle::hasIsolation() const
828 if (RuntimeEnabledFeatures::cssCompositingEnabled())
829 return rareNonInheritedData->m_isolation != IsolationAuto;
833 inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
835 // transform-origin brackets the transform with translate operations.
836 // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
838 if (applyOrigin != RenderStyle::IncludeTransformOrigin)
841 unsigned size = transformOperations.size();
842 for (unsigned i = 0; i < size; ++i) {
843 TransformOperation::OperationType type = transformOperations[i]->type();
844 if (type != TransformOperation::TranslateX
845 && type != TransformOperation::TranslateY
846 && type != TransformOperation::Translate
847 && type != TransformOperation::TranslateZ
848 && type != TransformOperation::Translate3D)
855 void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
857 applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin);
860 void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const
862 const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
863 bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
865 float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0;
866 float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0;
868 if (applyTransformOrigin) {
869 transform.translate3d(floatValueForLength(transformOriginX(), boundingBox.width()) + offsetX,
870 floatValueForLength(transformOriginY(), boundingBox.height()) + offsetY,
874 unsigned size = transformOperations.size();
875 for (unsigned i = 0; i < size; ++i)
876 transformOperations[i]->apply(transform, boundingBox.size());
878 if (applyTransformOrigin) {
879 transform.translate3d(-floatValueForLength(transformOriginX(), boundingBox.width()) - offsetX,
880 -floatValueForLength(transformOriginY(), boundingBox.height()) - offsetY,
881 -transformOriginZ());
885 void RenderStyle::setTextShadow(PassRefPtr<ShadowList> s)
887 rareInheritedData.access()->textShadow = s;
890 void RenderStyle::setBoxShadow(PassRefPtr<ShadowList> s)
892 rareNonInheritedData.access()->m_boxShadow = s;
895 static RoundedRect::Radii calcRadiiFor(const BorderData& border, IntSize size)
897 return RoundedRect::Radii(
898 IntSize(valueForLength(border.topLeft().width(), size.width()),
899 valueForLength(border.topLeft().height(), size.height())),
900 IntSize(valueForLength(border.topRight().width(), size.width()),
901 valueForLength(border.topRight().height(), size.height())),
902 IntSize(valueForLength(border.bottomLeft().width(), size.width()),
903 valueForLength(border.bottomLeft().height(), size.height())),
904 IntSize(valueForLength(border.bottomRight().width(), size.width()),
905 valueForLength(border.bottomRight().height(), size.height())));
908 static float calcConstraintScaleFor(const IntRect& rect, const RoundedRect::Radii& radii)
910 // Constrain corner radii using CSS3 rules:
911 // http://www.w3.org/TR/css3-background/#the-border-radius
917 radiiSum = static_cast<unsigned>(radii.topLeft().width()) + static_cast<unsigned>(radii.topRight().width()); // Casts to avoid integer overflow.
918 if (radiiSum > static_cast<unsigned>(rect.width()))
919 factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
922 radiiSum = static_cast<unsigned>(radii.bottomLeft().width()) + static_cast<unsigned>(radii.bottomRight().width());
923 if (radiiSum > static_cast<unsigned>(rect.width()))
924 factor = min(static_cast<float>(rect.width()) / radiiSum, factor);
927 radiiSum = static_cast<unsigned>(radii.topLeft().height()) + static_cast<unsigned>(radii.bottomLeft().height());
928 if (radiiSum > static_cast<unsigned>(rect.height()))
929 factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
932 radiiSum = static_cast<unsigned>(radii.topRight().height()) + static_cast<unsigned>(radii.bottomRight().height());
933 if (radiiSum > static_cast<unsigned>(rect.height()))
934 factor = min(static_cast<float>(rect.height()) / radiiSum, factor);
940 StyleImage* RenderStyle::listStyleImage() const { return rareInheritedData->listStyleImage.get(); }
941 void RenderStyle::setListStyleImage(PassRefPtr<StyleImage> v)
943 if (rareInheritedData->listStyleImage != v)
944 rareInheritedData.access()->listStyleImage = v;
947 Color RenderStyle::color() const { return inherited->color; }
948 Color RenderStyle::visitedLinkColor() const { return inherited->visitedLinkColor; }
949 void RenderStyle::setColor(const Color& v) { SET_VAR(inherited, color, v); }
950 void RenderStyle::setVisitedLinkColor(const Color& v) { SET_VAR(inherited, visitedLinkColor, v); }
952 short RenderStyle::horizontalBorderSpacing() const { return inherited->horizontal_border_spacing; }
953 short RenderStyle::verticalBorderSpacing() const { return inherited->vertical_border_spacing; }
954 void RenderStyle::setHorizontalBorderSpacing(short v) { SET_VAR(inherited, horizontal_border_spacing, v); }
955 void RenderStyle::setVerticalBorderSpacing(short v) { SET_VAR(inherited, vertical_border_spacing, v); }
957 RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
959 IntRect snappedBorderRect(pixelSnappedIntRect(borderRect));
960 RoundedRect roundedRect(snappedBorderRect);
961 if (hasBorderRadius()) {
962 RoundedRect::Radii radii = calcRadiiFor(surround->border, snappedBorderRect.size());
963 radii.scale(calcConstraintScaleFor(snappedBorderRect, radii));
964 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
969 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
971 bool horizontal = isHorizontalWritingMode();
973 int leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
974 int rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
975 int topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
976 int bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
978 return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
981 RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect,
982 int topWidth, int bottomWidth, int leftWidth, int rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
984 LayoutRect innerRect(borderRect.x() + leftWidth,
985 borderRect.y() + topWidth,
986 borderRect.width() - leftWidth - rightWidth,
987 borderRect.height() - topWidth - bottomWidth);
989 RoundedRect roundedRect(pixelSnappedIntRect(innerRect));
991 if (hasBorderRadius()) {
992 RoundedRect::Radii radii = getRoundedBorderFor(borderRect).radii();
993 radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
994 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
999 static bool allLayersAreFixed(const FillLayer* layer)
1001 bool allFixed = true;
1003 for (const FillLayer* currLayer = layer; currLayer; currLayer = currLayer->next())
1004 allFixed &= (currLayer->image() && currLayer->attachment() == FixedBackgroundAttachment);
1006 return layer && allFixed;
1009 bool RenderStyle::hasEntirelyFixedBackground() const
1011 return allLayersAreFixed(backgroundLayers());
1014 const CounterDirectiveMap* RenderStyle::counterDirectives() const
1016 return rareNonInheritedData->m_counterDirectives.get();
1019 CounterDirectiveMap& RenderStyle::accessCounterDirectives()
1021 OwnPtr<CounterDirectiveMap>& map = rareNonInheritedData.access()->m_counterDirectives;
1023 map = adoptPtr(new CounterDirectiveMap);
1027 const CounterDirectives RenderStyle::getCounterDirectives(const AtomicString& identifier) const
1029 if (const CounterDirectiveMap* directives = counterDirectives())
1030 return directives->get(identifier);
1031 return CounterDirectives();
1034 const AtomicString& RenderStyle::hyphenString() const
1036 const AtomicString& hyphenationString = rareInheritedData.get()->hyphenationString;
1037 if (!hyphenationString.isNull())
1038 return hyphenationString;
1040 // FIXME: This should depend on locale.
1041 DEFINE_STATIC_LOCAL(AtomicString, hyphenMinusString, (&hyphenMinus, 1));
1042 DEFINE_STATIC_LOCAL(AtomicString, hyphenString, (&hyphen, 1));
1043 return font().primaryFontHasGlyphForCharacter(hyphen) ? hyphenString : hyphenMinusString;
1046 const AtomicString& RenderStyle::textEmphasisMarkString() const
1048 switch (textEmphasisMark()) {
1049 case TextEmphasisMarkNone:
1051 case TextEmphasisMarkCustom:
1052 return textEmphasisCustomMark();
1053 case TextEmphasisMarkDot: {
1054 DEFINE_STATIC_LOCAL(AtomicString, filledDotString, (&bullet, 1));
1055 DEFINE_STATIC_LOCAL(AtomicString, openDotString, (&whiteBullet, 1));
1056 return textEmphasisFill() == TextEmphasisFillFilled ? filledDotString : openDotString;
1058 case TextEmphasisMarkCircle: {
1059 DEFINE_STATIC_LOCAL(AtomicString, filledCircleString, (&blackCircle, 1));
1060 DEFINE_STATIC_LOCAL(AtomicString, openCircleString, (&whiteCircle, 1));
1061 return textEmphasisFill() == TextEmphasisFillFilled ? filledCircleString : openCircleString;
1063 case TextEmphasisMarkDoubleCircle: {
1064 DEFINE_STATIC_LOCAL(AtomicString, filledDoubleCircleString, (&fisheye, 1));
1065 DEFINE_STATIC_LOCAL(AtomicString, openDoubleCircleString, (&bullseye, 1));
1066 return textEmphasisFill() == TextEmphasisFillFilled ? filledDoubleCircleString : openDoubleCircleString;
1068 case TextEmphasisMarkTriangle: {
1069 DEFINE_STATIC_LOCAL(AtomicString, filledTriangleString, (&blackUpPointingTriangle, 1));
1070 DEFINE_STATIC_LOCAL(AtomicString, openTriangleString, (&whiteUpPointingTriangle, 1));
1071 return textEmphasisFill() == TextEmphasisFillFilled ? filledTriangleString : openTriangleString;
1073 case TextEmphasisMarkSesame: {
1074 DEFINE_STATIC_LOCAL(AtomicString, filledSesameString, (&sesameDot, 1));
1075 DEFINE_STATIC_LOCAL(AtomicString, openSesameString, (&whiteSesameDot, 1));
1076 return textEmphasisFill() == TextEmphasisFillFilled ? filledSesameString : openSesameString;
1078 case TextEmphasisMarkAuto:
1079 ASSERT_NOT_REACHED();
1083 ASSERT_NOT_REACHED();
1087 void RenderStyle::adjustAnimations()
1089 CSSAnimationDataList* animationList = rareNonInheritedData->m_animations.get();
1093 // Get rid of empty animations and anything beyond them
1094 for (size_t i = 0; i < animationList->size(); ++i) {
1095 if (animationList->animation(i)->isEmpty()) {
1096 animationList->resize(i);
1101 if (animationList->isEmpty()) {
1106 // Repeat patterns into layers that don't have some properties set.
1107 animationList->fillUnsetProperties();
1110 void RenderStyle::adjustTransitions()
1112 CSSAnimationDataList* transitionList = rareNonInheritedData->m_transitions.get();
1113 if (!transitionList)
1116 // Get rid of empty transitions and anything beyond them
1117 for (size_t i = 0; i < transitionList->size(); ++i) {
1118 if (transitionList->animation(i)->isEmpty()) {
1119 transitionList->resize(i);
1124 if (transitionList->isEmpty()) {
1129 // Repeat patterns into layers that don't have some properties set.
1130 transitionList->fillUnsetProperties();
1132 // Make sure there are no duplicate properties. This is an O(n^2) algorithm
1133 // but the lists tend to be very short, so it is probably ok
1134 for (size_t i = 0; i < transitionList->size(); ++i) {
1135 for (size_t j = i+1; j < transitionList->size(); ++j) {
1136 if (transitionList->animation(i)->property() == transitionList->animation(j)->property()) {
1138 transitionList->remove(i);
1145 CSSAnimationDataList* RenderStyle::accessAnimations()
1147 if (!rareNonInheritedData.access()->m_animations)
1148 rareNonInheritedData.access()->m_animations = adoptPtr(new CSSAnimationDataList());
1149 return rareNonInheritedData->m_animations.get();
1152 CSSAnimationDataList* RenderStyle::accessTransitions()
1154 if (!rareNonInheritedData.access()->m_transitions)
1155 rareNonInheritedData.access()->m_transitions = adoptPtr(new CSSAnimationDataList());
1156 return rareNonInheritedData->m_transitions.get();
1159 const CSSAnimationData* RenderStyle::transitionForProperty(CSSPropertyID property) const
1161 if (transitions()) {
1162 for (size_t i = 0; i < transitions()->size(); ++i) {
1163 const CSSAnimationData* p = transitions()->animation(i);
1164 if (p->animationMode() == CSSAnimationData::AnimateAll || p->property() == property) {
1172 const Font& RenderStyle::font() const { return inherited->font; }
1173 const FontMetrics& RenderStyle::fontMetrics() const { return inherited->font.fontMetrics(); }
1174 const FontDescription& RenderStyle::fontDescription() const { return inherited->font.fontDescription(); }
1175 float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); }
1176 float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); }
1177 int RenderStyle::fontSize() const { return fontDescription().computedPixelSize(); }
1179 float RenderStyle::wordSpacing() const { return fontDescription().wordSpacing(); }
1180 float RenderStyle::letterSpacing() const { return fontDescription().letterSpacing(); }
1182 bool RenderStyle::setFontDescription(const FontDescription& v)
1184 if (inherited->font.fontDescription() != v) {
1185 inherited.access()->font = Font(v);
1191 Length RenderStyle::specifiedLineHeight() const { return inherited->line_height; }
1192 Length RenderStyle::lineHeight() const
1194 const Length& lh = inherited->line_height;
1195 // Unlike fontDescription().computedSize() and hence fontSize(), this is
1196 // recalculated on demand as we only store the specified line height.
1197 // FIXME: Should consider scaling the fixed part of any calc expressions
1198 // too, though this involves messily poking into CalcExpressionLength.
1199 float multiplier = textAutosizingMultiplier();
1200 if (multiplier > 1 && lh.isFixed())
1201 return Length(TextAutosizer::computeAutosizedFontSize(lh.value(), multiplier), Fixed);
1205 void RenderStyle::setLineHeight(Length specifiedLineHeight) { SET_VAR(inherited, line_height, specifiedLineHeight); }
1207 int RenderStyle::computedLineHeight() const
1209 const Length& lh = lineHeight();
1211 // Negative value means the line height is not set. Use the font's built-in spacing.
1212 if (lh.isNegative())
1213 return fontMetrics().lineSpacing();
1216 return minimumValueForLength(lh, fontSize());
1221 void RenderStyle::setWordSpacing(float v) { inherited.access()->font.mutableFontDescription().setWordSpacing(v); }
1222 void RenderStyle::setLetterSpacing(float v) { inherited.access()->font.mutableFontDescription().setLetterSpacing(v); }
1224 void RenderStyle::setFontSize(float size)
1226 // size must be specifiedSize if Text Autosizing is enabled, but computedSize if text
1227 // zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
1229 ASSERT(std::isfinite(size));
1230 if (!std::isfinite(size) || size < 0)
1233 size = min(maximumAllowedFontSize, size);
1235 FontSelector* currentFontSelector = font().fontSelector();
1236 FontDescription desc(fontDescription());
1237 desc.setSpecifiedSize(size);
1238 desc.setComputedSize(size);
1240 float multiplier = textAutosizingMultiplier();
1241 if (multiplier > 1) {
1242 float autosizedFontSize = TextAutosizer::computeAutosizedFontSize(size, multiplier);
1243 desc.setComputedSize(min(maximumAllowedFontSize, autosizedFontSize));
1246 setFontDescription(desc);
1247 font().update(currentFontSelector);
1250 void RenderStyle::getShadowExtent(const ShadowList* shadowList, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const
1257 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1258 for (size_t i = 0; i < shadowCount; ++i) {
1259 const ShadowData& shadow = shadowList->shadows()[i];
1260 if (shadow.style() == Inset)
1262 float blurAndSpread = shadow.blur() + shadow.spread();
1264 top = min<LayoutUnit>(top, shadow.y() - blurAndSpread);
1265 right = max<LayoutUnit>(right, shadow.x() + blurAndSpread);
1266 bottom = max<LayoutUnit>(bottom, shadow.y() + blurAndSpread);
1267 left = min<LayoutUnit>(left, shadow.x() - blurAndSpread);
1271 LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowList* shadowList) const
1274 LayoutUnit right = 0;
1275 LayoutUnit bottom = 0;
1276 LayoutUnit left = 0;
1278 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1279 for (size_t i = 0; i < shadowCount; ++i) {
1280 const ShadowData& shadow = shadowList->shadows()[i];
1281 if (shadow.style() == Normal)
1283 float blurAndSpread = shadow.blur() + shadow.spread();
1284 top = max<LayoutUnit>(top, shadow.y() + blurAndSpread);
1285 right = min<LayoutUnit>(right, shadow.x() - blurAndSpread);
1286 bottom = min<LayoutUnit>(bottom, shadow.y() - blurAndSpread);
1287 left = max<LayoutUnit>(left, shadow.x() + blurAndSpread);
1290 return LayoutBoxExtent(top, right, bottom, left);
1293 void RenderStyle::getShadowHorizontalExtent(const ShadowList* shadowList, LayoutUnit &left, LayoutUnit &right) const
1298 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1299 for (size_t i = 0; i < shadowCount; ++i) {
1300 const ShadowData& shadow = shadowList->shadows()[i];
1301 if (shadow.style() == Inset)
1303 float blurAndSpread = shadow.blur() + shadow.spread();
1305 left = min<LayoutUnit>(left, shadow.x() - blurAndSpread);
1306 right = max<LayoutUnit>(right, shadow.x() + blurAndSpread);
1310 void RenderStyle::getShadowVerticalExtent(const ShadowList* shadowList, LayoutUnit &top, LayoutUnit &bottom) const
1315 size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1316 for (size_t i = 0; i < shadowCount; ++i) {
1317 const ShadowData& shadow = shadowList->shadows()[i];
1318 if (shadow.style() == Inset)
1320 float blurAndSpread = shadow.blur() + shadow.spread();
1322 top = min<LayoutUnit>(top, shadow.y() - blurAndSpread);
1323 bottom = max<LayoutUnit>(bottom, shadow.y() + blurAndSpread);
1327 StyleColor RenderStyle::visitedDependentDecorationColor() const
1329 // Text decoration color fallback is handled in RenderObject::decorationColor.
1330 return insideLink() == InsideVisitedLink ? visitedLinkTextDecorationColor() : textDecorationColor();
1333 Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) const
1335 StyleColor result(StyleColor::currentColor());
1336 EBorderStyle borderStyle = BNONE;
1337 switch (colorProperty) {
1338 case CSSPropertyBackgroundColor:
1339 result = visitedLink ? visitedLinkBackgroundColor() : backgroundColor();
1341 case CSSPropertyBorderLeftColor:
1342 result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor();
1343 borderStyle = borderLeftStyle();
1345 case CSSPropertyBorderRightColor:
1346 result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor();
1347 borderStyle = borderRightStyle();
1349 case CSSPropertyBorderTopColor:
1350 result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor();
1351 borderStyle = borderTopStyle();
1353 case CSSPropertyBorderBottomColor:
1354 result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor();
1355 borderStyle = borderBottomStyle();
1357 case CSSPropertyColor:
1358 result = visitedLink ? visitedLinkColor() : color();
1360 case CSSPropertyOutlineColor:
1361 result = visitedLink ? visitedLinkOutlineColor() : outlineColor();
1363 case CSSPropertyWebkitColumnRuleColor:
1364 result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor();
1366 case CSSPropertyWebkitTextEmphasisColor:
1367 result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor();
1369 case CSSPropertyWebkitTextFillColor:
1370 result = visitedLink ? visitedLinkTextFillColor() : textFillColor();
1372 case CSSPropertyWebkitTextStrokeColor:
1373 result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor();
1375 case CSSPropertyFloodColor:
1376 result = floodColor();
1378 case CSSPropertyLightingColor:
1379 result = lightingColor();
1381 case CSSPropertyStopColor:
1382 result = stopColor();
1384 case CSSPropertyWebkitTapHighlightColor:
1385 result = tapHighlightColor();
1388 ASSERT_NOT_REACHED();
1392 if (!result.isCurrentColor())
1393 return result.color();
1395 // FIXME: Treating styled borders with initial color differently causes problems
1396 // See crbug.com/316559, crbug.com/276231
1397 if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE))
1398 return Color(238, 238, 238);
1399 return visitedLink ? visitedLinkColor() : color();
1402 Color RenderStyle::visitedDependentColor(int colorProperty) const
1404 Color unvisitedColor = colorIncludingFallback(colorProperty, false);
1405 if (insideLink() != InsideVisitedLink)
1406 return unvisitedColor;
1408 Color visitedColor = colorIncludingFallback(colorProperty, true);
1410 // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
1411 // assume that if the background color is transparent that it wasn't set. Note that it's weird that
1412 // we're returning unvisited info for a visited link, but given our restriction that the alpha values
1413 // have to match, it makes more sense to return the unvisited background color if specified than it
1414 // does to return black. This behavior matches what Firefox 4 does as well.
1415 if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent)
1416 return unvisitedColor;
1418 // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1419 return Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), unvisitedColor.alpha());
1422 const BorderValue& RenderStyle::borderBefore() const
1424 switch (writingMode()) {
1425 case TopToBottomWritingMode:
1427 case BottomToTopWritingMode:
1428 return borderBottom();
1429 case LeftToRightWritingMode:
1430 return borderLeft();
1431 case RightToLeftWritingMode:
1432 return borderRight();
1434 ASSERT_NOT_REACHED();
1438 const BorderValue& RenderStyle::borderAfter() const
1440 switch (writingMode()) {
1441 case TopToBottomWritingMode:
1442 return borderBottom();
1443 case BottomToTopWritingMode:
1445 case LeftToRightWritingMode:
1446 return borderRight();
1447 case RightToLeftWritingMode:
1448 return borderLeft();
1450 ASSERT_NOT_REACHED();
1451 return borderBottom();
1454 const BorderValue& RenderStyle::borderStart() const
1456 if (isHorizontalWritingMode())
1457 return isLeftToRightDirection() ? borderLeft() : borderRight();
1458 return isLeftToRightDirection() ? borderTop() : borderBottom();
1461 const BorderValue& RenderStyle::borderEnd() const
1463 if (isHorizontalWritingMode())
1464 return isLeftToRightDirection() ? borderRight() : borderLeft();
1465 return isLeftToRightDirection() ? borderBottom() : borderTop();
1468 unsigned short RenderStyle::borderBeforeWidth() const
1470 switch (writingMode()) {
1471 case TopToBottomWritingMode:
1472 return borderTopWidth();
1473 case BottomToTopWritingMode:
1474 return borderBottomWidth();
1475 case LeftToRightWritingMode:
1476 return borderLeftWidth();
1477 case RightToLeftWritingMode:
1478 return borderRightWidth();
1480 ASSERT_NOT_REACHED();
1481 return borderTopWidth();
1484 unsigned short RenderStyle::borderAfterWidth() const
1486 switch (writingMode()) {
1487 case TopToBottomWritingMode:
1488 return borderBottomWidth();
1489 case BottomToTopWritingMode:
1490 return borderTopWidth();
1491 case LeftToRightWritingMode:
1492 return borderRightWidth();
1493 case RightToLeftWritingMode:
1494 return borderLeftWidth();
1496 ASSERT_NOT_REACHED();
1497 return borderBottomWidth();
1500 unsigned short RenderStyle::borderStartWidth() const
1502 if (isHorizontalWritingMode())
1503 return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
1504 return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
1507 unsigned short RenderStyle::borderEndWidth() const
1509 if (isHorizontalWritingMode())
1510 return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
1511 return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
1514 void RenderStyle::setMarginStart(Length margin)
1516 if (isHorizontalWritingMode()) {
1517 if (isLeftToRightDirection())
1518 setMarginLeft(margin);
1520 setMarginRight(margin);
1522 if (isLeftToRightDirection())
1523 setMarginTop(margin);
1525 setMarginBottom(margin);
1529 void RenderStyle::setMarginEnd(Length margin)
1531 if (isHorizontalWritingMode()) {
1532 if (isLeftToRightDirection())
1533 setMarginRight(margin);
1535 setMarginLeft(margin);
1537 if (isLeftToRightDirection())
1538 setMarginBottom(margin);
1540 setMarginTop(margin);
1544 TextEmphasisMark RenderStyle::textEmphasisMark() const
1546 TextEmphasisMark mark = static_cast<TextEmphasisMark>(rareInheritedData->textEmphasisMark);
1547 if (mark != TextEmphasisMarkAuto)
1550 if (isHorizontalWritingMode())
1551 return TextEmphasisMarkDot;
1553 return TextEmphasisMarkSesame;
1556 Color RenderStyle::initialTapHighlightColor()
1558 return RenderTheme::tapHighlightColor();
1561 LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const
1563 return LayoutBoxExtent(NinePieceImage::computeOutset(image.outset().top(), borderTopWidth()),
1564 NinePieceImage::computeOutset(image.outset().right(), borderRightWidth()),
1565 NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth()),
1566 NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth()));
1569 void RenderStyle::setBorderImageSource(PassRefPtr<StyleImage> image)
1571 if (surround->border.m_image.image() == image.get())
1573 surround.access()->border.m_image.setImage(image);
1576 void RenderStyle::setBorderImageSlices(LengthBox slices)
1578 if (surround->border.m_image.imageSlices() == slices)
1580 surround.access()->border.m_image.setImageSlices(slices);
1583 void RenderStyle::setBorderImageWidth(const BorderImageLengthBox& slices)
1585 if (surround->border.m_image.borderSlices() == slices)
1587 surround.access()->border.m_image.setBorderSlices(slices);
1590 void RenderStyle::setBorderImageOutset(const BorderImageLengthBox& outset)
1592 if (surround->border.m_image.outset() == outset)
1594 surround.access()->border.m_image.setOutset(outset);
1597 } // namespace WebCore