1/*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
4 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
5 *
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.
10 *
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.
15 *
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.
20 *
21 */
22
23#include "config.h"
24#include "RenderStyle.h"
25
26#include "CSSComputedStyleDeclaration.h"
27#include "CSSCustomPropertyValue.h"
28#include "CSSParser.h"
29#include "CSSPropertyNames.h"
30#include "CSSPropertyParser.h"
31#include "ContentData.h"
32#include "CursorList.h"
33#include "FloatRoundedRect.h"
34#include "FontCascade.h"
35#include "FontSelector.h"
36#include "InlineTextBoxStyle.h"
37#include "Pagination.h"
38#include "QuotesData.h"
39#include "RenderObject.h"
40#include "RenderTheme.h"
41#include "RuntimeEnabledFeatures.h"
42#include "ScaleTransformOperation.h"
43#include "ShadowData.h"
44#include "StyleBuilderConverter.h"
45#include "StyleImage.h"
46#include "StyleInheritedData.h"
47#include "StyleResolver.h"
48#include "StyleScrollSnapPoints.h"
49#include "StyleSelfAlignmentData.h"
50#include "StyleTreeResolver.h"
51#include "WillChangeData.h"
52#include <wtf/MathExtras.h>
53#include <wtf/PointerComparison.h>
54#include <wtf/StdLibExtras.h>
55#include <algorithm>
56
57#if ENABLE(TEXT_AUTOSIZING)
58#include <wtf/text/StringHash.h>
59#endif
60
61namespace WebCore {
62
63struct SameSizeAsBorderValue {
64 Color m_color;
65 float m_width;
66 int m_restBits;
67};
68
69COMPILE_ASSERT(sizeof(BorderValue) == sizeof(SameSizeAsBorderValue), BorderValue_should_not_grow);
70
71struct SameSizeAsRenderStyle {
72 void* dataRefs[7];
73 void* ownPtrs[1];
74 void* dataRefSvgStyle;
75 struct InheritedFlags {
76 unsigned m_bitfields[2];
77 } m_inheritedFlags;
78
79 struct NonInheritedFlags {
80 unsigned m_bitfields[2];
81 } m_nonInheritedFlags;
82#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
83 bool deletionCheck;
84#endif
85};
86
87static_assert(sizeof(RenderStyle) == sizeof(SameSizeAsRenderStyle), "RenderStyle should stay small");
88
89RenderStyle& RenderStyle::defaultStyle()
90{
91 static NeverDestroyed<RenderStyle> style { CreateDefaultStyle };
92 return style;
93}
94
95RenderStyle RenderStyle::create()
96{
97 return clone(defaultStyle());
98}
99
100std::unique_ptr<RenderStyle> RenderStyle::createPtr()
101{
102 return clonePtr(defaultStyle());
103}
104
105RenderStyle RenderStyle::clone(const RenderStyle& style)
106{
107 return RenderStyle(style, Clone);
108}
109
110std::unique_ptr<RenderStyle> RenderStyle::clonePtr(const RenderStyle& style)
111{
112 return std::make_unique<RenderStyle>(style, Clone);
113}
114
115RenderStyle RenderStyle::createAnonymousStyleWithDisplay(const RenderStyle& parentStyle, DisplayType display)
116{
117 auto newStyle = create();
118 newStyle.inheritFrom(parentStyle);
119 newStyle.inheritUnicodeBidiFrom(&parentStyle);
120 newStyle.setDisplay(display);
121 return newStyle;
122}
123
124RenderStyle RenderStyle::createStyleInheritingFromPseudoStyle(const RenderStyle& pseudoStyle)
125{
126 ASSERT(pseudoStyle.styleType() == PseudoId::Before || pseudoStyle.styleType() == PseudoId::After);
127
128 auto style = create();
129 style.inheritFrom(pseudoStyle);
130 return style;
131}
132
133RenderStyle::RenderStyle(RenderStyle&&) = default;
134RenderStyle& RenderStyle::operator=(RenderStyle&&) = default;
135
136RenderStyle::RenderStyle(CreateDefaultStyleTag)
137 : m_boxData(StyleBoxData::create())
138 , m_visualData(StyleVisualData::create())
139 , m_backgroundData(StyleBackgroundData::create())
140 , m_surroundData(StyleSurroundData::create())
141 , m_rareNonInheritedData(StyleRareNonInheritedData::create())
142 , m_rareInheritedData(StyleRareInheritedData::create())
143 , m_inheritedData(StyleInheritedData::create())
144 , m_svgStyle(SVGRenderStyle::create())
145{
146 m_inheritedFlags.emptyCells = static_cast<unsigned>(initialEmptyCells());
147 m_inheritedFlags.captionSide = static_cast<unsigned>(initialCaptionSide());
148 m_inheritedFlags.listStyleType = static_cast<unsigned>(initialListStyleType());
149 m_inheritedFlags.listStylePosition = static_cast<unsigned>(initialListStylePosition());
150 m_inheritedFlags.visibility = static_cast<unsigned>(initialVisibility());
151 m_inheritedFlags.textAlign = static_cast<unsigned>(initialTextAlign());
152 m_inheritedFlags.textTransform = static_cast<unsigned>(initialTextTransform());
153 m_inheritedFlags.textDecorations = initialTextDecoration().toRaw();
154 m_inheritedFlags.cursor = static_cast<unsigned>(initialCursor());
155#if ENABLE(CURSOR_VISIBILITY)
156 m_inheritedFlags.cursorVisibility = static_cast<unsigned>(initialCursorVisibility());
157#endif
158 m_inheritedFlags.direction = static_cast<unsigned>(initialDirection());
159 m_inheritedFlags.whiteSpace = static_cast<unsigned>(initialWhiteSpace());
160 m_inheritedFlags.borderCollapse = static_cast<unsigned>(initialBorderCollapse());
161 m_inheritedFlags.rtlOrdering = static_cast<unsigned>(initialRTLOrdering());
162 m_inheritedFlags.boxDirection = static_cast<unsigned>(initialBoxDirection());
163 m_inheritedFlags.printColorAdjust = static_cast<unsigned>(initialPrintColorAdjust());
164 m_inheritedFlags.pointerEvents = static_cast<unsigned>(initialPointerEvents());
165 m_inheritedFlags.insideLink = static_cast<unsigned>(InsideLink::NotInside);
166 m_inheritedFlags.insideDefaultButton = false;
167 m_inheritedFlags.writingMode = initialWritingMode();
168
169 m_nonInheritedFlags.effectiveDisplay = static_cast<unsigned>(initialDisplay());
170 m_nonInheritedFlags.originalDisplay = static_cast<unsigned>(initialDisplay());
171 m_nonInheritedFlags.overflowX = static_cast<unsigned>(initialOverflowX());
172 m_nonInheritedFlags.overflowY = static_cast<unsigned>(initialOverflowY());
173 m_nonInheritedFlags.verticalAlign = static_cast<unsigned>(initialVerticalAlign());
174 m_nonInheritedFlags.clear = static_cast<unsigned>(initialClear());
175 m_nonInheritedFlags.position = static_cast<unsigned>(initialPosition());
176 m_nonInheritedFlags.unicodeBidi = initialUnicodeBidi();
177 m_nonInheritedFlags.floating = static_cast<unsigned>(initialFloating());
178 m_nonInheritedFlags.tableLayout = static_cast<unsigned>(initialTableLayout());
179 m_nonInheritedFlags.hasExplicitlySetDirection = false;
180 m_nonInheritedFlags.hasExplicitlySetWritingMode = false;
181 m_nonInheritedFlags.hasExplicitlySetTextAlign = false;
182 m_nonInheritedFlags.hasViewportUnits = false;
183 m_nonInheritedFlags.hasExplicitlyInheritedProperties = false;
184 m_nonInheritedFlags.isUnique = false;
185 m_nonInheritedFlags.emptyState = false;
186 m_nonInheritedFlags.firstChildState = false;
187 m_nonInheritedFlags.lastChildState = false;
188 m_nonInheritedFlags.affectedByHover = false;
189 m_nonInheritedFlags.affectedByActive = false;
190 m_nonInheritedFlags.affectedByDrag = false;
191 m_nonInheritedFlags.isLink = false;
192 m_nonInheritedFlags.styleType = static_cast<unsigned>(PseudoId::None);
193 m_nonInheritedFlags.pseudoBits = static_cast<unsigned>(PseudoId::None);
194
195 static_assert((sizeof(InheritedFlags) <= 8), "InheritedFlags does not grow");
196 static_assert((sizeof(NonInheritedFlags) <= 8), "NonInheritedFlags does not grow");
197}
198
199inline RenderStyle::RenderStyle(const RenderStyle& other, CloneTag)
200 : m_boxData(other.m_boxData)
201 , m_visualData(other.m_visualData)
202 , m_backgroundData(other.m_backgroundData)
203 , m_surroundData(other.m_surroundData)
204 , m_rareNonInheritedData(other.m_rareNonInheritedData)
205 , m_nonInheritedFlags(other.m_nonInheritedFlags)
206 , m_rareInheritedData(other.m_rareInheritedData)
207 , m_inheritedData(other.m_inheritedData)
208 , m_inheritedFlags(other.m_inheritedFlags)
209 , m_svgStyle(other.m_svgStyle)
210{
211}
212
213inline RenderStyle::RenderStyle(RenderStyle& a, RenderStyle&& b)
214 : m_boxData(a.m_boxData.replace(WTFMove(b.m_boxData)))
215 , m_visualData(a.m_visualData.replace(WTFMove(b.m_visualData)))
216 , m_backgroundData(a.m_backgroundData.replace(WTFMove(b.m_backgroundData)))
217 , m_surroundData(a.m_surroundData.replace(WTFMove(b.m_surroundData)))
218 , m_rareNonInheritedData(a.m_rareNonInheritedData.replace(WTFMove(b.m_rareNonInheritedData)))
219 , m_nonInheritedFlags(std::exchange(a.m_nonInheritedFlags, b.m_nonInheritedFlags))
220 , m_rareInheritedData(a.m_rareInheritedData.replace(WTFMove(b.m_rareInheritedData)))
221 , m_inheritedData(a.m_inheritedData.replace(WTFMove(b.m_inheritedData)))
222 , m_inheritedFlags(std::exchange(a.m_inheritedFlags, b.m_inheritedFlags))
223 , m_cachedPseudoStyles(std::exchange(a.m_cachedPseudoStyles, WTFMove(b.m_cachedPseudoStyles)))
224 , m_svgStyle(a.m_svgStyle.replace(WTFMove(b.m_svgStyle)))
225{
226}
227
228RenderStyle::~RenderStyle()
229{
230#if !ASSERT_DISABLED || ENABLE(SECURITY_ASSERTIONS)
231 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
232 m_deletionHasBegun = true;
233#endif
234}
235
236RenderStyle RenderStyle::replace(RenderStyle&& newStyle)
237{
238 return RenderStyle { *this, WTFMove(newStyle) };
239}
240
241static StyleSelfAlignmentData resolvedSelfAlignment(const StyleSelfAlignmentData& value, ItemPosition normalValueBehavior)
242{
243 if (value.position() == ItemPosition::Legacy || value.position() == ItemPosition::Normal || value.position() == ItemPosition::Auto)
244 return { normalValueBehavior, OverflowAlignment::Default };
245 return value;
246}
247
248StyleSelfAlignmentData RenderStyle::resolvedAlignItems(ItemPosition normalValueBehaviour) const
249{
250 return resolvedSelfAlignment(alignItems(), normalValueBehaviour);
251}
252
253StyleSelfAlignmentData RenderStyle::resolvedAlignSelf(const RenderStyle* parentStyle, ItemPosition normalValueBehaviour) const
254{
255 // The auto keyword computes to the parent's align-items computed value.
256 // We will return the behaviour of 'normal' value if needed, which is specific of each layout model.
257 if (!parentStyle || alignSelf().position() != ItemPosition::Auto)
258 return resolvedSelfAlignment(alignSelf(), normalValueBehaviour);
259 return parentStyle->resolvedAlignItems(normalValueBehaviour);
260}
261
262StyleSelfAlignmentData RenderStyle::resolvedJustifyItems(ItemPosition normalValueBehaviour) const
263{
264 return resolvedSelfAlignment(justifyItems(), normalValueBehaviour);
265}
266
267StyleSelfAlignmentData RenderStyle::resolvedJustifySelf(const RenderStyle* parentStyle, ItemPosition normalValueBehaviour) const
268{
269 // The auto keyword computes to the parent's justify-items computed value.
270 // We will return the behaviour of 'normal' value if needed, which is specific of each layout model.
271 if (!parentStyle || justifySelf().position() != ItemPosition::Auto)
272 return resolvedSelfAlignment(justifySelf(), normalValueBehaviour);
273 return parentStyle->resolvedJustifyItems(normalValueBehaviour);
274}
275
276static inline StyleContentAlignmentData resolvedContentAlignment(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior)
277{
278 return (value.position() == ContentPosition::Normal && value.distribution() == ContentDistribution::Default) ? normalValueBehavior : value;
279}
280
281StyleContentAlignmentData RenderStyle::resolvedAlignContent(const StyleContentAlignmentData& normalValueBehavior) const
282{
283 // We will return the behaviour of 'normal' value if needed, which is specific of each layout model.
284 return resolvedContentAlignment(alignContent(), normalValueBehavior);
285}
286
287StyleContentAlignmentData RenderStyle::resolvedJustifyContent(const StyleContentAlignmentData& normalValueBehavior) const
288{
289 // We will return the behaviour of 'normal' value if needed, which is specific of each layout model.
290 return resolvedContentAlignment(justifyContent(), normalValueBehavior);
291}
292
293static inline ContentPosition resolvedContentAlignmentPosition(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior)
294{
295 return (value.position() == ContentPosition::Normal && value.distribution() == ContentDistribution::Default) ? normalValueBehavior.position() : value.position();
296}
297
298static inline ContentDistribution resolvedContentAlignmentDistribution(const StyleContentAlignmentData& value, const StyleContentAlignmentData& normalValueBehavior)
299{
300 return (value.position() == ContentPosition::Normal && value.distribution() == ContentDistribution::Default) ? normalValueBehavior.distribution() : value.distribution();
301}
302
303ContentPosition RenderStyle::resolvedJustifyContentPosition(const StyleContentAlignmentData& normalValueBehavior) const
304{
305 return resolvedContentAlignmentPosition(justifyContent(), normalValueBehavior);
306}
307
308ContentDistribution RenderStyle::resolvedJustifyContentDistribution(const StyleContentAlignmentData& normalValueBehavior) const
309{
310 return resolvedContentAlignmentDistribution(justifyContent(), normalValueBehavior);
311}
312
313ContentPosition RenderStyle::resolvedAlignContentPosition(const StyleContentAlignmentData& normalValueBehavior) const
314{
315 return resolvedContentAlignmentPosition(alignContent(), normalValueBehavior);
316}
317
318ContentDistribution RenderStyle::resolvedAlignContentDistribution(const StyleContentAlignmentData& normalValueBehavior) const
319{
320 return resolvedContentAlignmentDistribution(alignContent(), normalValueBehavior);
321}
322
323void RenderStyle::inheritFrom(const RenderStyle& inheritParent)
324{
325 m_rareInheritedData = inheritParent.m_rareInheritedData;
326 m_inheritedData = inheritParent.m_inheritedData;
327 m_inheritedFlags = inheritParent.m_inheritedFlags;
328
329 if (m_svgStyle != inheritParent.m_svgStyle)
330 m_svgStyle.access().inheritFrom(inheritParent.m_svgStyle.get());
331}
332
333void RenderStyle::copyNonInheritedFrom(const RenderStyle& other)
334{
335 m_boxData = other.m_boxData;
336 m_visualData = other.m_visualData;
337 m_backgroundData = other.m_backgroundData;
338 m_surroundData = other.m_surroundData;
339 m_rareNonInheritedData = other.m_rareNonInheritedData;
340 m_nonInheritedFlags.copyNonInheritedFrom(other.m_nonInheritedFlags);
341
342 if (m_svgStyle != other.m_svgStyle)
343 m_svgStyle.access().copyNonInheritedFrom(other.m_svgStyle.get());
344
345 ASSERT(zoom() == initialZoom());
346}
347
348void RenderStyle::copyContentFrom(const RenderStyle& other)
349{
350 if (!other.m_rareNonInheritedData->content)
351 return;
352 m_rareNonInheritedData.access().content = other.m_rareNonInheritedData->content->clone();
353}
354
355bool RenderStyle::operator==(const RenderStyle& other) const
356{
357 // compare everything except the pseudoStyle pointer
358 return m_inheritedFlags == other.m_inheritedFlags
359 && m_nonInheritedFlags == other.m_nonInheritedFlags
360 && m_boxData == other.m_boxData
361 && m_visualData == other.m_visualData
362 && m_backgroundData == other.m_backgroundData
363 && m_surroundData == other.m_surroundData
364 && m_rareNonInheritedData == other.m_rareNonInheritedData
365 && m_rareInheritedData == other.m_rareInheritedData
366 && m_inheritedData == other.m_inheritedData
367 && m_svgStyle == other.m_svgStyle;
368}
369
370bool RenderStyle::hasUniquePseudoStyle() const
371{
372 if (!m_cachedPseudoStyles || styleType() != PseudoId::None)
373 return false;
374
375 for (auto& pseudoStyle : *m_cachedPseudoStyles) {
376 if (pseudoStyle->unique())
377 return true;
378 }
379
380 return false;
381}
382
383RenderStyle* RenderStyle::getCachedPseudoStyle(PseudoId pid) const
384{
385 if (!m_cachedPseudoStyles || !m_cachedPseudoStyles->size())
386 return nullptr;
387
388 if (styleType() != PseudoId::None)
389 return nullptr;
390
391 for (auto& pseudoStyle : *m_cachedPseudoStyles) {
392 if (pseudoStyle->styleType() == pid)
393 return pseudoStyle.get();
394 }
395
396 return nullptr;
397}
398
399RenderStyle* RenderStyle::addCachedPseudoStyle(std::unique_ptr<RenderStyle> pseudo)
400{
401 if (!pseudo)
402 return nullptr;
403
404 ASSERT(pseudo->styleType() > PseudoId::None);
405
406 RenderStyle* result = pseudo.get();
407
408 if (!m_cachedPseudoStyles)
409 m_cachedPseudoStyles = std::make_unique<PseudoStyleCache>();
410
411 m_cachedPseudoStyles->append(WTFMove(pseudo));
412
413 return result;
414}
415
416void RenderStyle::removeCachedPseudoStyle(PseudoId pid)
417{
418 if (!m_cachedPseudoStyles)
419 return;
420 for (size_t i = 0; i < m_cachedPseudoStyles->size(); ++i) {
421 RenderStyle* pseudoStyle = m_cachedPseudoStyles->at(i).get();
422 if (pseudoStyle->styleType() == pid) {
423 m_cachedPseudoStyles->remove(i);
424 return;
425 }
426 }
427}
428
429bool RenderStyle::inheritedNotEqual(const RenderStyle* other) const
430{
431 return m_inheritedFlags != other->m_inheritedFlags
432 || m_inheritedData != other->m_inheritedData
433 || m_svgStyle->inheritedNotEqual(other->m_svgStyle)
434 || m_rareInheritedData != other->m_rareInheritedData;
435}
436
437#if ENABLE(TEXT_AUTOSIZING)
438
439static inline unsigned computeFontHash(const FontCascade& font)
440{
441 IntegerHasher hasher;
442 hasher.add(ASCIICaseInsensitiveHash::hash(font.fontDescription().firstFamily()));
443 hasher.add(font.fontDescription().specifiedSize());
444 return hasher.hash();
445}
446
447unsigned RenderStyle::hashForTextAutosizing() const
448{
449 // FIXME: Not a very smart hash. Could be improved upon. See <https://bugs.webkit.org/show_bug.cgi?id=121131>.
450 unsigned hash = m_rareNonInheritedData->appearance;
451 hash ^= m_rareNonInheritedData->marginBeforeCollapse;
452 hash ^= m_rareNonInheritedData->marginAfterCollapse;
453 hash ^= m_rareNonInheritedData->lineClamp.value();
454 hash ^= m_rareInheritedData->overflowWrap;
455 hash ^= m_rareInheritedData->nbspMode;
456 hash ^= m_rareInheritedData->lineBreak;
457 hash ^= WTF::FloatHash<float>::hash(m_inheritedData->specifiedLineHeight.value());
458 hash ^= computeFontHash(m_inheritedData->fontCascade);
459 hash ^= WTF::FloatHash<float>::hash(m_inheritedData->horizontalBorderSpacing);
460 hash ^= WTF::FloatHash<float>::hash(m_inheritedData->verticalBorderSpacing);
461 hash ^= m_inheritedFlags.boxDirection;
462 hash ^= m_inheritedFlags.rtlOrdering;
463 hash ^= m_nonInheritedFlags.position;
464 hash ^= m_nonInheritedFlags.floating;
465 hash ^= m_rareNonInheritedData->textOverflow;
466 hash ^= m_rareInheritedData->textSecurity;
467 return hash;
468}
469
470bool RenderStyle::equalForTextAutosizing(const RenderStyle& other) const
471{
472 return m_rareNonInheritedData->appearance == other.m_rareNonInheritedData->appearance
473 && m_rareNonInheritedData->marginBeforeCollapse == other.m_rareNonInheritedData->marginBeforeCollapse
474 && m_rareNonInheritedData->marginAfterCollapse == other.m_rareNonInheritedData->marginAfterCollapse
475 && m_rareNonInheritedData->lineClamp == other.m_rareNonInheritedData->lineClamp
476 && m_rareInheritedData->textSizeAdjust == other.m_rareInheritedData->textSizeAdjust
477 && m_rareInheritedData->overflowWrap == other.m_rareInheritedData->overflowWrap
478 && m_rareInheritedData->nbspMode == other.m_rareInheritedData->nbspMode
479 && m_rareInheritedData->lineBreak == other.m_rareInheritedData->lineBreak
480 && m_rareInheritedData->textSecurity == other.m_rareInheritedData->textSecurity
481 && m_inheritedData->specifiedLineHeight == other.m_inheritedData->specifiedLineHeight
482 && m_inheritedData->fontCascade.equalForTextAutoSizing(other.m_inheritedData->fontCascade)
483 && m_inheritedData->horizontalBorderSpacing == other.m_inheritedData->horizontalBorderSpacing
484 && m_inheritedData->verticalBorderSpacing == other.m_inheritedData->verticalBorderSpacing
485 && m_inheritedFlags.boxDirection == other.m_inheritedFlags.boxDirection
486 && m_inheritedFlags.rtlOrdering == other.m_inheritedFlags.rtlOrdering
487 && m_nonInheritedFlags.position == other.m_nonInheritedFlags.position
488 && m_nonInheritedFlags.floating == other.m_nonInheritedFlags.floating
489 && m_rareNonInheritedData->textOverflow == other.m_rareNonInheritedData->textOverflow;
490}
491
492#endif // ENABLE(TEXT_AUTOSIZING)
493
494bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
495{
496 // This is a fast check that only looks if the data structures are shared.
497 return m_inheritedFlags == other->m_inheritedFlags
498 && m_inheritedData.ptr() == other->m_inheritedData.ptr()
499 && m_svgStyle.ptr() == other->m_svgStyle.ptr()
500 && m_rareInheritedData.ptr() == other->m_rareInheritedData.ptr();
501}
502
503static bool positionChangeIsMovementOnly(const LengthBox& a, const LengthBox& b, const Length& width)
504{
505 // If any unit types are different, then we can't guarantee
506 // that this was just a movement.
507 if (a.left().type() != b.left().type()
508 || a.right().type() != b.right().type()
509 || a.top().type() != b.top().type()
510 || a.bottom().type() != b.bottom().type())
511 return false;
512
513 // Only one unit can be non-auto in the horizontal direction and
514 // in the vertical direction. Otherwise the adjustment of values
515 // is changing the size of the box.
516 if (!a.left().isIntrinsicOrAuto() && !a.right().isIntrinsicOrAuto())
517 return false;
518 if (!a.top().isIntrinsicOrAuto() && !a.bottom().isIntrinsicOrAuto())
519 return false;
520 // If our width is auto and left or right is specified then this
521 // is not just a movement - we need to resize to our container.
522 if ((!a.left().isIntrinsicOrAuto() || !a.right().isIntrinsicOrAuto()) && width.isIntrinsicOrAuto())
523 return false;
524
525 // One of the units is fixed or percent in both directions and stayed
526 // that way in the new style. Therefore all we are doing is moving.
527 return true;
528}
529
530inline bool RenderStyle::changeAffectsVisualOverflow(const RenderStyle& other) const
531{
532 if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()
533 && !arePointingToEqualData(m_rareNonInheritedData->boxShadow, other.m_rareNonInheritedData->boxShadow))
534 return true;
535
536 if (m_rareInheritedData.ptr() != other.m_rareInheritedData.ptr()
537 && !arePointingToEqualData(m_rareInheritedData->textShadow, other.m_rareInheritedData->textShadow))
538 return true;
539
540 if (m_inheritedFlags.textDecorations != other.m_inheritedFlags.textDecorations
541 || m_rareNonInheritedData->textDecorationStyle != other.m_rareNonInheritedData->textDecorationStyle
542 || m_rareInheritedData->textDecorationThickness != other.m_rareInheritedData->textDecorationThickness
543 || m_rareInheritedData->textUnderlineOffset != other.m_rareInheritedData->textUnderlineOffset
544 || m_rareInheritedData->textUnderlinePosition != other.m_rareInheritedData->textUnderlinePosition) {
545 // Underlines are always drawn outside of their textbox bounds when text-underline-position: under;
546 // is specified. We can take an early out here.
547 if (textUnderlinePosition() == TextUnderlinePosition::Under || other.textUnderlinePosition() == TextUnderlinePosition::Under)
548 return true;
549 return visualOverflowForDecorations(*this, nullptr) != visualOverflowForDecorations(other, nullptr);
550 }
551
552 if (hasOutlineInVisualOverflow() != other.hasOutlineInVisualOverflow())
553 return true;
554 return false;
555}
556
557static bool rareNonInheritedDataChangeRequiresLayout(const StyleRareNonInheritedData& first, const StyleRareNonInheritedData& second, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties)
558{
559 ASSERT(&first != &second);
560
561 if (first.appearance != second.appearance
562 || first.marginBeforeCollapse != second.marginBeforeCollapse
563 || first.marginAfterCollapse != second.marginAfterCollapse
564 || first.lineClamp != second.lineClamp
565 || first.initialLetter != second.initialLetter
566 || first.textOverflow != second.textOverflow)
567 return true;
568
569 if (first.shapeMargin != second.shapeMargin)
570 return true;
571
572 if (first.deprecatedFlexibleBox != second.deprecatedFlexibleBox)
573 return true;
574
575 if (first.flexibleBox != second.flexibleBox)
576 return true;
577
578 if (first.order != second.order
579 || first.alignContent != second.alignContent
580 || first.alignItems != second.alignItems
581 || first.alignSelf != second.alignSelf
582 || first.justifyContent != second.justifyContent
583 || first.justifyItems != second.justifyItems
584 || first.justifySelf != second.justifySelf)
585 return true;
586
587 if (!arePointingToEqualData(first.boxReflect, second.boxReflect))
588 return true;
589
590 if (first.multiCol != second.multiCol)
591 return true;
592
593 if (first.transform.ptr() != second.transform.ptr()) {
594 if (first.transform->hasTransform() != second.transform->hasTransform())
595 return true;
596 if (*first.transform != *second.transform) {
597 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Transform);
598 // Don't return; keep looking for another change
599 }
600 }
601
602 if (first.grid != second.grid
603 || first.gridItem != second.gridItem)
604 return true;
605
606#if ENABLE(DASHBOARD_SUPPORT)
607 // If regions change, trigger a relayout to re-calc regions.
608 if (first.dashboardRegions != second.dashboardRegions)
609 return true;
610#endif
611
612 if (!arePointingToEqualData(first.willChange, second.willChange)) {
613 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::WillChange);
614 // Don't return; keep looking for another change
615 }
616
617 if (first.textCombine != second.textCombine)
618 return true;
619
620 if (first.breakBefore != second.breakBefore
621 || first.breakAfter != second.breakAfter
622 || first.breakInside != second.breakInside)
623 return true;
624
625 if (first.hasOpacity() != second.hasOpacity()) {
626 // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
627 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
628 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
629 // In addition we need to solve the floating object issue when layers come and go. Right now
630 // a full layout is necessary to keep floating object lists sane.
631 return true;
632 }
633
634#if ENABLE(CSS_COMPOSITING)
635 if (first.isolation != second.isolation) {
636 // Ideally this would trigger a cheaper layout that just updates layer z-order trees (webit.org/b/190088).
637 return true;
638 }
639#endif
640
641 if (first.hasFilters() != second.hasFilters())
642 return true;
643
644#if ENABLE(FILTERS_LEVEL_2)
645 if (first.hasBackdropFilters() != second.hasBackdropFilters())
646 return true;
647#endif
648
649 return false;
650}
651
652static bool rareInheritedDataChangeRequiresLayout(const StyleRareInheritedData& first, const StyleRareInheritedData& second)
653{
654 ASSERT(&first != &second);
655
656 if (first.indent != second.indent
657#if ENABLE(CSS3_TEXT)
658 || first.textAlignLast != second.textAlignLast
659 || first.textJustify != second.textJustify
660 || first.textIndentLine != second.textIndentLine
661#endif
662 || first.effectiveZoom != second.effectiveZoom
663 || first.textZoom != second.textZoom
664#if ENABLE(TEXT_AUTOSIZING)
665 || first.textSizeAdjust != second.textSizeAdjust
666#endif
667 || first.wordBreak != second.wordBreak
668 || first.overflowWrap != second.overflowWrap
669 || first.nbspMode != second.nbspMode
670 || first.lineBreak != second.lineBreak
671 || first.textSecurity != second.textSecurity
672 || first.hyphens != second.hyphens
673 || first.hyphenationLimitBefore != second.hyphenationLimitBefore
674 || first.hyphenationLimitAfter != second.hyphenationLimitAfter
675 || first.hyphenationString != second.hyphenationString
676 || first.rubyPosition != second.rubyPosition
677 || first.textEmphasisMark != second.textEmphasisMark
678 || first.textEmphasisPosition != second.textEmphasisPosition
679 || first.textEmphasisCustomMark != second.textEmphasisCustomMark
680 || first.textOrientation != second.textOrientation
681 || first.tabSize != second.tabSize
682 || first.lineBoxContain != second.lineBoxContain
683 || first.lineGrid != second.lineGrid
684#if ENABLE(CSS_IMAGE_ORIENTATION)
685 || first.imageOrientation != second.imageOrientation
686#endif
687#if ENABLE(CSS_IMAGE_RESOLUTION)
688 || first.imageResolutionSource != second.imageResolutionSource
689 || first.imageResolutionSnap != second.imageResolutionSnap
690 || first.imageResolution != second.imageResolution
691#endif
692 || first.lineSnap != second.lineSnap
693 || first.lineAlign != second.lineAlign
694 || first.hangingPunctuation != second.hangingPunctuation
695#if ENABLE(OVERFLOW_SCROLLING_TOUCH)
696 || first.useTouchOverflowScrolling != second.useTouchOverflowScrolling
697#endif
698 || first.listStyleImage != second.listStyleImage) // FIXME: needs arePointingToEqualData()?
699 return true;
700
701 if (first.textStrokeWidth != second.textStrokeWidth)
702 return true;
703
704 // These properties affect the cached stroke bounding box rects.
705 if (first.capStyle != second.capStyle
706 || first.joinStyle != second.joinStyle
707 || first.strokeWidth != second.strokeWidth
708 || first.miterLimit != second.miterLimit)
709 return true;
710
711 if (!arePointingToEqualData(first.quotes, second.quotes))
712 return true;
713
714 return false;
715}
716
717bool RenderStyle::changeRequiresLayout(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const
718{
719 if (m_boxData.ptr() != other.m_boxData.ptr()) {
720 if (m_boxData->width() != other.m_boxData->width()
721 || m_boxData->minWidth() != other.m_boxData->minWidth()
722 || m_boxData->maxWidth() != other.m_boxData->maxWidth()
723 || m_boxData->height() != other.m_boxData->height()
724 || m_boxData->minHeight() != other.m_boxData->minHeight()
725 || m_boxData->maxHeight() != other.m_boxData->maxHeight())
726 return true;
727
728 if (m_boxData->verticalAlign() != other.m_boxData->verticalAlign())
729 return true;
730
731 if (m_boxData->boxSizing() != other.m_boxData->boxSizing())
732 return true;
733 }
734
735 if (m_surroundData->margin != other.m_surroundData->margin)
736 return true;
737
738 if (m_surroundData->padding != other.m_surroundData->padding)
739 return true;
740
741 // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
742 if (changeAffectsVisualOverflow(other))
743 return true;
744
745 if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()
746 && rareNonInheritedDataChangeRequiresLayout(*m_rareNonInheritedData, *other.m_rareNonInheritedData, changedContextSensitiveProperties))
747 return true;
748
749 if (m_rareInheritedData.ptr() != other.m_rareInheritedData.ptr()
750 && rareInheritedDataChangeRequiresLayout(*m_rareInheritedData, *other.m_rareInheritedData))
751 return true;
752
753 if (m_inheritedData.ptr() != other.m_inheritedData.ptr()) {
754 if (m_inheritedData->lineHeight != other.m_inheritedData->lineHeight
755#if ENABLE(TEXT_AUTOSIZING)
756 || m_inheritedData->specifiedLineHeight != other.m_inheritedData->specifiedLineHeight
757#endif
758 || m_inheritedData->fontCascade != other.m_inheritedData->fontCascade
759 || m_inheritedData->horizontalBorderSpacing != other.m_inheritedData->horizontalBorderSpacing
760 || m_inheritedData->verticalBorderSpacing != other.m_inheritedData->verticalBorderSpacing)
761 return true;
762 }
763
764 if (m_inheritedFlags.boxDirection != other.m_inheritedFlags.boxDirection
765 || m_inheritedFlags.rtlOrdering != other.m_inheritedFlags.rtlOrdering
766 || m_nonInheritedFlags.position != other.m_nonInheritedFlags.position
767 || m_nonInheritedFlags.floating != other.m_nonInheritedFlags.floating
768 || m_nonInheritedFlags.originalDisplay != other.m_nonInheritedFlags.originalDisplay
769 || m_nonInheritedFlags.verticalAlign != other.m_nonInheritedFlags.verticalAlign)
770 return true;
771
772 if (static_cast<DisplayType>(m_nonInheritedFlags.effectiveDisplay) >= DisplayType::Table) {
773 if (m_inheritedFlags.borderCollapse != other.m_inheritedFlags.borderCollapse
774 || m_inheritedFlags.emptyCells != other.m_inheritedFlags.emptyCells
775 || m_inheritedFlags.captionSide != other.m_inheritedFlags.captionSide
776 || m_nonInheritedFlags.tableLayout != other.m_nonInheritedFlags.tableLayout)
777 return true;
778
779 // In the collapsing border model, 'hidden' suppresses other borders, while 'none'
780 // does not, so these style differences can be width differences.
781 if (m_inheritedFlags.borderCollapse
782 && ((borderTopStyle() == BorderStyle::Hidden && other.borderTopStyle() == BorderStyle::None)
783 || (borderTopStyle() == BorderStyle::None && other.borderTopStyle() == BorderStyle::Hidden)
784 || (borderBottomStyle() == BorderStyle::Hidden && other.borderBottomStyle() == BorderStyle::None)
785 || (borderBottomStyle() == BorderStyle::None && other.borderBottomStyle() == BorderStyle::Hidden)
786 || (borderLeftStyle() == BorderStyle::Hidden && other.borderLeftStyle() == BorderStyle::None)
787 || (borderLeftStyle() == BorderStyle::None && other.borderLeftStyle() == BorderStyle::Hidden)
788 || (borderRightStyle() == BorderStyle::Hidden && other.borderRightStyle() == BorderStyle::None)
789 || (borderRightStyle() == BorderStyle::None && other.borderRightStyle() == BorderStyle::Hidden)))
790 return true;
791 }
792
793 if (static_cast<DisplayType>(m_nonInheritedFlags.effectiveDisplay) == DisplayType::ListItem) {
794 if (m_inheritedFlags.listStyleType != other.m_inheritedFlags.listStyleType
795 || m_inheritedFlags.listStylePosition != other.m_inheritedFlags.listStylePosition)
796 return true;
797 }
798
799 if (m_inheritedFlags.textAlign != other.m_inheritedFlags.textAlign
800 || m_inheritedFlags.textTransform != other.m_inheritedFlags.textTransform
801 || m_inheritedFlags.direction != other.m_inheritedFlags.direction
802 || m_inheritedFlags.whiteSpace != other.m_inheritedFlags.whiteSpace
803 || m_nonInheritedFlags.clear != other.m_nonInheritedFlags.clear
804 || m_nonInheritedFlags.unicodeBidi != other.m_nonInheritedFlags.unicodeBidi)
805 return true;
806
807 // Check block flow direction.
808 if (m_inheritedFlags.writingMode != other.m_inheritedFlags.writingMode)
809 return true;
810
811 // Overflow returns a layout hint.
812 if (m_nonInheritedFlags.overflowX != other.m_nonInheritedFlags.overflowX
813 || m_nonInheritedFlags.overflowY != other.m_nonInheritedFlags.overflowY)
814 return true;
815
816 // If our border widths change, then we need to layout. Other changes to borders
817 // only necessitate a repaint.
818 if (borderLeftWidth() != other.borderLeftWidth()
819 || borderTopWidth() != other.borderTopWidth()
820 || borderBottomWidth() != other.borderBottomWidth()
821 || borderRightWidth() != other.borderRightWidth())
822 return true;
823
824 // If the counter directives change, trigger a relayout to re-calculate counter values and rebuild the counter node tree.
825 if (!arePointingToEqualData(m_rareNonInheritedData->counterDirectives, other.m_rareNonInheritedData->counterDirectives))
826 return true;
827
828 if ((visibility() == Visibility::Collapse) != (other.visibility() == Visibility::Collapse))
829 return true;
830
831 if (position() != PositionType::Static) {
832 if (m_surroundData->offset != other.m_surroundData->offset) {
833 // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
834 // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
835 // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
836 if (position() != PositionType::Absolute)
837 return true;
838
839 // Optimize for the case where a positioned layer is moving but not changing size.
840 if (!positionChangeIsMovementOnly(m_surroundData->offset, other.m_surroundData->offset, m_boxData->width()))
841 return true;
842 }
843 }
844
845 bool hasFirstLineStyle = hasPseudoStyle(PseudoId::FirstLine);
846 if (hasFirstLineStyle != other.hasPseudoStyle(PseudoId::FirstLine))
847 return true;
848 if (hasFirstLineStyle) {
849 auto* firstLineStyle = getCachedPseudoStyle(PseudoId::FirstLine);
850 if (!firstLineStyle)
851 return true;
852 auto* otherFirstLineStyle = other.getCachedPseudoStyle(PseudoId::FirstLine);
853 if (!otherFirstLineStyle)
854 return true;
855 // FIXME: Not all first line style changes actually need layout.
856 if (*firstLineStyle != *otherFirstLineStyle)
857 return true;
858 }
859
860 return false;
861}
862
863bool RenderStyle::changeRequiresPositionedLayoutOnly(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>&) const
864{
865 if (position() == PositionType::Static)
866 return false;
867
868 if (m_surroundData->offset != other.m_surroundData->offset) {
869 // Optimize for the case where a positioned layer is moving but not changing size.
870 if (position() == PositionType::Absolute && positionChangeIsMovementOnly(m_surroundData->offset, other.m_surroundData->offset, m_boxData->width()))
871 return true;
872 }
873
874 return false;
875}
876
877static bool rareNonInheritedDataChangeRequiresLayerRepaint(const StyleRareNonInheritedData& first, const StyleRareNonInheritedData& second, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties)
878{
879#if ENABLE(CSS_COMPOSITING)
880 if (first.effectiveBlendMode != second.effectiveBlendMode)
881 return true;
882#endif
883
884 if (first.opacity != second.opacity) {
885 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Opacity);
886 // Don't return true; keep looking for another change.
887 }
888
889 if (first.filter != second.filter) {
890 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Filter);
891 // Don't return true; keep looking for another change.
892 }
893
894#if ENABLE(FILTERS_LEVEL_2)
895 if (first.backdropFilter != second.backdropFilter) {
896 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Filter);
897 // Don't return true; keep looking for another change.
898 }
899#endif
900
901 if (first.mask != second.mask || first.maskBoxImage != second.maskBoxImage)
902 return true;
903
904 return false;
905}
906
907bool RenderStyle::changeRequiresLayerRepaint(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const
908{
909 // StyleResolver has ensured that zIndex is non-auto only if it's applicable.
910 if (m_boxData->zIndex() != other.m_boxData->zIndex() || m_boxData->hasAutoZIndex() != other.m_boxData->hasAutoZIndex())
911 return true;
912
913 if (position() != PositionType::Static) {
914 if (m_visualData->clip != other.m_visualData->clip || m_visualData->hasClip != other.m_visualData->hasClip) {
915 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::ClipRect);
916 return true;
917 }
918 }
919
920 if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()
921 && rareNonInheritedDataChangeRequiresLayerRepaint(*m_rareNonInheritedData, *other.m_rareNonInheritedData, changedContextSensitiveProperties))
922 return true;
923
924 return false;
925}
926
927static bool requiresPainting(const RenderStyle& style)
928{
929 if (style.visibility() == Visibility::Hidden)
930 return false;
931 if (!style.opacity())
932 return false;
933 return true;
934}
935
936static bool rareNonInheritedDataChangeRequiresRepaint(const StyleRareNonInheritedData& first, const StyleRareNonInheritedData& second, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties)
937{
938 if (first.userDrag != second.userDrag
939 || first.borderFit != second.borderFit
940 || first.objectFit != second.objectFit
941 || first.objectPosition != second.objectPosition)
942 return true;
943
944 if (first.isNotFinal != second.isNotFinal)
945 return true;
946
947 if (first.shapeOutside != second.shapeOutside)
948 return true;
949
950 // FIXME: this should probably be moved to changeRequiresLayerRepaint().
951 if (first.clipPath != second.clipPath) {
952 changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::ClipPath);
953 // Don't return true; keep looking for another change.
954 }
955
956 return false;
957}
958
959static bool rareInheritedDataChangeRequiresRepaint(const StyleRareInheritedData& first, const StyleRareInheritedData& second)
960{
961 return first.userModify != second.userModify
962 || first.userSelect != second.userSelect
963 || first.appleColorFilter != second.appleColorFilter
964 || first.imageRendering != second.imageRendering
965#if ENABLE(DARK_MODE_CSS)
966 || first.colorScheme != second.colorScheme
967#endif
968 ;
969}
970
971#if ENABLE(CSS_PAINTING_API)
972void RenderStyle::addCustomPaintWatchProperty(const String& name)
973{
974 auto& data = m_rareNonInheritedData.access();
975 if (!data.customPaintWatchedProperties)
976 data.customPaintWatchedProperties = std::make_unique<HashSet<String>>();
977 data.customPaintWatchedProperties->add(name);
978}
979
980inline static bool changedCustomPaintWatchedProperty(const RenderStyle& a, const StyleRareNonInheritedData& aData, const RenderStyle& b, const StyleRareNonInheritedData& bData)
981{
982 auto* propertiesA = aData.customPaintWatchedProperties.get();
983 auto* propertiesB = bData.customPaintWatchedProperties.get();
984
985 if (UNLIKELY(propertiesA || propertiesB)) {
986 // FIXME: We should not need to use ComputedStyleExtractor here.
987 ComputedStyleExtractor extractor((Element*) nullptr);
988
989 for (auto* watchPropertiesMap : { propertiesA, propertiesB }) {
990 if (!watchPropertiesMap)
991 continue;
992
993 for (auto& name : *watchPropertiesMap) {
994 RefPtr<CSSValue> valueA;
995 RefPtr<CSSValue> valueB;
996 if (isCustomPropertyName(name)) {
997 if (a.getCustomProperty(name))
998 valueA = CSSCustomPropertyValue::create(*a.getCustomProperty(name));
999 if (b.getCustomProperty(name))
1000 valueB = CSSCustomPropertyValue::create(*b.getCustomProperty(name));
1001 } else {
1002 CSSPropertyID propertyID = cssPropertyID(name);
1003 if (!propertyID)
1004 continue;
1005 valueA = extractor.valueForPropertyinStyle(a, propertyID);
1006 valueB = extractor.valueForPropertyinStyle(b, propertyID);
1007 }
1008
1009 if ((valueA && !valueB) || (!valueA && valueB))
1010 return true;
1011
1012 if (!valueA)
1013 continue;
1014
1015 if (!(*valueA == *valueB))
1016 return true;
1017 }
1018 }
1019 }
1020
1021 return false;
1022}
1023#endif
1024
1025bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const
1026{
1027 if (!requiresPainting(*this) && !requiresPainting(other))
1028 return false;
1029
1030 if (m_inheritedFlags.visibility != other.m_inheritedFlags.visibility
1031 || m_inheritedFlags.printColorAdjust != other.m_inheritedFlags.printColorAdjust
1032 || m_inheritedFlags.insideLink != other.m_inheritedFlags.insideLink
1033 || m_inheritedFlags.insideDefaultButton != other.m_inheritedFlags.insideDefaultButton
1034 || m_surroundData->border != other.m_surroundData->border
1035 || !m_backgroundData->isEquivalentForPainting(*other.m_backgroundData))
1036 return true;
1037
1038 if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()
1039 && rareNonInheritedDataChangeRequiresRepaint(*m_rareNonInheritedData, *other.m_rareNonInheritedData, changedContextSensitiveProperties))
1040 return true;
1041
1042 if (m_rareInheritedData.ptr() != other.m_rareInheritedData.ptr()
1043 && rareInheritedDataChangeRequiresRepaint(*m_rareInheritedData, *other.m_rareInheritedData))
1044 return true;
1045
1046#if ENABLE(CSS_PAINTING_API)
1047 if (changedCustomPaintWatchedProperty(*this, *m_rareNonInheritedData, other, *other.m_rareNonInheritedData))
1048 return true;
1049#endif
1050
1051 return false;
1052}
1053
1054bool RenderStyle::changeRequiresRepaintIfTextOrBorderOrOutline(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>&) const
1055{
1056 if (m_inheritedData->color != other.m_inheritedData->color
1057 || m_inheritedFlags.textDecorations != other.m_inheritedFlags.textDecorations
1058 || m_visualData->textDecoration != other.m_visualData->textDecoration
1059 || m_rareNonInheritedData->textDecorationStyle != other.m_rareNonInheritedData->textDecorationStyle
1060 || m_rareNonInheritedData->textDecorationColor != other.m_rareNonInheritedData->textDecorationColor
1061 || m_rareInheritedData->textDecorationSkip != other.m_rareInheritedData->textDecorationSkip
1062 || m_rareInheritedData->textFillColor != other.m_rareInheritedData->textFillColor
1063 || m_rareInheritedData->textStrokeColor != other.m_rareInheritedData->textStrokeColor
1064 || m_rareInheritedData->textEmphasisColor != other.m_rareInheritedData->textEmphasisColor
1065 || m_rareInheritedData->textEmphasisFill != other.m_rareInheritedData->textEmphasisFill
1066 || m_rareInheritedData->strokeColor != other.m_rareInheritedData->strokeColor
1067 || m_rareInheritedData->caretColor != other.m_rareInheritedData->caretColor)
1068 return true;
1069
1070 return false;
1071}
1072
1073bool RenderStyle::changeRequiresRecompositeLayer(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>&) const
1074{
1075 if (m_rareNonInheritedData.ptr() != other.m_rareNonInheritedData.ptr()) {
1076 if (m_rareNonInheritedData->transformStyle3D != other.m_rareNonInheritedData->transformStyle3D
1077 || m_rareNonInheritedData->backfaceVisibility != other.m_rareNonInheritedData->backfaceVisibility
1078 || m_rareNonInheritedData->perspective != other.m_rareNonInheritedData->perspective
1079 || m_rareNonInheritedData->perspectiveOriginX != other.m_rareNonInheritedData->perspectiveOriginX
1080 || m_rareNonInheritedData->perspectiveOriginY != other.m_rareNonInheritedData->perspectiveOriginY)
1081 return true;
1082 }
1083
1084 return false;
1085}
1086
1087StyleDifference RenderStyle::diff(const RenderStyle& other, OptionSet<StyleDifferenceContextSensitiveProperty>& changedContextSensitiveProperties) const
1088{
1089 changedContextSensitiveProperties = OptionSet<StyleDifferenceContextSensitiveProperty>();
1090
1091 StyleDifference svgChange = StyleDifference::Equal;
1092 if (m_svgStyle != other.m_svgStyle) {
1093 svgChange = m_svgStyle->diff(other.m_svgStyle.get());
1094 if (svgChange == StyleDifference::Layout)
1095 return svgChange;
1096 }
1097
1098 if (changeRequiresLayout(other, changedContextSensitiveProperties))
1099 return StyleDifference::Layout;
1100
1101 // SVGRenderStyle::diff() might have returned StyleDifference::Repaint, eg. if fill changes.
1102 // If eg. the font-size changed at the same time, we're not allowed to return StyleDifference::Repaint,
1103 // but have to return StyleDifference::Layout, that's why this if branch comes after all branches
1104 // that are relevant for SVG and might return StyleDifference::Layout.
1105 if (svgChange != StyleDifference::Equal)
1106 return svgChange;
1107
1108 if (changeRequiresPositionedLayoutOnly(other, changedContextSensitiveProperties))
1109 return StyleDifference::LayoutPositionedMovementOnly;
1110
1111 if (changeRequiresLayerRepaint(other, changedContextSensitiveProperties))
1112 return StyleDifference::RepaintLayer;
1113
1114 if (changeRequiresRepaint(other, changedContextSensitiveProperties))
1115 return StyleDifference::Repaint;
1116
1117 if (changeRequiresRecompositeLayer(other, changedContextSensitiveProperties))
1118 return StyleDifference::RecompositeLayer;
1119
1120 if (changeRequiresRepaintIfTextOrBorderOrOutline(other, changedContextSensitiveProperties))
1121 return StyleDifference::RepaintIfTextOrBorderOrOutline;
1122
1123 // Cursors are not checked, since they will be set appropriately in response to mouse events,
1124 // so they don't need to cause any repaint or layout.
1125
1126 // 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
1127 // the resulting transition properly.
1128 return StyleDifference::Equal;
1129}
1130
1131bool RenderStyle::diffRequiresLayerRepaint(const RenderStyle& style, bool isComposited) const
1132{
1133 OptionSet<StyleDifferenceContextSensitiveProperty> changedContextSensitiveProperties;
1134
1135 if (changeRequiresRepaint(style, changedContextSensitiveProperties))
1136 return true;
1137
1138 if (isComposited && changeRequiresLayerRepaint(style, changedContextSensitiveProperties))
1139 return changedContextSensitiveProperties.contains(StyleDifferenceContextSensitiveProperty::ClipRect);
1140
1141 return false;
1142}
1143
1144void RenderStyle::setClip(Length&& top, Length&& right, Length&& bottom, Length&& left)
1145{
1146 auto& data = m_visualData.access();
1147 data.clip.top() = WTFMove(top);
1148 data.clip.right() = WTFMove(right);
1149 data.clip.bottom() = WTFMove(bottom);
1150 data.clip.left() = WTFMove(left);
1151}
1152
1153void RenderStyle::addCursor(RefPtr<StyleImage>&& image, const IntPoint& hotSpot)
1154{
1155 auto& cursorData = m_rareInheritedData.access().cursorData;
1156 if (!cursorData)
1157 cursorData = CursorList::create();
1158 cursorData->append(CursorData(WTFMove(image), hotSpot));
1159}
1160
1161void RenderStyle::setCursorList(RefPtr<CursorList>&& list)
1162{
1163 m_rareInheritedData.access().cursorData = WTFMove(list);
1164}
1165
1166void RenderStyle::setQuotes(RefPtr<QuotesData>&& q)
1167{
1168 if (m_rareInheritedData->quotes == q || (m_rareInheritedData->quotes && q && *m_rareInheritedData->quotes == *q))
1169 return;
1170
1171 m_rareInheritedData.access().quotes = WTFMove(q);
1172}
1173
1174void RenderStyle::setWillChange(RefPtr<WillChangeData>&& willChangeData)
1175{
1176 if (arePointingToEqualData(m_rareNonInheritedData->willChange.get(), willChangeData.get()))
1177 return;
1178
1179 m_rareNonInheritedData.access().willChange = WTFMove(willChangeData);
1180}
1181
1182void RenderStyle::clearCursorList()
1183{
1184 if (m_rareInheritedData->cursorData)
1185 m_rareInheritedData.access().cursorData = nullptr;
1186}
1187
1188void RenderStyle::clearContent()
1189{
1190 if (m_rareNonInheritedData->content)
1191 m_rareNonInheritedData.access().content = nullptr;
1192}
1193
1194static inline ContentData& lastContent(ContentData& firstContent)
1195{
1196 auto* lastContent = &firstContent;
1197 for (auto* content = &firstContent; content; content = content->next())
1198 lastContent = content;
1199 return *lastContent;
1200}
1201
1202void RenderStyle::setContent(std::unique_ptr<ContentData> contentData, bool add)
1203{
1204 auto& data = m_rareNonInheritedData.access();
1205 if (add && data.content)
1206 lastContent(*data.content).setNext(WTFMove(contentData));
1207 else {
1208 data.content = WTFMove(contentData);
1209 auto& altText = data.altText;
1210 if (!altText.isNull())
1211 data.content->setAltText(altText);
1212 }
1213}
1214
1215void RenderStyle::setContent(RefPtr<StyleImage>&& image, bool add)
1216{
1217 if (!image)
1218 return;
1219 setContent(std::make_unique<ImageContentData>(image.releaseNonNull()), add);
1220}
1221
1222void RenderStyle::setContent(const String& string, bool add)
1223{
1224 auto& data = m_rareNonInheritedData.access();
1225 if (add && data.content) {
1226 auto& last = lastContent(*data.content);
1227 if (!is<TextContentData>(last))
1228 last.setNext(std::make_unique<TextContentData>(string));
1229 else {
1230 auto& textContent = downcast<TextContentData>(last);
1231 textContent.setText(textContent.text() + string);
1232 }
1233 } else {
1234 data.content = std::make_unique<TextContentData>(string);
1235 auto& altText = data.altText;
1236 if (!altText.isNull())
1237 data.content->setAltText(altText);
1238 }
1239}
1240
1241void RenderStyle::setContent(std::unique_ptr<CounterContent> counter, bool add)
1242{
1243 if (!counter)
1244 return;
1245 setContent(std::make_unique<CounterContentData>(WTFMove(counter)), add);
1246}
1247
1248void RenderStyle::setContent(QuoteType quote, bool add)
1249{
1250 setContent(std::make_unique<QuoteContentData>(quote), add);
1251}
1252
1253void RenderStyle::setContentAltText(const String& string)
1254{
1255 auto& data = m_rareNonInheritedData.access();
1256 data.altText = string;
1257 if (data.content)
1258 data.content->setAltText(string);
1259}
1260
1261const String& RenderStyle::contentAltText() const
1262{
1263 return m_rareNonInheritedData->altText;
1264}
1265
1266void RenderStyle::setHasAttrContent()
1267{
1268 setUnique();
1269 SET_VAR(m_rareNonInheritedData, hasAttrContent, true);
1270}
1271
1272static inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation>>& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
1273{
1274 // The transform-origin property brackets the transform with translate operations.
1275 // When the only transform is a translation, the transform-origin is irrelevant.
1276
1277 if (applyOrigin != RenderStyle::IncludeTransformOrigin)
1278 return false;
1279
1280 for (auto& operation : transformOperations) {
1281 // FIXME: Use affectedByTransformOrigin().
1282 auto type = operation->type();
1283 if (type != TransformOperation::TRANSLATE
1284 && type != TransformOperation::TRANSLATE_3D
1285 && type != TransformOperation::TRANSLATE_X
1286 && type != TransformOperation::TRANSLATE_Y
1287 && type != TransformOperation::TRANSLATE_Z)
1288 return true;
1289 }
1290
1291 return false;
1292}
1293
1294void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const
1295{
1296 auto& operations = m_rareNonInheritedData->transform->operations.operations();
1297 bool applyTransformOrigin = requireTransformOrigin(operations, applyOrigin);
1298
1299 FloatPoint3D originTranslate;
1300 if (applyTransformOrigin) {
1301 originTranslate.setX(boundingBox.x() + floatValueForLength(transformOriginX(), boundingBox.width()));
1302 originTranslate.setY(boundingBox.y() + floatValueForLength(transformOriginY(), boundingBox.height()));
1303 originTranslate.setZ(transformOriginZ());
1304 transform.translate3d(originTranslate.x(), originTranslate.y(), originTranslate.z());
1305 }
1306
1307 for (auto& operation : operations)
1308 operation->apply(transform, boundingBox.size());
1309
1310 if (applyTransformOrigin)
1311 transform.translate3d(-originTranslate.x(), -originTranslate.y(), -originTranslate.z());
1312}
1313
1314void RenderStyle::setPageScaleTransform(float scale)
1315{
1316 if (scale == 1)
1317 return;
1318 TransformOperations transform;
1319 transform.operations().append(ScaleTransformOperation::create(scale, scale, ScaleTransformOperation::SCALE));
1320 setTransform(transform);
1321 setTransformOriginX(Length(0, Fixed));
1322 setTransformOriginY(Length(0, Fixed));
1323}
1324
1325void RenderStyle::setTextShadow(std::unique_ptr<ShadowData> shadowData, bool add)
1326{
1327 ASSERT(!shadowData || (!shadowData->spread() && shadowData->style() == Normal));
1328
1329 auto& rareData = m_rareInheritedData.access();
1330 if (!add) {
1331 rareData.textShadow = WTFMove(shadowData);
1332 return;
1333 }
1334
1335 shadowData->setNext(WTFMove(rareData.textShadow));
1336 rareData.textShadow = WTFMove(shadowData);
1337}
1338
1339void RenderStyle::setBoxShadow(std::unique_ptr<ShadowData> shadowData, bool add)
1340{
1341 auto& rareData = m_rareNonInheritedData.access();
1342 if (!add) {
1343 rareData.boxShadow = WTFMove(shadowData);
1344 return;
1345 }
1346
1347 shadowData->setNext(WTFMove(rareData.boxShadow));
1348 rareData.boxShadow = WTFMove(shadowData);
1349}
1350
1351static RoundedRect::Radii calcRadiiFor(const BorderData& border, const LayoutSize& size)
1352{
1353 return {
1354 sizeForLengthSize(border.topLeft(), size),
1355 sizeForLengthSize(border.topRight(), size),
1356 sizeForLengthSize(border.bottomLeft(), size),
1357 sizeForLengthSize(border.bottomRight(), size)
1358 };
1359}
1360
1361StyleImage* RenderStyle::listStyleImage() const
1362{
1363 return m_rareInheritedData->listStyleImage.get();
1364}
1365
1366void RenderStyle::setListStyleImage(RefPtr<StyleImage>&& v)
1367{
1368 if (m_rareInheritedData->listStyleImage != v)
1369 m_rareInheritedData.access().listStyleImage = WTFMove(v);
1370}
1371
1372const Color& RenderStyle::color() const
1373{
1374 return m_inheritedData->color;
1375}
1376
1377const Color& RenderStyle::visitedLinkColor() const
1378{
1379 return m_inheritedData->visitedLinkColor;
1380}
1381
1382void RenderStyle::setColor(const Color& v)
1383{
1384 SET_VAR(m_inheritedData, color, v);
1385}
1386
1387void RenderStyle::setVisitedLinkColor(const Color& v)
1388{
1389 SET_VAR(m_inheritedData, visitedLinkColor, v);
1390}
1391
1392float RenderStyle::horizontalBorderSpacing() const
1393{
1394 return m_inheritedData->horizontalBorderSpacing;
1395}
1396
1397float RenderStyle::verticalBorderSpacing() const
1398{
1399 return m_inheritedData->verticalBorderSpacing;
1400}
1401
1402void RenderStyle::setHorizontalBorderSpacing(float v)
1403{
1404 SET_VAR(m_inheritedData, horizontalBorderSpacing, v);
1405}
1406
1407void RenderStyle::setVerticalBorderSpacing(float v)
1408{
1409 SET_VAR(m_inheritedData, verticalBorderSpacing, v);
1410}
1411
1412RoundedRect RenderStyle::getRoundedBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
1413{
1414 RoundedRect roundedRect(borderRect);
1415 if (hasBorderRadius()) {
1416 RoundedRect::Radii radii = calcRadiiFor(m_surroundData->border, borderRect.size());
1417 radii.scale(calcBorderRadiiConstraintScaleFor(borderRect, radii));
1418 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
1419 }
1420 return roundedRect;
1421}
1422
1423RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
1424{
1425 bool horizontal = isHorizontalWritingMode();
1426 auto leftWidth = (!horizontal || includeLogicalLeftEdge) ? borderLeftWidth() : 0;
1427 auto rightWidth = (!horizontal || includeLogicalRightEdge) ? borderRightWidth() : 0;
1428 auto topWidth = (horizontal || includeLogicalLeftEdge) ? borderTopWidth() : 0;
1429 auto bottomWidth = (horizontal || includeLogicalRightEdge) ? borderBottomWidth() : 0;
1430 return getRoundedInnerBorderFor(borderRect, topWidth, bottomWidth, leftWidth, rightWidth, includeLogicalLeftEdge, includeLogicalRightEdge);
1431}
1432
1433RoundedRect RenderStyle::getRoundedInnerBorderFor(const LayoutRect& borderRect, LayoutUnit topWidth, LayoutUnit bottomWidth,
1434 LayoutUnit leftWidth, LayoutUnit rightWidth, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
1435{
1436 RoundedRect roundedRect { { borderRect.x() + leftWidth, borderRect.y() + topWidth,
1437 borderRect.width() - leftWidth - rightWidth, borderRect.height() - topWidth - bottomWidth } };
1438 if (hasBorderRadius()) {
1439 auto radii = getRoundedBorderFor(borderRect).radii();
1440 radii.shrink(topWidth, bottomWidth, leftWidth, rightWidth);
1441 roundedRect.includeLogicalEdges(radii, isHorizontalWritingMode(), includeLogicalLeftEdge, includeLogicalRightEdge);
1442 }
1443 return roundedRect;
1444}
1445
1446static bool allLayersAreFixed(const FillLayer& layers)
1447{
1448 for (auto* layer = &layers; layer; layer = layer->next()) {
1449 if (!(layer->image() && layer->attachment() == FillAttachment::FixedBackground))
1450 return false;
1451 }
1452 return true;
1453}
1454
1455bool RenderStyle::hasEntirelyFixedBackground() const
1456{
1457 return allLayersAreFixed(backgroundLayers());
1458}
1459
1460const CounterDirectiveMap* RenderStyle::counterDirectives() const
1461{
1462 return m_rareNonInheritedData->counterDirectives.get();
1463}
1464
1465CounterDirectiveMap& RenderStyle::accessCounterDirectives()
1466{
1467 auto& map = m_rareNonInheritedData.access().counterDirectives;
1468 if (!map)
1469 map = std::make_unique<CounterDirectiveMap>();
1470 return *map;
1471}
1472
1473const AtomicString& RenderStyle::hyphenString() const
1474{
1475 ASSERT(hyphens() != Hyphens::None);
1476
1477 auto& hyphenationString = m_rareInheritedData->hyphenationString;
1478 if (!hyphenationString.isNull())
1479 return hyphenationString;
1480
1481 // FIXME: This should depend on locale.
1482 static NeverDestroyed<AtomicString> hyphenMinusString(&hyphenMinus, 1);
1483 static NeverDestroyed<AtomicString> hyphenString(&hyphen, 1);
1484 return fontCascade().primaryFont().glyphForCharacter(hyphen) ? hyphenString : hyphenMinusString;
1485}
1486
1487const AtomicString& RenderStyle::textEmphasisMarkString() const
1488{
1489 switch (textEmphasisMark()) {
1490 case TextEmphasisMark::None:
1491 return nullAtom();
1492 case TextEmphasisMark::Custom:
1493 return textEmphasisCustomMark();
1494 case TextEmphasisMark::Dot: {
1495 static NeverDestroyed<AtomicString> filledDotString(&bullet, 1);
1496 static NeverDestroyed<AtomicString> openDotString(&whiteBullet, 1);
1497 return textEmphasisFill() == TextEmphasisFill::Filled ? filledDotString : openDotString;
1498 }
1499 case TextEmphasisMark::Circle: {
1500 static NeverDestroyed<AtomicString> filledCircleString(&blackCircle, 1);
1501 static NeverDestroyed<AtomicString> openCircleString(&whiteCircle, 1);
1502 return textEmphasisFill() == TextEmphasisFill::Filled ? filledCircleString : openCircleString;
1503 }
1504 case TextEmphasisMark::DoubleCircle: {
1505 static NeverDestroyed<AtomicString> filledDoubleCircleString(&fisheye, 1);
1506 static NeverDestroyed<AtomicString> openDoubleCircleString(&bullseye, 1);
1507 return textEmphasisFill() == TextEmphasisFill::Filled ? filledDoubleCircleString : openDoubleCircleString;
1508 }
1509 case TextEmphasisMark::Triangle: {
1510 static NeverDestroyed<AtomicString> filledTriangleString(&blackUpPointingTriangle, 1);
1511 static NeverDestroyed<AtomicString> openTriangleString(&whiteUpPointingTriangle, 1);
1512 return textEmphasisFill() == TextEmphasisFill::Filled ? filledTriangleString : openTriangleString;
1513 }
1514 case TextEmphasisMark::Sesame: {
1515 static NeverDestroyed<AtomicString> filledSesameString(&sesameDot, 1);
1516 static NeverDestroyed<AtomicString> openSesameString(&whiteSesameDot, 1);
1517 return textEmphasisFill() == TextEmphasisFill::Filled ? filledSesameString : openSesameString;
1518 }
1519 case TextEmphasisMark::Auto:
1520 ASSERT_NOT_REACHED();
1521 return nullAtom();
1522 }
1523
1524 ASSERT_NOT_REACHED();
1525 return nullAtom();
1526}
1527
1528#if ENABLE(DASHBOARD_SUPPORT)
1529
1530const Vector<StyleDashboardRegion>& RenderStyle::initialDashboardRegions()
1531{
1532 static NeverDestroyed<Vector<StyleDashboardRegion>> emptyList;
1533 return emptyList;
1534}
1535
1536const Vector<StyleDashboardRegion>& RenderStyle::noneDashboardRegions()
1537{
1538 static NeverDestroyed<Vector<StyleDashboardRegion>> noneList;
1539 static bool noneListInitialized = false;
1540 if (!noneListInitialized) {
1541 noneList.get().append(StyleDashboardRegion { emptyString(), { }, StyleDashboardRegion::None });
1542 noneListInitialized = true;
1543 }
1544 return noneList;
1545}
1546
1547#endif
1548
1549void RenderStyle::adjustAnimations()
1550{
1551 auto* animationList = m_rareNonInheritedData->animations.get();
1552 if (!animationList)
1553 return;
1554
1555 // Get rid of empty animations and anything beyond them
1556 for (size_t i = 0, size = animationList->size(); i < size; ++i) {
1557 if (animationList->animation(i).isEmpty()) {
1558 animationList->resize(i);
1559 break;
1560 }
1561 }
1562
1563 if (animationList->isEmpty()) {
1564 clearAnimations();
1565 return;
1566 }
1567
1568 // Repeat patterns into layers that don't have some properties set.
1569 animationList->fillUnsetProperties();
1570}
1571
1572void RenderStyle::adjustTransitions()
1573{
1574 auto* transitionList = m_rareNonInheritedData->transitions.get();
1575 if (!transitionList)
1576 return;
1577
1578 // Get rid of empty transitions and anything beyond them
1579 for (size_t i = 0, size = transitionList->size(); i < size; ++i) {
1580 if (transitionList->animation(i).isEmpty()) {
1581 transitionList->resize(i);
1582 break;
1583 }
1584 }
1585
1586 if (transitionList->isEmpty()) {
1587 clearTransitions();
1588 return;
1589 }
1590
1591 // Repeat patterns into layers that don't have some properties set.
1592 transitionList->fillUnsetProperties();
1593
1594 // Make sure there are no duplicate properties.
1595 // This is an O(n^2) algorithm but the lists tend to be short, so it is probably OK.
1596 for (size_t i = 0; i < transitionList->size(); ++i) {
1597 for (size_t j = i + 1; j < transitionList->size(); ++j) {
1598 if (transitionList->animation(i).property() == transitionList->animation(j).property()) {
1599 // toss i
1600 transitionList->remove(i);
1601 j = i;
1602 }
1603 }
1604 }
1605}
1606
1607AnimationList& RenderStyle::ensureAnimations()
1608{
1609 if (!m_rareNonInheritedData.access().animations)
1610 m_rareNonInheritedData.access().animations = std::make_unique<AnimationList>();
1611 return *m_rareNonInheritedData->animations;
1612}
1613
1614AnimationList& RenderStyle::ensureTransitions()
1615{
1616 if (!m_rareNonInheritedData.access().transitions)
1617 m_rareNonInheritedData.access().transitions = std::make_unique<AnimationList>();
1618 return *m_rareNonInheritedData->transitions;
1619}
1620
1621const Animation* RenderStyle::transitionForProperty(CSSPropertyID property) const
1622{
1623 auto* transitions = this->transitions();
1624 if (!transitions)
1625 return nullptr;
1626 for (size_t i = 0, size = transitions->size(); i < size; ++i) {
1627 auto& animation = transitions->animation(i);
1628 if (animation.animationMode() == Animation::AnimateAll || animation.property() == property)
1629 return &animation;
1630 }
1631 return nullptr;
1632}
1633
1634const FontCascade& RenderStyle::fontCascade() const
1635{
1636 return m_inheritedData->fontCascade;
1637}
1638
1639const FontMetrics& RenderStyle::fontMetrics() const
1640{
1641 return m_inheritedData->fontCascade.fontMetrics();
1642}
1643
1644const FontCascadeDescription& RenderStyle::fontDescription() const
1645{
1646 return m_inheritedData->fontCascade.fontDescription();
1647}
1648
1649float RenderStyle::specifiedFontSize() const
1650{
1651 return fontDescription().specifiedSize();
1652}
1653
1654float RenderStyle::computedFontSize() const
1655{
1656 return fontDescription().computedSize();
1657}
1658
1659unsigned RenderStyle::computedFontPixelSize() const
1660{
1661 return fontDescription().computedPixelSize();
1662}
1663
1664const Length& RenderStyle::wordSpacing() const
1665{
1666 return m_rareInheritedData->wordSpacing;
1667}
1668
1669float RenderStyle::letterSpacing() const
1670{
1671 return m_inheritedData->fontCascade.letterSpacing();
1672}
1673
1674bool RenderStyle::setFontDescription(FontCascadeDescription&& description)
1675{
1676 if (m_inheritedData->fontCascade.fontDescription() == description)
1677 return false;
1678 auto& cascade = m_inheritedData.access().fontCascade;
1679 cascade = { WTFMove(description), cascade.letterSpacing(), cascade.wordSpacing() };
1680 return true;
1681}
1682
1683const Length& RenderStyle::specifiedLineHeight() const
1684{
1685#if ENABLE(TEXT_AUTOSIZING)
1686 return m_inheritedData->specifiedLineHeight;
1687#else
1688 return m_inheritedData->lineHeight;
1689#endif
1690}
1691
1692#if ENABLE(TEXT_AUTOSIZING)
1693
1694void RenderStyle::setSpecifiedLineHeight(Length&& height)
1695{
1696 SET_VAR(m_inheritedData, specifiedLineHeight, WTFMove(height));
1697}
1698
1699#endif
1700
1701const Length& RenderStyle::lineHeight() const
1702{
1703 return m_inheritedData->lineHeight;
1704}
1705
1706void RenderStyle::setLineHeight(Length&& height)
1707{
1708 SET_VAR(m_inheritedData, lineHeight, WTFMove(height));
1709}
1710
1711int RenderStyle::computedLineHeight() const
1712{
1713 const Length& lh = lineHeight();
1714
1715 // Negative value means the line height is not set. Use the font's built-in spacing.
1716 if (lh.isNegative())
1717 return fontMetrics().lineSpacing();
1718
1719 if (lh.isPercentOrCalculated())
1720 return minimumValueForLength(lh, computedFontPixelSize());
1721
1722 return clampTo<int>(lh.value());
1723}
1724
1725void RenderStyle::setWordSpacing(Length&& value)
1726{
1727 float fontWordSpacing;
1728 switch (value.type()) {
1729 case Auto:
1730 fontWordSpacing = 0;
1731 break;
1732 case Percent:
1733 fontWordSpacing = value.percent() * fontCascade().spaceWidth() / 100;
1734 break;
1735 case Fixed:
1736 fontWordSpacing = value.value();
1737 break;
1738 case Calculated:
1739 fontWordSpacing = value.nonNanCalculatedValue(maxValueForCssLength);
1740 break;
1741 default:
1742 ASSERT_NOT_REACHED();
1743 fontWordSpacing = 0;
1744 break;
1745 }
1746 m_inheritedData.access().fontCascade.setWordSpacing(fontWordSpacing);
1747 m_rareInheritedData.access().wordSpacing = WTFMove(value);
1748}
1749
1750void RenderStyle::setLetterSpacing(float v) { m_inheritedData.access().fontCascade.setLetterSpacing(v); }
1751
1752void RenderStyle::setFontSize(float size)
1753{
1754 // size must be specifiedSize if Text Autosizing is enabled, but computedSize if text
1755 // zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
1756
1757 ASSERT(std::isfinite(size));
1758 if (!std::isfinite(size) || size < 0)
1759 size = 0;
1760 else
1761 size = std::min(maximumAllowedFontSize, size);
1762
1763 FontSelector* currentFontSelector = fontCascade().fontSelector();
1764 auto description = fontDescription();
1765 description.setSpecifiedSize(size);
1766 description.setComputedSize(size);
1767
1768 setFontDescription(WTFMove(description));
1769 fontCascade().update(currentFontSelector);
1770}
1771
1772#if ENABLE(VARIATION_FONTS)
1773void RenderStyle::setFontVariationSettings(FontVariationSettings settings)
1774{
1775 FontSelector* currentFontSelector = fontCascade().fontSelector();
1776 auto description = fontDescription();
1777 description.setVariationSettings(WTFMove(settings));
1778
1779 setFontDescription(WTFMove(description));
1780 fontCascade().update(currentFontSelector);
1781}
1782#endif
1783
1784void RenderStyle::setFontWeight(FontSelectionValue value)
1785{
1786 FontSelector* currentFontSelector = fontCascade().fontSelector();
1787 auto description = fontDescription();
1788 description.setWeight(value);
1789
1790 setFontDescription(WTFMove(description));
1791 fontCascade().update(currentFontSelector);
1792}
1793
1794void RenderStyle::setFontStretch(FontSelectionValue value)
1795{
1796 FontSelector* currentFontSelector = fontCascade().fontSelector();
1797 auto description = fontDescription();
1798 description.setStretch(value);
1799
1800 setFontDescription(WTFMove(description));
1801 fontCascade().update(currentFontSelector);
1802}
1803
1804void RenderStyle::setFontItalic(Optional<FontSelectionValue> value)
1805{
1806 FontSelector* currentFontSelector = fontCascade().fontSelector();
1807 auto description = fontDescription();
1808 description.setItalic(value);
1809
1810 setFontDescription(WTFMove(description));
1811 fontCascade().update(currentFontSelector);
1812}
1813
1814void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit& top, LayoutUnit& right, LayoutUnit& bottom, LayoutUnit& left) const
1815{
1816 top = 0;
1817 right = 0;
1818 bottom = 0;
1819 left = 0;
1820
1821 for ( ; shadow; shadow = shadow->next()) {
1822 if (shadow->style() == Inset)
1823 continue;
1824
1825 int extentAndSpread = shadow->paintingExtent() + shadow->spread();
1826 top = std::min<LayoutUnit>(top, shadow->y() - extentAndSpread);
1827 right = std::max<LayoutUnit>(right, shadow->x() + extentAndSpread);
1828 bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
1829 left = std::min<LayoutUnit>(left, shadow->x() - extentAndSpread);
1830 }
1831}
1832
1833LayoutBoxExtent RenderStyle::getShadowInsetExtent(const ShadowData* shadow) const
1834{
1835 LayoutUnit top;
1836 LayoutUnit right;
1837 LayoutUnit bottom;
1838 LayoutUnit left;
1839
1840 for ( ; shadow; shadow = shadow->next()) {
1841 if (shadow->style() == Normal)
1842 continue;
1843
1844 int extentAndSpread = shadow->paintingExtent() + shadow->spread();
1845 top = std::max<LayoutUnit>(top, shadow->y() + extentAndSpread);
1846 right = std::min<LayoutUnit>(right, shadow->x() - extentAndSpread);
1847 bottom = std::min<LayoutUnit>(bottom, shadow->y() - extentAndSpread);
1848 left = std::max<LayoutUnit>(left, shadow->x() + extentAndSpread);
1849 }
1850
1851 return LayoutBoxExtent(WTFMove(top), WTFMove(right), WTFMove(bottom), WTFMove(left));
1852}
1853
1854void RenderStyle::getShadowHorizontalExtent(const ShadowData* shadow, LayoutUnit &left, LayoutUnit &right) const
1855{
1856 left = 0;
1857 right = 0;
1858
1859 for ( ; shadow; shadow = shadow->next()) {
1860 if (shadow->style() == Inset)
1861 continue;
1862
1863 int extentAndSpread = shadow->paintingExtent() + shadow->spread();
1864 left = std::min<LayoutUnit>(left, shadow->x() - extentAndSpread);
1865 right = std::max<LayoutUnit>(right, shadow->x() + extentAndSpread);
1866 }
1867}
1868
1869void RenderStyle::getShadowVerticalExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &bottom) const
1870{
1871 top = 0;
1872 bottom = 0;
1873
1874 for ( ; shadow; shadow = shadow->next()) {
1875 if (shadow->style() == Inset)
1876 continue;
1877
1878 int extentAndSpread = shadow->paintingExtent() + shadow->spread();
1879 top = std::min<LayoutUnit>(top, shadow->y() - extentAndSpread);
1880 bottom = std::max<LayoutUnit>(bottom, shadow->y() + extentAndSpread);
1881 }
1882}
1883
1884Color RenderStyle::colorIncludingFallback(CSSPropertyID colorProperty, bool visitedLink) const
1885{
1886 Color result;
1887 BorderStyle borderStyle = BorderStyle::None;
1888 switch (colorProperty) {
1889 case CSSPropertyBackgroundColor:
1890 return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back.
1891 case CSSPropertyBorderLeftColor:
1892 result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor();
1893 borderStyle = borderLeftStyle();
1894 break;
1895 case CSSPropertyBorderRightColor:
1896 result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor();
1897 borderStyle = borderRightStyle();
1898 break;
1899 case CSSPropertyBorderTopColor:
1900 result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor();
1901 borderStyle = borderTopStyle();
1902 break;
1903 case CSSPropertyBorderBottomColor:
1904 result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor();
1905 borderStyle = borderBottomStyle();
1906 break;
1907 case CSSPropertyCaretColor:
1908 result = visitedLink ? visitedLinkCaretColor() : caretColor();
1909 break;
1910 case CSSPropertyColor:
1911 result = visitedLink ? visitedLinkColor() : color();
1912 break;
1913 case CSSPropertyOutlineColor:
1914 result = visitedLink ? visitedLinkOutlineColor() : outlineColor();
1915 break;
1916 case CSSPropertyColumnRuleColor:
1917 result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor();
1918 break;
1919 case CSSPropertyTextDecorationColor:
1920 // Text decoration color fallback is handled in RenderObject::decorationColor.
1921 return visitedLink ? visitedLinkTextDecorationColor() : textDecorationColor();
1922 case CSSPropertyWebkitTextEmphasisColor:
1923 result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor();
1924 break;
1925 case CSSPropertyWebkitTextFillColor:
1926 result = visitedLink ? visitedLinkTextFillColor() : textFillColor();
1927 break;
1928 case CSSPropertyWebkitTextStrokeColor:
1929 result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor();
1930 break;
1931 case CSSPropertyStrokeColor:
1932 result = visitedLink ? visitedLinkStrokeColor() : strokeColor();
1933 break;
1934 default:
1935 ASSERT_NOT_REACHED();
1936 break;
1937 }
1938
1939 if (!result.isValid()) {
1940 if (!visitedLink && (borderStyle == BorderStyle::Inset || borderStyle == BorderStyle::Outset || borderStyle == BorderStyle::Ridge || borderStyle == BorderStyle::Groove))
1941 result = Color(238, 238, 238);
1942 else
1943 result = visitedLink ? visitedLinkColor() : color();
1944 }
1945 return result;
1946}
1947
1948Color RenderStyle::visitedDependentColor(CSSPropertyID colorProperty) const
1949{
1950 Color unvisitedColor = colorIncludingFallback(colorProperty, false);
1951 if (insideLink() != InsideLink::InsideVisited)
1952 return unvisitedColor;
1953
1954 Color visitedColor = colorIncludingFallback(colorProperty, true);
1955
1956 // Text decoration color validity is preserved (checked in RenderObject::decorationColor).
1957 if (colorProperty == CSSPropertyTextDecorationColor)
1958 return visitedColor;
1959
1960 // FIXME: Technically someone could explicitly specify the color transparent, but for now we'll just
1961 // assume that if the background color is transparent that it wasn't set. Note that it's weird that
1962 // we're returning unvisited info for a visited link, but given our restriction that the alpha values
1963 // have to match, it makes more sense to return the unvisited background color if specified than it
1964 // does to return black. This behavior matches what Firefox 4 does as well.
1965 if (colorProperty == CSSPropertyBackgroundColor && visitedColor == Color::transparent)
1966 return unvisitedColor;
1967
1968 // Take the alpha from the unvisited color, but get the RGB values from the visited color.
1969 return visitedColor.colorWithAlpha(unvisitedColor.alphaAsFloat());
1970}
1971
1972Color RenderStyle::visitedDependentColorWithColorFilter(CSSPropertyID colorProperty) const
1973{
1974 if (!hasAppleColorFilter())
1975 return visitedDependentColor(colorProperty);
1976
1977 return colorByApplyingColorFilter(visitedDependentColor(colorProperty));
1978}
1979
1980Color RenderStyle::colorByApplyingColorFilter(const Color& color) const
1981{
1982 Color transformedColor = color;
1983 appleColorFilter().transformColor(transformedColor);
1984 return transformedColor;
1985}
1986
1987const BorderValue& RenderStyle::borderBefore() const
1988{
1989 switch (writingMode()) {
1990 case TopToBottomWritingMode:
1991 return borderTop();
1992 case BottomToTopWritingMode:
1993 return borderBottom();
1994 case LeftToRightWritingMode:
1995 return borderLeft();
1996 case RightToLeftWritingMode:
1997 return borderRight();
1998 }
1999 ASSERT_NOT_REACHED();
2000 return borderTop();
2001}
2002
2003const BorderValue& RenderStyle::borderAfter() const
2004{
2005 switch (writingMode()) {
2006 case TopToBottomWritingMode:
2007 return borderBottom();
2008 case BottomToTopWritingMode:
2009 return borderTop();
2010 case LeftToRightWritingMode:
2011 return borderRight();
2012 case RightToLeftWritingMode:
2013 return borderLeft();
2014 }
2015 ASSERT_NOT_REACHED();
2016 return borderBottom();
2017}
2018
2019const BorderValue& RenderStyle::borderStart() const
2020{
2021 if (isHorizontalWritingMode())
2022 return isLeftToRightDirection() ? borderLeft() : borderRight();
2023 return isLeftToRightDirection() ? borderTop() : borderBottom();
2024}
2025
2026const BorderValue& RenderStyle::borderEnd() const
2027{
2028 if (isHorizontalWritingMode())
2029 return isLeftToRightDirection() ? borderRight() : borderLeft();
2030 return isLeftToRightDirection() ? borderBottom() : borderTop();
2031}
2032
2033float RenderStyle::borderBeforeWidth() const
2034{
2035 switch (writingMode()) {
2036 case TopToBottomWritingMode:
2037 return borderTopWidth();
2038 case BottomToTopWritingMode:
2039 return borderBottomWidth();
2040 case LeftToRightWritingMode:
2041 return borderLeftWidth();
2042 case RightToLeftWritingMode:
2043 return borderRightWidth();
2044 }
2045 ASSERT_NOT_REACHED();
2046 return borderTopWidth();
2047}
2048
2049float RenderStyle::borderAfterWidth() const
2050{
2051 switch (writingMode()) {
2052 case TopToBottomWritingMode:
2053 return borderBottomWidth();
2054 case BottomToTopWritingMode:
2055 return borderTopWidth();
2056 case LeftToRightWritingMode:
2057 return borderRightWidth();
2058 case RightToLeftWritingMode:
2059 return borderLeftWidth();
2060 }
2061 ASSERT_NOT_REACHED();
2062 return borderBottomWidth();
2063}
2064
2065float RenderStyle::borderStartWidth() const
2066{
2067 if (isHorizontalWritingMode())
2068 return isLeftToRightDirection() ? borderLeftWidth() : borderRightWidth();
2069 return isLeftToRightDirection() ? borderTopWidth() : borderBottomWidth();
2070}
2071
2072float RenderStyle::borderEndWidth() const
2073{
2074 if (isHorizontalWritingMode())
2075 return isLeftToRightDirection() ? borderRightWidth() : borderLeftWidth();
2076 return isLeftToRightDirection() ? borderBottomWidth() : borderTopWidth();
2077}
2078
2079void RenderStyle::setMarginStart(Length&& margin)
2080{
2081 if (isHorizontalWritingMode()) {
2082 if (isLeftToRightDirection())
2083 setMarginLeft(WTFMove(margin));
2084 else
2085 setMarginRight(WTFMove(margin));
2086 } else {
2087 if (isLeftToRightDirection())
2088 setMarginTop(WTFMove(margin));
2089 else
2090 setMarginBottom(WTFMove(margin));
2091 }
2092}
2093
2094void RenderStyle::setMarginEnd(Length&& margin)
2095{
2096 if (isHorizontalWritingMode()) {
2097 if (isLeftToRightDirection())
2098 setMarginRight(WTFMove(margin));
2099 else
2100 setMarginLeft(WTFMove(margin));
2101 } else {
2102 if (isLeftToRightDirection())
2103 setMarginBottom(WTFMove(margin));
2104 else
2105 setMarginTop(WTFMove(margin));
2106 }
2107}
2108
2109TextEmphasisMark RenderStyle::textEmphasisMark() const
2110{
2111 auto mark = static_cast<TextEmphasisMark>(m_rareInheritedData->textEmphasisMark);
2112 if (mark != TextEmphasisMark::Auto)
2113 return mark;
2114 if (isHorizontalWritingMode())
2115 return TextEmphasisMark::Dot;
2116 return TextEmphasisMark::Sesame;
2117}
2118
2119#if ENABLE(TOUCH_EVENTS)
2120
2121Color RenderStyle::initialTapHighlightColor()
2122{
2123 return RenderTheme::tapHighlightColor();
2124}
2125
2126#endif
2127
2128LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const
2129{
2130 return LayoutBoxExtent(NinePieceImage::computeOutset(image.outset().top(), borderTopWidth()),
2131 NinePieceImage::computeOutset(image.outset().right(), borderRightWidth()),
2132 NinePieceImage::computeOutset(image.outset().bottom(), borderBottomWidth()),
2133 NinePieceImage::computeOutset(image.outset().left(), borderLeftWidth()));
2134}
2135
2136std::pair<FontOrientation, NonCJKGlyphOrientation> RenderStyle::fontAndGlyphOrientation()
2137{
2138 // FIXME: TextOrientationSideways should map to sideways-left in vertical-lr, which is not supported yet.
2139
2140 if (isHorizontalWritingMode())
2141 return { FontOrientation::Horizontal, NonCJKGlyphOrientation::Mixed };
2142
2143 switch (textOrientation()) {
2144 case TextOrientation::Mixed:
2145 return { FontOrientation::Vertical, NonCJKGlyphOrientation::Mixed };
2146 case TextOrientation::Upright:
2147 return { FontOrientation::Vertical, NonCJKGlyphOrientation::Upright };
2148 case TextOrientation::Sideways:
2149 return { FontOrientation::Horizontal, NonCJKGlyphOrientation::Mixed };
2150 default:
2151 ASSERT_NOT_REACHED();
2152 return { FontOrientation::Horizontal, NonCJKGlyphOrientation::Mixed };
2153 }
2154}
2155
2156void RenderStyle::setBorderImageSource(RefPtr<StyleImage>&& image)
2157{
2158 if (m_surroundData->border.m_image.image() == image.get())
2159 return;
2160 m_surroundData.access().border.m_image.setImage(WTFMove(image));
2161}
2162
2163void RenderStyle::setBorderImageSlices(LengthBox&& slices)
2164{
2165 if (m_surroundData->border.m_image.imageSlices() == slices)
2166 return;
2167 m_surroundData.access().border.m_image.setImageSlices(WTFMove(slices));
2168}
2169
2170void RenderStyle::setBorderImageWidth(LengthBox&& slices)
2171{
2172 if (m_surroundData->border.m_image.borderSlices() == slices)
2173 return;
2174 m_surroundData.access().border.m_image.setBorderSlices(WTFMove(slices));
2175}
2176
2177void RenderStyle::setBorderImageOutset(LengthBox&& outset)
2178{
2179 if (m_surroundData->border.m_image.outset() == outset)
2180 return;
2181 m_surroundData.access().border.m_image.setOutset(WTFMove(outset));
2182}
2183
2184void RenderStyle::setColumnStylesFromPaginationMode(const Pagination::Mode& paginationMode)
2185{
2186 if (paginationMode == Pagination::Unpaginated)
2187 return;
2188
2189 setColumnFill(ColumnFill::Auto);
2190
2191 switch (paginationMode) {
2192 case Pagination::LeftToRightPaginated:
2193 setColumnAxis(ColumnAxis::Horizontal);
2194 if (isHorizontalWritingMode())
2195 setColumnProgression(isLeftToRightDirection() ? ColumnProgression::Normal : ColumnProgression::Reverse);
2196 else
2197 setColumnProgression(isFlippedBlocksWritingMode() ? ColumnProgression::Reverse : ColumnProgression::Normal);
2198 break;
2199 case Pagination::RightToLeftPaginated:
2200 setColumnAxis(ColumnAxis::Horizontal);
2201 if (isHorizontalWritingMode())
2202 setColumnProgression(isLeftToRightDirection() ? ColumnProgression::Reverse : ColumnProgression::Normal);
2203 else
2204 setColumnProgression(isFlippedBlocksWritingMode() ? ColumnProgression::Normal : ColumnProgression::Reverse);
2205 break;
2206 case Pagination::TopToBottomPaginated:
2207 setColumnAxis(ColumnAxis::Vertical);
2208 if (isHorizontalWritingMode())
2209 setColumnProgression(isFlippedBlocksWritingMode() ? ColumnProgression::Reverse : ColumnProgression::Normal);
2210 else
2211 setColumnProgression(isLeftToRightDirection() ? ColumnProgression::Normal : ColumnProgression::Reverse);
2212 break;
2213 case Pagination::BottomToTopPaginated:
2214 setColumnAxis(ColumnAxis::Vertical);
2215 if (isHorizontalWritingMode())
2216 setColumnProgression(isFlippedBlocksWritingMode() ? ColumnProgression::Normal : ColumnProgression::Reverse);
2217 else
2218 setColumnProgression(isLeftToRightDirection() ? ColumnProgression::Reverse : ColumnProgression::Normal);
2219 break;
2220 case Pagination::Unpaginated:
2221 ASSERT_NOT_REACHED();
2222 break;
2223 }
2224}
2225
2226#if ENABLE(CSS_SCROLL_SNAP)
2227
2228ScrollSnapType RenderStyle::initialScrollSnapType()
2229{
2230 return { };
2231}
2232
2233ScrollSnapAlign RenderStyle::initialScrollSnapAlign()
2234{
2235 return { };
2236}
2237
2238const StyleScrollSnapArea& RenderStyle::scrollSnapArea() const
2239{
2240 return *m_rareNonInheritedData->scrollSnapArea;
2241}
2242
2243const StyleScrollSnapPort& RenderStyle::scrollSnapPort() const
2244{
2245 return *m_rareNonInheritedData->scrollSnapPort;
2246}
2247
2248const ScrollSnapType& RenderStyle::scrollSnapType() const
2249{
2250 return m_rareNonInheritedData->scrollSnapPort->type;
2251}
2252
2253const LengthBox& RenderStyle::scrollPadding() const
2254{
2255 return m_rareNonInheritedData->scrollSnapPort->scrollPadding;
2256}
2257
2258const Length& RenderStyle::scrollPaddingTop() const
2259{
2260 return scrollPadding().top();
2261}
2262
2263const Length& RenderStyle::scrollPaddingBottom() const
2264{
2265 return scrollPadding().bottom();
2266}
2267
2268const Length& RenderStyle::scrollPaddingLeft() const
2269{
2270 return scrollPadding().left();
2271}
2272
2273const Length& RenderStyle::scrollPaddingRight() const
2274{
2275 return scrollPadding().right();
2276}
2277
2278const ScrollSnapAlign& RenderStyle::scrollSnapAlign() const
2279{
2280 return m_rareNonInheritedData->scrollSnapArea->alignment;
2281}
2282
2283const LengthBox& RenderStyle::scrollSnapMargin() const
2284{
2285 return m_rareNonInheritedData->scrollSnapArea->scrollSnapMargin;
2286}
2287
2288const Length& RenderStyle::scrollSnapMarginTop() const
2289{
2290 return scrollSnapMargin().top();
2291}
2292
2293const Length& RenderStyle::scrollSnapMarginBottom() const
2294{
2295 return scrollSnapMargin().bottom();
2296}
2297
2298const Length& RenderStyle::scrollSnapMarginLeft() const
2299{
2300 return scrollSnapMargin().left();
2301}
2302
2303const Length& RenderStyle::scrollSnapMarginRight() const
2304{
2305 return scrollSnapMargin().right();
2306}
2307
2308void RenderStyle::setScrollSnapType(const ScrollSnapType& type)
2309{
2310 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, type, type);
2311}
2312
2313void RenderStyle::setScrollPaddingTop(Length&& length)
2314{
2315 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.top(), WTFMove(length));
2316}
2317
2318void RenderStyle::setScrollPaddingBottom(Length&& length)
2319{
2320 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.bottom(), WTFMove(length));
2321}
2322
2323void RenderStyle::setScrollPaddingLeft(Length&& length)
2324{
2325 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.left(), WTFMove(length));
2326}
2327
2328void RenderStyle::setScrollPaddingRight(Length&& length)
2329{
2330 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapPort, scrollPadding.right(), WTFMove(length));
2331}
2332
2333void RenderStyle::setScrollSnapAlign(const ScrollSnapAlign& alignment)
2334{
2335 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, alignment, alignment);
2336}
2337
2338void RenderStyle::setScrollSnapMarginTop(Length&& length)
2339{
2340 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.top(), WTFMove(length));
2341}
2342
2343void RenderStyle::setScrollSnapMarginBottom(Length&& length)
2344{
2345 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.bottom(), WTFMove(length));
2346}
2347
2348void RenderStyle::setScrollSnapMarginLeft(Length&& length)
2349{
2350 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.left(), WTFMove(length));
2351}
2352
2353void RenderStyle::setScrollSnapMarginRight(Length&& length)
2354{
2355 SET_NESTED_VAR(m_rareNonInheritedData, scrollSnapArea, scrollSnapMargin.right(), WTFMove(length));
2356}
2357
2358#endif
2359
2360bool RenderStyle::hasReferenceFilterOnly() const
2361{
2362 if (!hasFilter())
2363 return false;
2364 auto& filterOperations = m_rareNonInheritedData->filter->operations;
2365 return filterOperations.size() == 1 && filterOperations.at(0)->type() == FilterOperation::REFERENCE;
2366}
2367
2368float RenderStyle::outlineWidth() const
2369{
2370 if (m_backgroundData->outline.style() == BorderStyle::None)
2371 return 0;
2372 if (outlineStyleIsAuto() == OutlineIsAuto::On)
2373 return std::max(m_backgroundData->outline.width(), RenderTheme::platformFocusRingWidth());
2374 return m_backgroundData->outline.width();
2375}
2376
2377float RenderStyle::outlineOffset() const
2378{
2379 if (m_backgroundData->outline.style() == BorderStyle::None)
2380 return 0;
2381 if (outlineStyleIsAuto() == OutlineIsAuto::On)
2382 return (m_backgroundData->outline.offset() + RenderTheme::platformFocusRingOffset(outlineWidth()));
2383 return m_backgroundData->outline.offset();
2384}
2385
2386bool RenderStyle::shouldPlaceBlockDirectionScrollbarOnLeft() const
2387{
2388 return !isLeftToRightDirection() && isHorizontalWritingMode();
2389}
2390
2391#if ENABLE(DASHBOARD_SUPPORT)
2392
2393void RenderStyle::setDashboardRegion(int type, const String& label, Length&& top, Length&& right, Length&& bottom, Length&& left, bool append)
2394{
2395 if (!append)
2396 m_rareNonInheritedData.access().dashboardRegions.clear();
2397 m_rareNonInheritedData.access().dashboardRegions.append({ label, { WTFMove(top), WTFMove(right), WTFMove(bottom), WTFMove(left) }, type });
2398}
2399
2400#endif
2401
2402Vector<PaintType, 3> RenderStyle::paintTypesForPaintOrder(PaintOrder order)
2403{
2404 Vector<PaintType, 3> paintOrder;
2405 switch (order) {
2406 case PaintOrder::Normal:
2407 FALLTHROUGH;
2408 case PaintOrder::Fill:
2409 paintOrder.append(PaintType::Fill);
2410 paintOrder.append(PaintType::Stroke);
2411 paintOrder.append(PaintType::Markers);
2412 break;
2413 case PaintOrder::FillMarkers:
2414 paintOrder.append(PaintType::Fill);
2415 paintOrder.append(PaintType::Markers);
2416 paintOrder.append(PaintType::Stroke);
2417 break;
2418 case PaintOrder::Stroke:
2419 paintOrder.append(PaintType::Stroke);
2420 paintOrder.append(PaintType::Fill);
2421 paintOrder.append(PaintType::Markers);
2422 break;
2423 case PaintOrder::StrokeMarkers:
2424 paintOrder.append(PaintType::Stroke);
2425 paintOrder.append(PaintType::Markers);
2426 paintOrder.append(PaintType::Fill);
2427 break;
2428 case PaintOrder::Markers:
2429 paintOrder.append(PaintType::Markers);
2430 paintOrder.append(PaintType::Fill);
2431 paintOrder.append(PaintType::Stroke);
2432 break;
2433 case PaintOrder::MarkersStroke:
2434 paintOrder.append(PaintType::Markers);
2435 paintOrder.append(PaintType::Stroke);
2436 paintOrder.append(PaintType::Fill);
2437 break;
2438 };
2439 return paintOrder;
2440}
2441
2442float RenderStyle::computedStrokeWidth(const IntSize& viewportSize) const
2443{
2444 // Use the stroke-width and stroke-color value combination only if stroke-color has been explicitly specified.
2445 // Since there will be no visible stroke when stroke-color is not specified (transparent by default), we fall
2446 // back to the legacy Webkit text stroke combination in that case.
2447 if (!hasExplicitlySetStrokeColor())
2448 return textStrokeWidth();
2449
2450 const Length& length = strokeWidth();
2451
2452 if (length.isPercent()) {
2453 // According to the spec, https://drafts.fxtf.org/paint/#stroke-width, the percentage is relative to the scaled viewport size.
2454 // The scaled viewport size is the geometric mean of the viewport width and height.
2455 ExceptionOr<float> result = length.value() * (viewportSize.width() + viewportSize.height()) / 200.0f;
2456 if (result.hasException())
2457 return 0;
2458 return result.releaseReturnValue();
2459 }
2460
2461 if (length.isAuto() || !length.isSpecified())
2462 return 0;
2463
2464 return floatValueForLength(length, viewportSize.width());
2465}
2466
2467bool RenderStyle::hasPositiveStrokeWidth() const
2468{
2469 if (!hasExplicitlySetStrokeWidth())
2470 return textStrokeWidth() > 0;
2471
2472 return strokeWidth().isPositive();
2473}
2474
2475Color RenderStyle::computedStrokeColor() const
2476{
2477 CSSPropertyID propertyID = CSSPropertyStrokeColor;
2478 if (!hasExplicitlySetStrokeColor())
2479 propertyID = CSSPropertyWebkitTextStrokeColor;
2480 return visitedDependentColor(propertyID);
2481}
2482
2483} // namespace WebCore
2484