1 /*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
4 * reserved.
5 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #include "third_party/blink/renderer/core/style/computed_style.h"
25
26 #include <algorithm>
27 #include <memory>
28 #include <utility>
29
30 #include "base/metrics/histogram_functions.h"
31 #include "base/numerics/clamped_math.h"
32 #include "base/numerics/ranges.h"
33 #include "build/build_config.h"
34 #include "cc/input/overscroll_behavior.h"
35 #include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
36 #include "third_party/blink/renderer/core/animation/css/css_transition_data.h"
37 #include "third_party/blink/renderer/core/css/css_paint_value.h"
38 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
39 #include "third_party/blink/renderer/core/css/css_property_equality.h"
40 #include "third_party/blink/renderer/core/css/properties/css_property.h"
41 #include "third_party/blink/renderer/core/css/properties/longhand.h"
42 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
43 #include "third_party/blink/renderer/core/dom/document.h"
44 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
45 #include "third_party/blink/renderer/core/html/html_progress_element.h"
46 #include "third_party/blink/renderer/core/layout/layout_theme.h"
47 #include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
48 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
49 #include "third_party/blink/renderer/core/style/applied_text_decoration.h"
50 #include "third_party/blink/renderer/core/style/border_edge.h"
51 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
52 #include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
53 #include "third_party/blink/renderer/core/style/content_data.h"
54 #include "third_party/blink/renderer/core/style/cursor_data.h"
55 #include "third_party/blink/renderer/core/style/data_equivalency.h"
56 #include "third_party/blink/renderer/core/style/quotes_data.h"
57 #include "third_party/blink/renderer/core/style/shadow_list.h"
58 #include "third_party/blink/renderer/core/style/style_difference.h"
59 #include "third_party/blink/renderer/core/style/style_fetched_image.h"
60 #include "third_party/blink/renderer/core/style/style_generated_image.h"
61 #include "third_party/blink/renderer/core/style/style_image.h"
62 #include "third_party/blink/renderer/core/style/style_inherited_variables.h"
63 #include "third_party/blink/renderer/core/style/style_non_inherited_variables.h"
64 #include "third_party/blink/renderer/core/style/style_ray.h"
65 #include "third_party/blink/renderer/platform/fonts/font.h"
66 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
67 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
68 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
69 #include "third_party/blink/renderer/platform/graphics/path.h"
70 #include "third_party/blink/renderer/platform/text/capitalize.h"
71 #include "third_party/blink/renderer/platform/text/character.h"
72 #include "third_party/blink/renderer/platform/transforms/rotate_transform_operation.h"
73 #include "third_party/blink/renderer/platform/transforms/scale_transform_operation.h"
74 #include "third_party/blink/renderer/platform/transforms/translate_transform_operation.h"
75 #include "third_party/blink/renderer/platform/wtf/assertions.h"
76 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
77 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
78 #include "third_party/blink/renderer/platform/wtf/text/case_map.h"
79 #include "third_party/blink/renderer/platform/wtf/text/math_transform.h"
80 #include "ui/base/ui_base_features.h"
81
82 namespace blink {
83
84 struct SameSizeAsBorderValue {
85 StyleColor color_;
86 unsigned bitfield_;
87 };
88
89 ASSERT_SIZE(BorderValue, SameSizeAsBorderValue);
90
91 // Since different compilers/architectures pack ComputedStyle differently,
92 // re-create the same structure for an accurate size comparison.
93 //
94 // Keep a separate struct for ComputedStyleBase so that we can recreate the
95 // inheritance structure. Make sure the fields have the same access specifiers
96 // as in the "real" class since it can affect the layout. Reference the fields
97 // so that they are not seen as unused (-Wunused-private-field).
98 struct SameSizeAsComputedStyleBase {
SameSizeAsComputedStyleBaseblink::SameSizeAsComputedStyleBase99 SameSizeAsComputedStyleBase() {
100 base::debug::Alias(&data_refs);
101 base::debug::Alias(&bitfields);
102 }
103
104 private:
105 void* data_refs[8];
106 unsigned bitfields[6];
107 };
108
109 struct SameSizeAsComputedStyle : public SameSizeAsComputedStyleBase,
110 public RefCounted<SameSizeAsComputedStyle> {
SameSizeAsComputedStyleblink::SameSizeAsComputedStyle111 SameSizeAsComputedStyle() {
112 base::debug::Alias(&own_ptrs);
113 base::debug::Alias(&data_ref_svg_style);
114 }
115
116 private:
117 void* own_ptrs[1];
118 void* data_ref_svg_style;
119 };
120
121 // If this assert fails, it means that size of ComputedStyle has changed. Please
122 // check that you really *do* want to increase the size of ComputedStyle, then
123 // update the SameSizeAsComputedStyle struct to match the updated storage of
124 // ComputedStyle.
125 ASSERT_SIZE(ComputedStyle, SameSizeAsComputedStyle);
126
Create()127 scoped_refptr<ComputedStyle> ComputedStyle::Create() {
128 return base::AdoptRef(new ComputedStyle(PassKey(), InitialStyle()));
129 }
130
CreateInitialStyle()131 scoped_refptr<ComputedStyle> ComputedStyle::CreateInitialStyle() {
132 return base::AdoptRef(new ComputedStyle(PassKey()));
133 }
134
MutableInitialStyle()135 ComputedStyle& ComputedStyle::MutableInitialStyle() {
136 LEAK_SANITIZER_DISABLED_SCOPE;
137 DEFINE_STATIC_REF(ComputedStyle, initial_style,
138 (ComputedStyle::CreateInitialStyle()));
139 return *initial_style;
140 }
141
InvalidateInitialStyle()142 void ComputedStyle::InvalidateInitialStyle() {
143 MutableInitialStyle().SetTapHighlightColor(
144 ComputedStyleInitialValues::InitialTapHighlightColor());
145 }
146
CreateAnonymousStyleWithDisplay(const ComputedStyle & parent_style,EDisplay display)147 scoped_refptr<ComputedStyle> ComputedStyle::CreateAnonymousStyleWithDisplay(
148 const ComputedStyle& parent_style,
149 EDisplay display) {
150 scoped_refptr<ComputedStyle> new_style = ComputedStyle::Create();
151 new_style->InheritFrom(parent_style);
152 new_style->SetUnicodeBidi(parent_style.GetUnicodeBidi());
153 new_style->SetDisplay(display);
154 return new_style;
155 }
156
157 scoped_refptr<ComputedStyle>
CreateInheritedDisplayContentsStyleIfNeeded(const ComputedStyle & parent_style,const ComputedStyle & layout_parent_style)158 ComputedStyle::CreateInheritedDisplayContentsStyleIfNeeded(
159 const ComputedStyle& parent_style,
160 const ComputedStyle& layout_parent_style) {
161 if (parent_style.InheritedEqual(layout_parent_style))
162 return nullptr;
163 return ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
164 EDisplay::kInline);
165 }
166
Clone(const ComputedStyle & other)167 scoped_refptr<ComputedStyle> ComputedStyle::Clone(const ComputedStyle& other) {
168 return base::AdoptRef(new ComputedStyle(PassKey(), other));
169 }
170
ComputedStyle()171 ALWAYS_INLINE ComputedStyle::ComputedStyle()
172 : ComputedStyleBase(), RefCounted<ComputedStyle>() {
173 svg_style_.Init();
174 }
175
ComputedStyle(const ComputedStyle & o)176 ALWAYS_INLINE ComputedStyle::ComputedStyle(const ComputedStyle& o)
177 : ComputedStyleBase(o),
178 RefCounted<ComputedStyle>(),
179 svg_style_(o.svg_style_) {}
180
ComputedStyle(PassKey key)181 ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key) : ComputedStyle() {}
182
ComputedStyle(PassKey key,const ComputedStyle & o)183 ALWAYS_INLINE ComputedStyle::ComputedStyle(PassKey key, const ComputedStyle& o)
184 : ComputedStyle(o) {}
185
PseudoElementStylesEqual(const ComputedStyle & old_style,const ComputedStyle & new_style)186 static bool PseudoElementStylesEqual(const ComputedStyle& old_style,
187 const ComputedStyle& new_style) {
188 if (!old_style.HasAnyPseudoElementStyles() &&
189 !new_style.HasAnyPseudoElementStyles())
190 return true;
191 for (PseudoId pseudo_id = kFirstPublicPseudoId;
192 pseudo_id < kFirstInternalPseudoId;
193 pseudo_id = static_cast<PseudoId>(pseudo_id + 1)) {
194 if (!old_style.HasPseudoElementStyle(pseudo_id) &&
195 !new_style.HasPseudoElementStyle(pseudo_id))
196 continue;
197 const ComputedStyle* new_pseudo_style =
198 new_style.GetCachedPseudoElementStyle(pseudo_id);
199 if (!new_pseudo_style)
200 return false;
201 const ComputedStyle* old_pseudo_style =
202 old_style.GetCachedPseudoElementStyle(pseudo_id);
203 if (old_pseudo_style && *old_pseudo_style != *new_pseudo_style)
204 return false;
205 }
206 return true;
207 }
208
NeedsReattachLayoutTree(const Element & element,const ComputedStyle * old_style,const ComputedStyle * new_style)209 bool ComputedStyle::NeedsReattachLayoutTree(const Element& element,
210 const ComputedStyle* old_style,
211 const ComputedStyle* new_style) {
212 if (old_style == new_style)
213 return false;
214 if (!old_style || !new_style)
215 return true;
216 if (old_style->Display() != new_style->Display())
217 return true;
218 if (old_style->HasPseudoElementStyle(kPseudoIdFirstLetter) !=
219 new_style->HasPseudoElementStyle(kPseudoIdFirstLetter))
220 return true;
221 if (!old_style->ContentDataEquivalent(*new_style))
222 return true;
223 if (old_style->HasTextCombine() != new_style->HasTextCombine())
224 return true;
225 // line-clamping is currently only handled by LayoutDeprecatedFlexibleBox,
226 // so that if line-clamping changes then the LayoutObject needs to be
227 // recreated.
228 if (old_style->IsDeprecatedFlexboxUsingFlexLayout() !=
229 new_style->IsDeprecatedFlexboxUsingFlexLayout())
230 return true;
231 // We need to perform a reattach if a "display: layout(foo)" has changed to a
232 // "display: layout(bar)". This is because one custom layout could be
233 // registered and the other may not, affecting the box-tree construction.
234 if (old_style->DisplayLayoutCustomName() !=
235 new_style->DisplayLayoutCustomName())
236 return true;
237 if (old_style->HasEffectiveAppearance() !=
238 new_style->HasEffectiveAppearance() &&
239 IsA<HTMLProgressElement>(element)) {
240 // HTMLProgressElement::CreateLayoutObject creates different LayoutObjects
241 // based on appearance.
242 return true;
243 }
244 if (!RuntimeEnabledFeatures::LayoutNGEnabled())
245 return false;
246
247 // LayoutNG needs an anonymous inline wrapper if ::first-line is applied.
248 // Also see |LayoutBlockFlow::NeedsAnonymousInlineWrapper()|.
249 if (new_style->HasPseudoElementStyle(kPseudoIdFirstLine) &&
250 !old_style->HasPseudoElementStyle(kPseudoIdFirstLine))
251 return true;
252
253 return false;
254 }
255
ComputeDifference(const ComputedStyle * old_style,const ComputedStyle * new_style)256 ComputedStyle::Difference ComputedStyle::ComputeDifference(
257 const ComputedStyle* old_style,
258 const ComputedStyle* new_style) {
259 if (old_style == new_style)
260 return Difference::kEqual;
261 if (!old_style || !new_style)
262 return Difference::kInherited;
263
264 // For inline elements, the new computed first line style will be |new_style|
265 // inheriting from the parent's first line style. If |new_style| is different
266 // from |old_style|'s cached inherited first line style, the new computed
267 // first line style may be different from the old even if |new_style| and
268 // |old_style| equal. Especially if the difference is on inherited properties,
269 // we need to propagate the difference to descendants.
270 // See external/wpt/css/css-pseudo/first-line-change-inline-color*.html.
271 auto inherited_first_line_style_diff = Difference::kEqual;
272 if (const ComputedStyle* cached_inherited_first_line_style =
273 old_style->GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited)) {
274 DCHECK(
275 !new_style->GetCachedPseudoElementStyle(kPseudoIdFirstLineInherited));
276 inherited_first_line_style_diff =
277 ComputeDifferenceIgnoringInheritedFirstLineStyle(
278 *cached_inherited_first_line_style, *new_style);
279 }
280 return std::max(
281 inherited_first_line_style_diff,
282 ComputeDifferenceIgnoringInheritedFirstLineStyle(*old_style, *new_style));
283 }
284
285 ComputedStyle::Difference
ComputeDifferenceIgnoringInheritedFirstLineStyle(const ComputedStyle & old_style,const ComputedStyle & new_style)286 ComputedStyle::ComputeDifferenceIgnoringInheritedFirstLineStyle(
287 const ComputedStyle& old_style,
288 const ComputedStyle& new_style) {
289 DCHECK_NE(&old_style, &new_style);
290 if (old_style.Display() != new_style.Display() &&
291 old_style.BlockifiesChildren() != new_style.BlockifiesChildren())
292 return Difference::kDisplayAffectingDescendantStyles;
293 if (!old_style.NonIndependentInheritedEqual(new_style))
294 return Difference::kInherited;
295 if (old_style.JustifyItems() != new_style.JustifyItems())
296 return Difference::kInherited;
297 bool non_inherited_equal = old_style.NonInheritedEqual(new_style);
298 if (!non_inherited_equal && old_style.ChildHasExplicitInheritance()) {
299 return Difference::kInherited;
300 }
301 bool variables_independent =
302 !old_style.HasVariableReference() && !old_style.HasVariableDeclaration();
303 bool inherited_variables_equal = old_style.InheritedVariablesEqual(new_style);
304 if (!inherited_variables_equal && !variables_independent)
305 return Difference::kInherited;
306 if (!old_style.IndependentInheritedEqual(new_style) ||
307 !inherited_variables_equal) {
308 return Difference::kIndependentInherited;
309 }
310 if (non_inherited_equal) {
311 DCHECK(old_style == new_style);
312 if (PseudoElementStylesEqual(old_style, new_style))
313 return Difference::kEqual;
314 return Difference::kPseudoElementStyle;
315 }
316 if (new_style.HasAnyPseudoElementStyles() ||
317 old_style.HasAnyPseudoElementStyles())
318 return Difference::kPseudoElementStyle;
319 if (old_style.Display() != new_style.Display() &&
320 (new_style.Display() == EDisplay::kListItem ||
321 old_style.Display() == EDisplay::kListItem))
322 return Difference::kPseudoElementStyle;
323 return Difference::kNonInherited;
324 }
325
PropagateIndependentInheritedProperties(const ComputedStyle & parent_style)326 void ComputedStyle::PropagateIndependentInheritedProperties(
327 const ComputedStyle& parent_style) {
328 ComputedStyleBase::PropagateIndependentInheritedProperties(parent_style);
329 if (!HasVariableReference() && !HasVariableDeclaration())
330 InheritCustomPropertiesFrom(parent_style);
331 }
332
ResolvedSelfAlignment(const StyleSelfAlignmentData & value,ItemPosition normal_value_behavior)333 StyleSelfAlignmentData ResolvedSelfAlignment(
334 const StyleSelfAlignmentData& value,
335 ItemPosition normal_value_behavior) {
336 if (value.GetPosition() == ItemPosition::kLegacy ||
337 value.GetPosition() == ItemPosition::kNormal ||
338 value.GetPosition() == ItemPosition::kAuto)
339 return {normal_value_behavior, OverflowAlignment::kDefault};
340 return value;
341 }
342
ResolvedAlignItems(ItemPosition normal_value_behaviour) const343 StyleSelfAlignmentData ComputedStyle::ResolvedAlignItems(
344 ItemPosition normal_value_behaviour) const {
345 // We will return the behaviour of 'normal' value if needed, which is specific
346 // of each layout model.
347 return ResolvedSelfAlignment(AlignItems(), normal_value_behaviour);
348 }
349
ResolvedAlignSelf(ItemPosition normal_value_behaviour,const ComputedStyle * parent_style) const350 StyleSelfAlignmentData ComputedStyle::ResolvedAlignSelf(
351 ItemPosition normal_value_behaviour,
352 const ComputedStyle* parent_style) const {
353 // We will return the behaviour of 'normal' value if needed, which is specific
354 // of each layout model.
355 if (!parent_style || AlignSelfPosition() != ItemPosition::kAuto)
356 return ResolvedSelfAlignment(AlignSelf(), normal_value_behaviour);
357
358 // The 'auto' keyword computes to the parent's align-items computed value.
359 return parent_style->ResolvedAlignItems(normal_value_behaviour);
360 }
361
ResolvedJustifyItems(ItemPosition normal_value_behaviour) const362 StyleSelfAlignmentData ComputedStyle::ResolvedJustifyItems(
363 ItemPosition normal_value_behaviour) const {
364 // We will return the behaviour of 'normal' value if needed, which is specific
365 // of each layout model.
366 return ResolvedSelfAlignment(JustifyItems(), normal_value_behaviour);
367 }
368
ResolvedJustifySelf(ItemPosition normal_value_behaviour,const ComputedStyle * parent_style) const369 StyleSelfAlignmentData ComputedStyle::ResolvedJustifySelf(
370 ItemPosition normal_value_behaviour,
371 const ComputedStyle* parent_style) const {
372 // We will return the behaviour of 'normal' value if needed, which is specific
373 // of each layout model.
374 if (!parent_style || JustifySelfPosition() != ItemPosition::kAuto)
375 return ResolvedSelfAlignment(JustifySelf(), normal_value_behaviour);
376
377 // The auto keyword computes to the parent's justify-items computed value.
378 return parent_style->ResolvedJustifyItems(normal_value_behaviour);
379 }
380
ResolvedContentAlignment(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_behaviour)381 StyleContentAlignmentData ResolvedContentAlignment(
382 const StyleContentAlignmentData& value,
383 const StyleContentAlignmentData& normal_behaviour) {
384 return (value.GetPosition() == ContentPosition::kNormal &&
385 value.Distribution() == ContentDistributionType::kDefault)
386 ? normal_behaviour
387 : value;
388 }
389
ResolvedAlignContent(const StyleContentAlignmentData & normal_behaviour) const390 StyleContentAlignmentData ComputedStyle::ResolvedAlignContent(
391 const StyleContentAlignmentData& normal_behaviour) const {
392 // We will return the behaviour of 'normal' value if needed, which is specific
393 // of each layout model.
394 return ResolvedContentAlignment(AlignContent(), normal_behaviour);
395 }
396
ResolvedJustifyContent(const StyleContentAlignmentData & normal_behaviour) const397 StyleContentAlignmentData ComputedStyle::ResolvedJustifyContent(
398 const StyleContentAlignmentData& normal_behaviour) const {
399 // We will return the behaviour of 'normal' value if needed, which is specific
400 // of each layout model.
401 return ResolvedContentAlignment(JustifyContent(), normal_behaviour);
402 }
403
ResolvedContentAlignmentPosition(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_value_behavior)404 static inline ContentPosition ResolvedContentAlignmentPosition(
405 const StyleContentAlignmentData& value,
406 const StyleContentAlignmentData& normal_value_behavior) {
407 return (value.GetPosition() == ContentPosition::kNormal &&
408 value.Distribution() == ContentDistributionType::kDefault)
409 ? normal_value_behavior.GetPosition()
410 : value.GetPosition();
411 }
412
ResolvedContentAlignmentDistribution(const StyleContentAlignmentData & value,const StyleContentAlignmentData & normal_value_behavior)413 static inline ContentDistributionType ResolvedContentAlignmentDistribution(
414 const StyleContentAlignmentData& value,
415 const StyleContentAlignmentData& normal_value_behavior) {
416 return (value.GetPosition() == ContentPosition::kNormal &&
417 value.Distribution() == ContentDistributionType::kDefault)
418 ? normal_value_behavior.Distribution()
419 : value.Distribution();
420 }
421
ResolvedJustifyContentPosition(const StyleContentAlignmentData & normal_value_behavior) const422 ContentPosition ComputedStyle::ResolvedJustifyContentPosition(
423 const StyleContentAlignmentData& normal_value_behavior) const {
424 return ResolvedContentAlignmentPosition(JustifyContent(),
425 normal_value_behavior);
426 }
427
ResolvedJustifyContentDistribution(const StyleContentAlignmentData & normal_value_behavior) const428 ContentDistributionType ComputedStyle::ResolvedJustifyContentDistribution(
429 const StyleContentAlignmentData& normal_value_behavior) const {
430 return ResolvedContentAlignmentDistribution(JustifyContent(),
431 normal_value_behavior);
432 }
433
ResolvedAlignContentPosition(const StyleContentAlignmentData & normal_value_behavior) const434 ContentPosition ComputedStyle::ResolvedAlignContentPosition(
435 const StyleContentAlignmentData& normal_value_behavior) const {
436 return ResolvedContentAlignmentPosition(AlignContent(),
437 normal_value_behavior);
438 }
439
ResolvedAlignContentDistribution(const StyleContentAlignmentData & normal_value_behavior) const440 ContentDistributionType ComputedStyle::ResolvedAlignContentDistribution(
441 const StyleContentAlignmentData& normal_value_behavior) const {
442 return ResolvedContentAlignmentDistribution(AlignContent(),
443 normal_value_behavior);
444 }
445
InheritFrom(const ComputedStyle & inherit_parent,IsAtShadowBoundary is_at_shadow_boundary)446 void ComputedStyle::InheritFrom(const ComputedStyle& inherit_parent,
447 IsAtShadowBoundary is_at_shadow_boundary) {
448 EUserModify current_user_modify = UserModify();
449
450 ComputedStyleBase::InheritFrom(inherit_parent, is_at_shadow_boundary);
451 if (svg_style_ != inherit_parent.svg_style_)
452 svg_style_.Access()->InheritFrom(*inherit_parent.svg_style_);
453
454 if (is_at_shadow_boundary == kAtShadowBoundary) {
455 // Even if surrounding content is user-editable, shadow DOM should act as a
456 // single unit, and not necessarily be editable
457 SetUserModify(current_user_modify);
458 }
459 }
460
CopyNonInheritedFromCached(const ComputedStyle & other)461 void ComputedStyle::CopyNonInheritedFromCached(const ComputedStyle& other) {
462 DCHECK(MatchedPropertiesCache::IsStyleCacheable(other));
463
464 ComputedStyleBase::CopyNonInheritedFromCached(other);
465
466 // The flags are copied one-by-one because they contain
467 // bunch of stuff other than real style data.
468 // See comments for each skipped flag below.
469
470 // Correctly set during selector matching:
471 // m_styleType
472 // m_pseudoBits
473
474 // Set correctly while computing style for children:
475 // m_explicitInheritance
476
477 // The following flags are set during matching before we decide that we get a
478 // match in the MatchedPropertiesCache which in turn calls this method. The
479 // reason why we don't copy these flags is that they're already correctly set
480 // and that they may differ between elements which have the same set of
481 // matched properties. For instance, given the rule:
482 //
483 // :-webkit-any(:hover, :focus) { background-color: green }"
484 //
485 // A hovered element, and a focused element may use the same cached matched
486 // properties here, but the affectedBy flags will be set differently based on
487 // the matching order of the :-webkit-any components.
488 //
489 // m_emptyState
490 // m_affectedByFocus
491 // m_affectedByHover
492 // m_affectedByActive
493 // m_affectedByDrag
494 // m_isLink
495
496 if (svg_style_ != other.svg_style_)
497 svg_style_.Access()->CopyNonInheritedFromCached(*other.svg_style_);
498 }
499
operator ==(const ComputedStyle & o) const500 bool ComputedStyle::operator==(const ComputedStyle& o) const {
501 return InheritedEqual(o) && NonInheritedEqual(o);
502 }
503
GetCachedPseudoElementStyle(PseudoId pid) const504 const ComputedStyle* ComputedStyle::GetCachedPseudoElementStyle(
505 PseudoId pid) const {
506 if (!cached_pseudo_element_styles_ || !cached_pseudo_element_styles_->size())
507 return nullptr;
508
509 if (StyleType() != kPseudoIdNone)
510 return nullptr;
511
512 for (const auto& pseudo_style : *cached_pseudo_element_styles_) {
513 if (pseudo_style->StyleType() == pid)
514 return pseudo_style.get();
515 }
516
517 return nullptr;
518 }
519
CachedPseudoElementStylesDependOnFontMetrics() const520 bool ComputedStyle::CachedPseudoElementStylesDependOnFontMetrics() const {
521 if (!cached_pseudo_element_styles_ || !cached_pseudo_element_styles_->size())
522 return false;
523
524 DCHECK_EQ(StyleType(), kPseudoIdNone);
525
526 for (const auto& pseudo_style : *cached_pseudo_element_styles_) {
527 if (pseudo_style->DependsOnFontMetrics())
528 return true;
529 }
530
531 return false;
532 }
533
AddCachedPseudoElementStyle(scoped_refptr<const ComputedStyle> pseudo) const534 const ComputedStyle* ComputedStyle::AddCachedPseudoElementStyle(
535 scoped_refptr<const ComputedStyle> pseudo) const {
536 DCHECK(pseudo);
537 DCHECK_GT(pseudo->StyleType(), kPseudoIdNone);
538
539 const ComputedStyle* result = pseudo.get();
540
541 if (!cached_pseudo_element_styles_)
542 cached_pseudo_element_styles_ = std::make_unique<PseudoElementStyleCache>();
543
544 cached_pseudo_element_styles_->push_back(std::move(pseudo));
545
546 return result;
547 }
548
InheritedEqual(const ComputedStyle & other) const549 bool ComputedStyle::InheritedEqual(const ComputedStyle& other) const {
550 return IndependentInheritedEqual(other) &&
551 NonIndependentInheritedEqual(other);
552 }
553
IndependentInheritedEqual(const ComputedStyle & other) const554 bool ComputedStyle::IndependentInheritedEqual(
555 const ComputedStyle& other) const {
556 return ComputedStyleBase::IndependentInheritedEqual(other);
557 }
558
NonIndependentInheritedEqual(const ComputedStyle & other) const559 bool ComputedStyle::NonIndependentInheritedEqual(
560 const ComputedStyle& other) const {
561 return ComputedStyleBase::NonIndependentInheritedEqual(other) &&
562 svg_style_->InheritedEqual(*other.svg_style_);
563 }
564
NonInheritedEqual(const ComputedStyle & other) const565 bool ComputedStyle::NonInheritedEqual(const ComputedStyle& other) const {
566 // compare everything except the pseudoStyle pointer
567 return ComputedStyleBase::NonInheritedEqual(other) &&
568 svg_style_->NonInheritedEqual(*other.svg_style_);
569 }
570
InheritedDataShared(const ComputedStyle & other) const571 bool ComputedStyle::InheritedDataShared(const ComputedStyle& other) const {
572 // This is a fast check that only looks if the data structures are shared.
573 return ComputedStyleBase::InheritedDataShared(other) &&
574 svg_style_.Get() == other.svg_style_.Get();
575 }
576
DependenceOnContentHeightHasChanged(const ComputedStyle & a,const ComputedStyle & b)577 static bool DependenceOnContentHeightHasChanged(const ComputedStyle& a,
578 const ComputedStyle& b) {
579 // If top or bottom become auto/non-auto then it means we either have to solve
580 // height based on the content or stop doing so
581 // (http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height)
582 // - either way requires a layout.
583 return a.LogicalTop().IsAuto() != b.LogicalTop().IsAuto() ||
584 a.LogicalBottom().IsAuto() != b.LogicalBottom().IsAuto();
585 }
586
VisualInvalidationDiff(const Document & document,const ComputedStyle & other) const587 StyleDifference ComputedStyle::VisualInvalidationDiff(
588 const Document& document,
589 const ComputedStyle& other) const {
590 // Note, we use .Get() on each DataRef below because DataRef::operator== will
591 // do a deep compare, which is duplicate work when we're going to compare each
592 // property inside this function anyway.
593
594 StyleDifference diff;
595 if (svg_style_.Get() != other.svg_style_.Get())
596 diff = svg_style_->Diff(*other.svg_style_);
597
598 if ((!diff.NeedsReshape() || !diff.NeedsFullLayout() ||
599 !diff.NeedsPaintInvalidation()) &&
600 DiffNeedsReshapeAndFullLayoutAndPaintInvalidation(*this, other)) {
601 diff.SetNeedsReshape();
602 diff.SetNeedsFullLayout();
603 diff.SetNeedsPaintInvalidation();
604 }
605
606 if ((!diff.NeedsFullLayout() || !diff.NeedsPaintInvalidation()) &&
607 DiffNeedsFullLayoutAndPaintInvalidation(other)) {
608 diff.SetNeedsFullLayout();
609 diff.SetNeedsPaintInvalidation();
610 }
611
612 if (!diff.NeedsFullLayout() && DiffNeedsFullLayout(document, other))
613 diff.SetNeedsFullLayout();
614
615 if (!diff.NeedsFullLayout() && !MarginEqual(other)) {
616 // Relative-positioned elements collapse their margins so need a full
617 // layout.
618 if (HasOutOfFlowPosition())
619 diff.SetNeedsPositionedMovementLayout();
620 else
621 diff.SetNeedsFullLayout();
622 }
623
624 if (!diff.NeedsFullLayout() && GetPosition() != EPosition::kStatic &&
625 !OffsetEqual(other)) {
626 // Optimize for the case where a positioned layer is moving but not changing
627 // size.
628 if (DependenceOnContentHeightHasChanged(*this, other))
629 diff.SetNeedsFullLayout();
630 else
631 diff.SetNeedsPositionedMovementLayout();
632 }
633
634 AdjustDiffForNeedsPaintInvalidation(other, diff, document);
635
636 if (DiffNeedsVisualRectUpdate(other))
637 diff.SetNeedsVisualRectUpdate();
638
639 UpdatePropertySpecificDifferences(other, diff);
640
641 // The following condition needs to be at last, because it may depend on
642 // conditions in diff computed above.
643 if (ScrollAnchorDisablingPropertyChanged(other, diff))
644 diff.SetScrollAnchorDisablingPropertyChanged();
645
646 // Cursors are not checked, since they will be set appropriately in response
647 // to mouse events, so they don't need to cause any paint invalidation or
648 // layout.
649
650 // Animations don't need to be checked either. We always set the new style on
651 // the layoutObject, so we will get a chance to fire off the resulting
652 // transition properly.
653
654 return diff;
655 }
656
ScrollAnchorDisablingPropertyChanged(const ComputedStyle & other,const StyleDifference & diff) const657 bool ComputedStyle::ScrollAnchorDisablingPropertyChanged(
658 const ComputedStyle& other,
659 const StyleDifference& diff) const {
660 if (ComputedStyleBase::ScrollAnchorDisablingPropertyChanged(*this, other))
661 return true;
662
663 if (diff.TransformChanged())
664 return true;
665
666 return false;
667 }
668
DiffNeedsFullLayoutAndPaintInvalidation(const ComputedStyle & other) const669 bool ComputedStyle::DiffNeedsFullLayoutAndPaintInvalidation(
670 const ComputedStyle& other) const {
671 // FIXME: Not all cases in this method need both full layout and paint
672 // invalidation.
673 // Should move cases into DiffNeedsFullLayout() if
674 // - don't need paint invalidation at all;
675 // - or the layoutObject knows how to exactly invalidate paints caused by the
676 // layout change instead of forced full paint invalidation.
677
678 if (ComputedStyleBase::DiffNeedsFullLayoutAndPaintInvalidation(*this, other))
679 return true;
680
681 if (IsDisplayTableType(Display())) {
682 if (ComputedStyleBase::
683 DiffNeedsFullLayoutAndPaintInvalidationDisplayTableType(*this,
684 other))
685 return true;
686
687 // In the collapsing border model, 'hidden' suppresses other borders, while
688 // 'none' does not, so these style differences can be width differences.
689 if ((BorderCollapse() == EBorderCollapse::kCollapse) &&
690 ((BorderTopStyle() == EBorderStyle::kHidden &&
691 other.BorderTopStyle() == EBorderStyle::kNone) ||
692 (BorderTopStyle() == EBorderStyle::kNone &&
693 other.BorderTopStyle() == EBorderStyle::kHidden) ||
694 (BorderBottomStyle() == EBorderStyle::kHidden &&
695 other.BorderBottomStyle() == EBorderStyle::kNone) ||
696 (BorderBottomStyle() == EBorderStyle::kNone &&
697 other.BorderBottomStyle() == EBorderStyle::kHidden) ||
698 (BorderLeftStyle() == EBorderStyle::kHidden &&
699 other.BorderLeftStyle() == EBorderStyle::kNone) ||
700 (BorderLeftStyle() == EBorderStyle::kNone &&
701 other.BorderLeftStyle() == EBorderStyle::kHidden) ||
702 (BorderRightStyle() == EBorderStyle::kHidden &&
703 other.BorderRightStyle() == EBorderStyle::kNone) ||
704 (BorderRightStyle() == EBorderStyle::kNone &&
705 other.BorderRightStyle() == EBorderStyle::kHidden)))
706 return true;
707 } else if (Display() == EDisplay::kListItem) {
708 if (ComputedStyleBase::
709 DiffNeedsFullLayoutAndPaintInvalidationDisplayListItem(*this,
710 other))
711 return true;
712 }
713
714 if ((Visibility() == EVisibility::kCollapse) !=
715 (other.Visibility() == EVisibility::kCollapse))
716 return true;
717
718 // Movement of non-static-positioned object is special cased in
719 // ComputedStyle::VisualInvalidationDiff().
720
721 return false;
722 }
723
DiffNeedsFullLayout(const Document & document,const ComputedStyle & other) const724 bool ComputedStyle::DiffNeedsFullLayout(const Document& document,
725 const ComputedStyle& other) const {
726 if (ComputedStyleBase::DiffNeedsFullLayout(*this, other))
727 return true;
728
729 if (IsDisplayLayoutCustomBox()) {
730 if (DiffNeedsFullLayoutForLayoutCustom(document, other))
731 return true;
732 }
733
734 if (DisplayLayoutCustomParentName()) {
735 if (DiffNeedsFullLayoutForLayoutCustomChild(document, other))
736 return true;
737 }
738
739 return false;
740 }
741
DiffNeedsFullLayoutForLayoutCustom(const Document & document,const ComputedStyle & other) const742 bool ComputedStyle::DiffNeedsFullLayoutForLayoutCustom(
743 const Document& document,
744 const ComputedStyle& other) const {
745 DCHECK(IsDisplayLayoutCustomBox());
746
747 LayoutWorklet* worklet = LayoutWorklet::From(*document.domWindow());
748 const AtomicString& name = DisplayLayoutCustomName();
749
750 if (!worklet->GetDocumentDefinitionMap()->Contains(name))
751 return false;
752
753 const DocumentLayoutDefinition* definition =
754 worklet->GetDocumentDefinitionMap()->at(name);
755 if (definition == kInvalidDocumentLayoutDefinition)
756 return false;
757
758 if (!PropertiesEqual(definition->NativeInvalidationProperties(), other))
759 return true;
760
761 if (!CustomPropertiesEqual(definition->CustomInvalidationProperties(), other))
762 return true;
763
764 return false;
765 }
766
DiffNeedsFullLayoutForLayoutCustomChild(const Document & document,const ComputedStyle & other) const767 bool ComputedStyle::DiffNeedsFullLayoutForLayoutCustomChild(
768 const Document& document,
769 const ComputedStyle& other) const {
770 LayoutWorklet* worklet = LayoutWorklet::From(*document.domWindow());
771 const AtomicString& name = DisplayLayoutCustomParentName();
772
773 if (!worklet->GetDocumentDefinitionMap()->Contains(name))
774 return false;
775
776 const DocumentLayoutDefinition* definition =
777 worklet->GetDocumentDefinitionMap()->at(name);
778 if (definition == kInvalidDocumentLayoutDefinition)
779 return false;
780
781 if (!PropertiesEqual(definition->ChildNativeInvalidationProperties(), other))
782 return true;
783
784 if (!CustomPropertiesEqual(definition->ChildCustomInvalidationProperties(),
785 other))
786 return true;
787
788 return false;
789 }
790
AdjustDiffForNeedsPaintInvalidation(const ComputedStyle & other,StyleDifference & diff,const Document & document) const791 void ComputedStyle::AdjustDiffForNeedsPaintInvalidation(
792 const ComputedStyle& other,
793 StyleDifference& diff,
794 const Document& document) const {
795 if (ComputedStyleBase::DiffNeedsPaintInvalidation(*this, other) ||
796 !BorderVisuallyEqual(other) || !RadiiEqual(other))
797 diff.SetNeedsPaintInvalidation();
798
799 AdjustDiffForBackgroundVisuallyEqual(other, diff);
800
801 if (diff.NeedsPaintInvalidation())
802 return;
803
804 if (PaintImagesInternal()) {
805 for (const auto& image : *PaintImagesInternal()) {
806 DCHECK(image);
807 if (DiffNeedsPaintInvalidationForPaintImage(*image, other, document)) {
808 diff.SetNeedsPaintInvalidation();
809 return;
810 }
811 }
812 }
813 }
814
AdjustDiffForBackgroundVisuallyEqual(const ComputedStyle & other,StyleDifference & diff) const815 void ComputedStyle::AdjustDiffForBackgroundVisuallyEqual(
816 const ComputedStyle& other,
817 StyleDifference& diff) const {
818 if (BackgroundColorInternal() != other.BackgroundColorInternal()) {
819 diff.SetNeedsPaintInvalidation();
820 if (BackgroundColorInternal()
821 .Resolve(GetCurrentColor(), UsedColorScheme())
822 .HasAlpha() !=
823 other.BackgroundColorInternal()
824 .Resolve(other.GetCurrentColor(), other.UsedColorScheme())
825 .HasAlpha()) {
826 diff.SetHasAlphaChanged();
827 return;
828 }
829 }
830 if (!BackgroundInternal().VisuallyEqual(other.BackgroundInternal())) {
831 diff.SetNeedsPaintInvalidation();
832 // Changes of background fill layers, such as images, may have
833 // changed alpha.
834 diff.SetHasAlphaChanged();
835 }
836 }
837
DiffNeedsPaintInvalidationForPaintImage(const StyleImage & image,const ComputedStyle & other,const Document & document) const838 bool ComputedStyle::DiffNeedsPaintInvalidationForPaintImage(
839 const StyleImage& image,
840 const ComputedStyle& other,
841 const Document& document) const {
842 // https://crbug.com/835589: early exit when paint target is associated with
843 // a link.
844 if (InsideLink() != EInsideLink::kNotInsideLink)
845 return false;
846
847 CSSPaintValue* value = To<CSSPaintValue>(image.CssValue());
848
849 // NOTE: If the invalidation properties vectors are null, we are invalid as
850 // we haven't yet been painted (and can't provide the invalidation
851 // properties yet).
852 if (!value->NativeInvalidationProperties(document) ||
853 !value->CustomInvalidationProperties(document))
854 return true;
855
856 if (!PropertiesEqual(*value->NativeInvalidationProperties(document), other))
857 return true;
858
859 if (!CustomPropertiesEqual(*value->CustomInvalidationProperties(document),
860 other))
861 return true;
862
863 return false;
864 }
865
PropertiesEqual(const Vector<CSSPropertyID> & properties,const ComputedStyle & other) const866 bool ComputedStyle::PropertiesEqual(const Vector<CSSPropertyID>& properties,
867 const ComputedStyle& other) const {
868 for (CSSPropertyID property_id : properties) {
869 // TODO(ikilpatrick): remove IsInterpolableProperty check once
870 // CSSPropertyEquality::PropertiesEqual correctly handles all properties.
871 const CSSProperty& property = CSSProperty::Get(property_id);
872 if (!property.IsInterpolable() ||
873 !CSSPropertyEquality::PropertiesEqual(PropertyHandle(property), *this,
874 other))
875 return false;
876 }
877
878 return true;
879 }
880
CustomPropertiesEqual(const Vector<AtomicString> & properties,const ComputedStyle & other) const881 bool ComputedStyle::CustomPropertiesEqual(
882 const Vector<AtomicString>& properties,
883 const ComputedStyle& other) const {
884 // Short-circuit if neither of the styles have custom properties.
885 if (!HasVariables() && !other.HasVariables())
886 return true;
887
888 for (const AtomicString& property_name : properties) {
889 if (!DataEquivalent(GetVariableData(property_name),
890 other.GetVariableData(property_name))) {
891 return false;
892 }
893 if (!DataEquivalent(GetVariableValue(property_name),
894 other.GetVariableValue(property_name))) {
895 return false;
896 }
897 }
898
899 return true;
900 }
901
902 // This doesn't include conditions needing layout or overflow recomputation
903 // which implies visual rect update.
DiffNeedsVisualRectUpdate(const ComputedStyle & other) const904 bool ComputedStyle::DiffNeedsVisualRectUpdate(
905 const ComputedStyle& other) const {
906 // Visual rect is empty if visibility is hidden. Also need to update visual
907 // rect of the resizer.
908 return ComputedStyleBase::DiffNeedsVisualRectUpdate(*this, other);
909 }
910
UpdatePropertySpecificDifferences(const ComputedStyle & other,StyleDifference & diff) const911 void ComputedStyle::UpdatePropertySpecificDifferences(
912 const ComputedStyle& other,
913 StyleDifference& diff) const {
914 if (ComputedStyleBase::UpdatePropertySpecificDifferencesZIndex(*this, other))
915 diff.SetZIndexChanged();
916
917 if (UpdatePropertySpecificDifferencesTransform(*this, other))
918 diff.SetTransformChanged();
919
920 if (ComputedStyleBase::UpdatePropertySpecificDifferencesOpacity(*this, other))
921 diff.SetOpacityChanged();
922
923 if (ComputedStyleBase::UpdatePropertySpecificDifferencesFilter(*this, other))
924 diff.SetFilterChanged();
925
926 if (ComputedStyleBase::
927 UpdatePropertySpecificDifferencesNeedsRecomputeVisualOverflow(*this,
928 other))
929 diff.SetNeedsRecomputeVisualOverflow();
930
931 if (!diff.NeedsPaintInvalidation() &&
932 ComputedStyleBase::UpdatePropertySpecificDifferencesTextDecorationOrColor(
933 *this, other)) {
934 diff.SetTextDecorationOrColorChanged();
935 }
936
937 if (ComputedStyleBase::UpdatePropertySpecificDifferencesMask(*this, other))
938 diff.SetMaskChanged();
939
940 bool has_clip = HasOutOfFlowPosition() && !HasAutoClip();
941 bool other_has_clip = other.HasOutOfFlowPosition() && !other.HasAutoClip();
942 if (has_clip != other_has_clip ||
943 (has_clip && Clip() != other.Clip()))
944 diff.SetCSSClipChanged();
945
946 if (GetBlendMode() != other.GetBlendMode())
947 diff.SetBlendModeChanged();
948
949 if (HasCurrentTransformAnimation() != other.HasCurrentTransformAnimation() ||
950 HasCurrentOpacityAnimation() != other.HasCurrentOpacityAnimation() ||
951 HasCurrentFilterAnimation() != other.HasCurrentFilterAnimation() ||
952 HasCurrentBackdropFilterAnimation() !=
953 other.HasCurrentBackdropFilterAnimation() ||
954 SubtreeWillChangeContents() != other.SubtreeWillChangeContents() ||
955 BackfaceVisibility() != other.BackfaceVisibility() ||
956 UsedTransformStyle3D() != other.UsedTransformStyle3D() ||
957 ContainsPaint() != other.ContainsPaint() ||
958 IsOverflowVisibleAlongBothAxes() !=
959 other.IsOverflowVisibleAlongBothAxes() ||
960 WillChangeProperties() != other.WillChangeProperties() ||
961 !BackdropFilterDataEquivalent(other)) {
962 diff.SetCompositingReasonsChanged();
963 }
964 }
965
AddPaintImage(StyleImage * image)966 void ComputedStyle::AddPaintImage(StyleImage* image) {
967 if (!MutablePaintImagesInternal()) {
968 SetPaintImagesInternal(std::make_unique<PaintImages>());
969 }
970 MutablePaintImagesInternal()->push_back(image);
971 }
972
HasCSSPaintImagesUsingCustomProperty(const AtomicString & custom_property_name,const Document & document) const973 bool ComputedStyle::HasCSSPaintImagesUsingCustomProperty(
974 const AtomicString& custom_property_name,
975 const Document& document) const {
976 if (PaintImagesInternal()) {
977 for (const auto& image : *PaintImagesInternal()) {
978 DCHECK(image);
979 // IsPaintImage is true for CSS Paint images only, please refer to the
980 // constructor of StyleGeneratedImage.
981 if (image->IsPaintImage()) {
982 return To<StyleGeneratedImage>(image.Get())
983 ->IsUsingCustomProperty(custom_property_name, document);
984 }
985 }
986 }
987 return false;
988 }
989
AddCursor(StyleImage * image,bool hot_spot_specified,const IntPoint & hot_spot)990 void ComputedStyle::AddCursor(StyleImage* image,
991 bool hot_spot_specified,
992 const IntPoint& hot_spot) {
993 if (!CursorDataInternal())
994 SetCursorDataInternal(MakeGarbageCollected<CursorList>());
995 MutableCursorDataInternal()->push_back(
996 CursorData(image, hot_spot_specified, hot_spot));
997 }
998
SetCursorList(CursorList * other)999 void ComputedStyle::SetCursorList(CursorList* other) {
1000 SetCursorDataInternal(other);
1001 }
1002
QuotesDataEquivalent(const ComputedStyle & other) const1003 bool ComputedStyle::QuotesDataEquivalent(const ComputedStyle& other) const {
1004 return DataEquivalent(Quotes(), other.Quotes());
1005 }
1006
ClearCursorList()1007 void ComputedStyle::ClearCursorList() {
1008 if (CursorDataInternal())
1009 SetCursorDataInternal(nullptr);
1010 }
1011
HasPropertyThatCreatesStackingContext(const Vector<CSSPropertyID> & properties)1012 static bool HasPropertyThatCreatesStackingContext(
1013 const Vector<CSSPropertyID>& properties) {
1014 for (CSSPropertyID property : properties) {
1015 switch (property) {
1016 case CSSPropertyID::kOpacity:
1017 case CSSPropertyID::kTransform:
1018 case CSSPropertyID::kAliasWebkitTransform:
1019 case CSSPropertyID::kTransformStyle:
1020 case CSSPropertyID::kAliasWebkitTransformStyle:
1021 case CSSPropertyID::kPerspective:
1022 case CSSPropertyID::kAliasWebkitPerspective:
1023 case CSSPropertyID::kTranslate:
1024 case CSSPropertyID::kRotate:
1025 case CSSPropertyID::kScale:
1026 case CSSPropertyID::kOffsetPath:
1027 case CSSPropertyID::kOffsetPosition:
1028 case CSSPropertyID::kWebkitMask:
1029 case CSSPropertyID::kWebkitMaskBoxImage:
1030 case CSSPropertyID::kClipPath:
1031 case CSSPropertyID::kAliasWebkitClipPath:
1032 case CSSPropertyID::kWebkitBoxReflect:
1033 case CSSPropertyID::kFilter:
1034 case CSSPropertyID::kAliasWebkitFilter:
1035 case CSSPropertyID::kBackdropFilter:
1036 case CSSPropertyID::kZIndex:
1037 case CSSPropertyID::kPosition:
1038 case CSSPropertyID::kMixBlendMode:
1039 case CSSPropertyID::kIsolation:
1040 case CSSPropertyID::kContain:
1041 return true;
1042 default:
1043 break;
1044 }
1045 }
1046 return false;
1047 }
1048
UpdateIsStackingContextWithoutContainment(bool is_document_element,bool is_in_top_layer,bool is_svg_stacking)1049 void ComputedStyle::UpdateIsStackingContextWithoutContainment(
1050 bool is_document_element,
1051 bool is_in_top_layer,
1052 bool is_svg_stacking) {
1053 if (IsStackingContextWithoutContainment())
1054 return;
1055
1056 // Force a stacking context for transform-style: preserve-3d. This happens
1057 // even if preserves-3d is ignored due to a 'grouping property' being present
1058 // which requires flattening. See:
1059 // ComputedStyle::HasGroupingPropertyForUsedTransformStyle3D().
1060 // This is legacy behavior that is left ambiguous in the official specs.
1061 // See https://crbug.com/663650 for more details.
1062 if (TransformStyle3D() == ETransformStyle3D::kPreserve3d) {
1063 SetIsStackingContextWithoutContainment(true);
1064 return;
1065 }
1066
1067 if (is_document_element || is_in_top_layer || is_svg_stacking ||
1068 StyleType() == kPseudoIdBackdrop || HasTransformRelatedProperty() ||
1069 HasStackingGroupingProperty(BoxReflect()) ||
1070 HasViewportConstrainedPosition() || GetPosition() == EPosition::kSticky ||
1071 HasPropertyThatCreatesStackingContext(WillChangeProperties()) ||
1072 /* TODO(882625): This becomes unnecessary when will-change correctly takes
1073 into account active animations. */
1074 ShouldCompositeForCurrentAnimations()) {
1075 SetIsStackingContextWithoutContainment(true);
1076 }
1077 }
1078
AddCallbackSelector(const String & selector)1079 void ComputedStyle::AddCallbackSelector(const String& selector) {
1080 if (!CallbackSelectors().Contains(selector))
1081 MutableCallbackSelectorsInternal().push_back(selector);
1082 }
1083
SetContent(ContentData * content_data)1084 void ComputedStyle::SetContent(ContentData* content_data) {
1085 SetContentInternal(content_data);
1086 }
1087
IsWillChangeTransformHintProperty(CSSPropertyID property)1088 static bool IsWillChangeTransformHintProperty(CSSPropertyID property) {
1089 switch (property) {
1090 case CSSPropertyID::kTransform:
1091 case CSSPropertyID::kAliasWebkitTransform:
1092 case CSSPropertyID::kPerspective:
1093 case CSSPropertyID::kTranslate:
1094 case CSSPropertyID::kScale:
1095 case CSSPropertyID::kRotate:
1096 case CSSPropertyID::kOffsetPath:
1097 case CSSPropertyID::kOffsetPosition:
1098 return true;
1099 default:
1100 break;
1101 }
1102 return false;
1103 }
1104
IsWillChangeCompositingHintProperty(CSSPropertyID property)1105 static bool IsWillChangeCompositingHintProperty(CSSPropertyID property) {
1106 if (IsWillChangeTransformHintProperty(property))
1107 return true;
1108 switch (property) {
1109 case CSSPropertyID::kOpacity:
1110 case CSSPropertyID::kFilter:
1111 case CSSPropertyID::kAliasWebkitFilter:
1112 case CSSPropertyID::kBackdropFilter:
1113 case CSSPropertyID::kTop:
1114 case CSSPropertyID::kLeft:
1115 case CSSPropertyID::kBottom:
1116 case CSSPropertyID::kRight:
1117 return true;
1118 default:
1119 break;
1120 }
1121 return false;
1122 }
1123
HasWillChangeCompositingHint() const1124 bool ComputedStyle::HasWillChangeCompositingHint() const {
1125 const auto& properties = WillChangeProperties();
1126 return std::any_of(properties.begin(), properties.end(),
1127 IsWillChangeCompositingHintProperty);
1128 }
1129
HasWillChangeTransformHint() const1130 bool ComputedStyle::HasWillChangeTransformHint() const {
1131 const auto& properties = WillChangeProperties();
1132 return std::any_of(properties.begin(), properties.end(),
1133 IsWillChangeTransformHintProperty);
1134 }
1135
RequireTransformOrigin(ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path) const1136 bool ComputedStyle::RequireTransformOrigin(
1137 ApplyTransformOrigin apply_origin,
1138 ApplyMotionPath apply_motion_path) const {
1139 // transform-origin brackets the transform with translate operations.
1140 // Optimize for the case where the only transform is a translation, since the
1141 // transform-origin is irrelevant in that case.
1142 if (apply_origin != kIncludeTransformOrigin)
1143 return false;
1144
1145 if (apply_motion_path == kIncludeMotionPath)
1146 return true;
1147
1148 for (const auto& operation : Transform().Operations()) {
1149 TransformOperation::OperationType type = operation->GetType();
1150 if (type != TransformOperation::kTranslateX &&
1151 type != TransformOperation::kTranslateY &&
1152 type != TransformOperation::kTranslate &&
1153 type != TransformOperation::kTranslateZ &&
1154 type != TransformOperation::kTranslate3D)
1155 return true;
1156 }
1157
1158 return Scale() || Rotate();
1159 }
1160
GetInterpolationQuality() const1161 InterpolationQuality ComputedStyle::GetInterpolationQuality() const {
1162 if (ImageRendering() == EImageRendering::kPixelated)
1163 return kInterpolationNone;
1164
1165 if (ImageRendering() == EImageRendering::kWebkitOptimizeContrast)
1166 return kInterpolationLow;
1167
1168 return kInterpolationDefault;
1169 }
1170
LoadDeferredImages(Document & document) const1171 void ComputedStyle::LoadDeferredImages(Document& document) const {
1172 if (HasBackgroundImage()) {
1173 for (const FillLayer* background_layer = &BackgroundLayers();
1174 background_layer; background_layer = background_layer->Next()) {
1175 if (StyleImage* image = background_layer->GetImage()) {
1176 if (image->IsImageResource() && image->IsLazyloadPossiblyDeferred())
1177 To<StyleFetchedImage>(image)->LoadDeferredImage(document);
1178 }
1179 }
1180 }
1181 }
1182
ApplyTransform(TransformationMatrix & result,const LayoutSize & border_box_size,ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path,ApplyIndependentTransformProperties apply_independent_transform_properties) const1183 void ComputedStyle::ApplyTransform(
1184 TransformationMatrix& result,
1185 const LayoutSize& border_box_size,
1186 ApplyTransformOrigin apply_origin,
1187 ApplyMotionPath apply_motion_path,
1188 ApplyIndependentTransformProperties apply_independent_transform_properties)
1189 const {
1190 ApplyTransform(result, FloatRect(FloatPoint(), FloatSize(border_box_size)),
1191 apply_origin, apply_motion_path,
1192 apply_independent_transform_properties);
1193 }
1194
ApplyTransform(TransformationMatrix & result,const FloatRect & bounding_box,ApplyTransformOrigin apply_origin,ApplyMotionPath apply_motion_path,ApplyIndependentTransformProperties apply_independent_transform_properties) const1195 void ComputedStyle::ApplyTransform(
1196 TransformationMatrix& result,
1197 const FloatRect& bounding_box,
1198 ApplyTransformOrigin apply_origin,
1199 ApplyMotionPath apply_motion_path,
1200 ApplyIndependentTransformProperties apply_independent_transform_properties)
1201 const {
1202 if (!HasOffset())
1203 apply_motion_path = kExcludeMotionPath;
1204 bool apply_transform_origin =
1205 RequireTransformOrigin(apply_origin, apply_motion_path);
1206
1207 float origin_x = 0;
1208 float origin_y = 0;
1209 float origin_z = 0;
1210
1211 const FloatSize& box_size = bounding_box.Size();
1212 if (apply_transform_origin ||
1213 // We need to calculate originX and originY for applying motion path.
1214 apply_motion_path == kIncludeMotionPath) {
1215 origin_x = FloatValueForLength(TransformOriginX(), box_size.Width()) +
1216 bounding_box.X();
1217 origin_y = FloatValueForLength(TransformOriginY(), box_size.Height()) +
1218 bounding_box.Y();
1219 if (apply_transform_origin) {
1220 origin_z = TransformOriginZ();
1221 result.Translate3d(origin_x, origin_y, origin_z);
1222 }
1223 }
1224
1225 if (apply_independent_transform_properties ==
1226 kIncludeIndependentTransformProperties) {
1227 if (Translate())
1228 Translate()->Apply(result, box_size);
1229
1230 if (Rotate())
1231 Rotate()->Apply(result, box_size);
1232
1233 if (Scale())
1234 Scale()->Apply(result, box_size);
1235 }
1236
1237 if (apply_motion_path == kIncludeMotionPath)
1238 ApplyMotionPathTransform(origin_x, origin_y, bounding_box, result);
1239
1240 for (const auto& operation : Transform().Operations())
1241 operation->Apply(result, box_size);
1242
1243 if (apply_transform_origin) {
1244 result.Translate3d(-origin_x, -origin_y, -origin_z);
1245 }
1246 }
1247
HasFilters() const1248 bool ComputedStyle::HasFilters() const {
1249 return FilterInternal().Get() && !FilterInternal()->operations_.IsEmpty();
1250 }
1251
ApplyMotionPathTransform(float origin_x,float origin_y,const FloatRect & bounding_box,TransformationMatrix & transform) const1252 void ComputedStyle::ApplyMotionPathTransform(
1253 float origin_x,
1254 float origin_y,
1255 const FloatRect& bounding_box,
1256 TransformationMatrix& transform) const {
1257 // TODO(ericwilligers): crbug.com/638055 Apply offset-position.
1258 if (!OffsetPath()) {
1259 return;
1260 }
1261 const LengthPoint& position = OffsetPosition();
1262 const LengthPoint& anchor = OffsetAnchor();
1263 const Length& distance = OffsetDistance();
1264 const BasicShape* path = OffsetPath();
1265 const StyleOffsetRotation& rotate = OffsetRotate();
1266
1267 FloatPoint point;
1268 float angle;
1269 if (path->GetType() == BasicShape::kStyleRayType) {
1270 // TODO(ericwilligers): crbug.com/641245 Support <size> for ray paths.
1271 float float_distance = FloatValueForLength(distance, 0);
1272
1273 angle = To<StyleRay>(*path).Angle() - 90;
1274 point.SetX(float_distance * cos(deg2rad(angle)));
1275 point.SetY(float_distance * sin(deg2rad(angle)));
1276 } else {
1277 float zoom = EffectiveZoom();
1278 const StylePath& motion_path = To<StylePath>(*path);
1279 float path_length = motion_path.length();
1280 float float_distance =
1281 FloatValueForLength(distance, path_length * zoom) / zoom;
1282 float computed_distance;
1283 if (motion_path.IsClosed() && path_length > 0) {
1284 computed_distance = fmod(float_distance, path_length);
1285 if (computed_distance < 0)
1286 computed_distance += path_length;
1287 } else {
1288 computed_distance = clampTo<float>(float_distance, 0, path_length);
1289 }
1290
1291 motion_path.GetPath().PointAndNormalAtLength(computed_distance, point,
1292 angle);
1293
1294 point.Scale(zoom, zoom);
1295 }
1296
1297 if (rotate.type == OffsetRotationType::kFixed)
1298 angle = 0;
1299
1300 float origin_shift_x = 0;
1301 float origin_shift_y = 0;
1302 // If the offset-position and offset-anchor properties are not yet enabled,
1303 // they will have the default value, auto.
1304 FloatPoint anchor_point(origin_x, origin_y);
1305 if (!position.X().IsAuto() || !anchor.X().IsAuto()) {
1306 anchor_point = FloatPointForLengthPoint(anchor, bounding_box.Size());
1307 anchor_point += bounding_box.Location();
1308
1309 // Shift the origin from transform-origin to offset-anchor.
1310 origin_shift_x = anchor_point.X() - origin_x;
1311 origin_shift_y = anchor_point.Y() - origin_y;
1312 }
1313
1314 transform.Translate(point.X() - anchor_point.X() + origin_shift_x,
1315 point.Y() - anchor_point.Y() + origin_shift_y);
1316 transform.Rotate(angle + rotate.angle);
1317
1318 if (!position.X().IsAuto() || !anchor.X().IsAuto())
1319 // Shift the origin back to transform-origin.
1320 transform.Translate(-origin_shift_x, -origin_shift_y);
1321 }
1322
TextShadowDataEquivalent(const ComputedStyle & other) const1323 bool ComputedStyle::TextShadowDataEquivalent(const ComputedStyle& other) const {
1324 return DataEquivalent(TextShadow(), other.TextShadow());
1325 }
1326
ListStyleImage() const1327 StyleImage* ComputedStyle::ListStyleImage() const {
1328 return ListStyleImageInternal();
1329 }
SetListStyleImage(StyleImage * v)1330 void ComputedStyle::SetListStyleImage(StyleImage* v) {
1331 SetListStyleImageInternal(v);
1332 }
1333
SetEffectiveZoom(float f)1334 bool ComputedStyle::SetEffectiveZoom(float f) {
1335 // Clamp the effective zoom value to a smaller (but hopeful still large
1336 // enough) range, to avoid overflow in derived computations.
1337 float clamped_effective_zoom = clampTo<float>(f, 1e-6, 1e6);
1338 if (EffectiveZoom() == clamped_effective_zoom)
1339 return false;
1340 SetEffectiveZoomInternal(clamped_effective_zoom);
1341 // Record UMA for the effective zoom in order to assess the relative
1342 // importance of sub-pixel behavior, and related features and bugs.
1343 // Clamp to a max of 400%, to make the histogram behave better at no
1344 // real cost to our understanding of the zooms in use.
1345 base::UmaHistogramSparse(
1346 "Blink.EffectiveZoom",
1347 base::ClampToRange<float>(clamped_effective_zoom * 100, 0, 400));
1348 return true;
1349 }
1350
CanRenderBorderImage() const1351 bool ComputedStyle::CanRenderBorderImage() const {
1352 if (!HasBorderDecoration())
1353 return false;
1354
1355 StyleImage* border_image = BorderImage().GetImage();
1356 return border_image && border_image->CanRender() && border_image->IsLoaded();
1357 }
1358
GetCounterDirectives() const1359 const CounterDirectiveMap* ComputedStyle::GetCounterDirectives() const {
1360 return CounterDirectivesInternal().get();
1361 }
1362
AccessCounterDirectives()1363 CounterDirectiveMap& ComputedStyle::AccessCounterDirectives() {
1364 std::unique_ptr<CounterDirectiveMap>& map =
1365 MutableCounterDirectivesInternal();
1366 if (!map)
1367 map = std::make_unique<CounterDirectiveMap>();
1368 return *map;
1369 }
1370
GetCounterDirectives(const AtomicString & identifier) const1371 const CounterDirectives ComputedStyle::GetCounterDirectives(
1372 const AtomicString& identifier) const {
1373 if (const CounterDirectiveMap* directives = GetCounterDirectives())
1374 return directives->at(identifier);
1375 return CounterDirectives();
1376 }
1377
ClearIncrementDirectives()1378 void ComputedStyle::ClearIncrementDirectives() {
1379 if (!GetCounterDirectives())
1380 return;
1381
1382 // This makes us copy even if we may not be removing any items.
1383 CounterDirectiveMap& map = AccessCounterDirectives();
1384 typedef CounterDirectiveMap::iterator Iterator;
1385
1386 Iterator end = map.end();
1387 for (Iterator it = map.begin(); it != end; ++it)
1388 it->value.ClearIncrement();
1389 }
1390
ClearResetDirectives()1391 void ComputedStyle::ClearResetDirectives() {
1392 if (!GetCounterDirectives())
1393 return;
1394
1395 // This makes us copy even if we may not be removing any items.
1396 CounterDirectiveMap& map = AccessCounterDirectives();
1397 typedef CounterDirectiveMap::iterator Iterator;
1398
1399 Iterator end = map.end();
1400 for (Iterator it = map.begin(); it != end; ++it)
1401 it->value.ClearReset();
1402 }
1403
ClearSetDirectives()1404 void ComputedStyle::ClearSetDirectives() {
1405 if (!GetCounterDirectives())
1406 return;
1407
1408 auto& map = AccessCounterDirectives();
1409 for (auto& value_pair : map)
1410 value_pair.value.ClearSet();
1411 }
1412
LocaleForLineBreakIterator() const1413 AtomicString ComputedStyle::LocaleForLineBreakIterator() const {
1414 LineBreakIteratorMode mode = LineBreakIteratorMode::kDefault;
1415 switch (GetLineBreak()) {
1416 case LineBreak::kAuto:
1417 case LineBreak::kAfterWhiteSpace:
1418 case LineBreak::kAnywhere:
1419 return Locale();
1420 case LineBreak::kNormal:
1421 mode = LineBreakIteratorMode::kNormal;
1422 break;
1423 case LineBreak::kStrict:
1424 mode = LineBreakIteratorMode::kStrict;
1425 break;
1426 case LineBreak::kLoose:
1427 mode = LineBreakIteratorMode::kLoose;
1428 break;
1429 }
1430 if (const LayoutLocale* locale = GetFontDescription().Locale())
1431 return locale->LocaleWithBreakKeyword(mode);
1432 return Locale();
1433 }
1434
GetHyphenation() const1435 Hyphenation* ComputedStyle::GetHyphenation() const {
1436 if (GetHyphens() != Hyphens::kAuto)
1437 return nullptr;
1438 if (const LayoutLocale* locale = GetFontDescription().Locale())
1439 return locale->GetHyphenation();
1440 return nullptr;
1441 }
1442
HyphenString() const1443 const AtomicString& ComputedStyle::HyphenString() const {
1444 const AtomicString& hyphenation_string = HyphenationString();
1445 if (!hyphenation_string.IsNull())
1446 return hyphenation_string;
1447
1448 // FIXME: This should depend on locale.
1449 DEFINE_STATIC_LOCAL(AtomicString, hyphen_minus_string,
1450 (&kHyphenMinusCharacter, 1));
1451 DEFINE_STATIC_LOCAL(AtomicString, hyphen_string, (&kHyphenCharacter, 1));
1452 const SimpleFontData* primary_font = GetFont().PrimaryFont();
1453 DCHECK(primary_font);
1454 return primary_font && primary_font->GlyphForCharacter(kHyphenCharacter)
1455 ? hyphen_string
1456 : hyphen_minus_string;
1457 }
1458
GetTextAlign(bool is_last_line) const1459 ETextAlign ComputedStyle::GetTextAlign(bool is_last_line) const {
1460 if (!is_last_line)
1461 return GetTextAlign();
1462
1463 // When this is the last line of a block, or the line ends with a forced line
1464 // break.
1465 // https://drafts.csswg.org/css-text-3/#propdef-text-align-last
1466 switch (TextAlignLast()) {
1467 case ETextAlignLast::kStart:
1468 return ETextAlign::kStart;
1469 case ETextAlignLast::kEnd:
1470 return ETextAlign::kEnd;
1471 case ETextAlignLast::kLeft:
1472 return ETextAlign::kLeft;
1473 case ETextAlignLast::kRight:
1474 return ETextAlign::kRight;
1475 case ETextAlignLast::kCenter:
1476 return ETextAlign::kCenter;
1477 case ETextAlignLast::kJustify:
1478 return ETextAlign::kJustify;
1479 case ETextAlignLast::kAuto:
1480 ETextAlign text_align = GetTextAlign();
1481 if (text_align == ETextAlign::kJustify)
1482 return ETextAlign::kStart;
1483 return text_align;
1484 }
1485 NOTREACHED();
1486 return GetTextAlign();
1487 }
1488
ShouldUseTextIndent(bool is_first_line,bool is_after_forced_break) const1489 bool ComputedStyle::ShouldUseTextIndent(bool is_first_line,
1490 bool is_after_forced_break) const {
1491 bool should_use =
1492 is_first_line || (is_after_forced_break &&
1493 GetTextIndentLine() != TextIndentLine::kFirstLine);
1494 return GetTextIndentType() == TextIndentType::kNormal ? should_use
1495 : !should_use;
1496 }
1497
1498 // Unicode 11 introduced Georgian capital letters (U+1C90 - U+1CBA,
1499 // U+1CB[D-F]), but virtually no font covers them. For now map them back
1500 // to their lowercase counterparts (U+10D0 - U+10FA, U+10F[D-F]).
1501 // https://www.unicode.org/charts/PDF/U10A0.pdf
1502 // https://www.unicode.org/charts/PDF/U1C90.pdf
1503 // See https://crbug.com/865427 .
1504 // TODO(jshin): Make this platform-dependent. For instance, turn this
1505 // off when CrOS gets new Georgian fonts covering capital letters.
1506 // ( https://crbug.com/880144 ).
DisableNewGeorgianCapitalLetters(const String & text)1507 static String DisableNewGeorgianCapitalLetters(const String& text) {
1508 if (text.IsNull() || text.Is8Bit())
1509 return text;
1510 unsigned length = text.length();
1511 const StringImpl& input = *(text.Impl());
1512 StringBuilder result;
1513 result.ReserveCapacity(length);
1514 // |input| must be well-formed UTF-16 so that there's no worry
1515 // about surrogate handling.
1516 for (unsigned i = 0; i < length; ++i) {
1517 UChar character = input[i];
1518 if (Character::IsModernGeorgianUppercase(character))
1519 result.Append(Character::LowercaseModernGeorgianUppercase(character));
1520 else
1521 result.Append(character);
1522 }
1523 return result.ToString();
1524 }
1525
1526 namespace {
1527
1528 // TODO(https://crbug.com/1076420): this needs to handle all text-transform
1529 // values.
ApplyMathTransform(String * text,ETextTransform math_variant)1530 static void ApplyMathTransform(String* text, ETextTransform math_variant) {
1531 DCHECK(math_variant == ETextTransform::kMathAuto);
1532 DCHECK_EQ(text->length(), 1u);
1533 UChar character = (*text)[0];
1534 UChar32 transformed_char = MathVariant((*text)[0]);
1535 if (transformed_char == static_cast<UChar32>(character))
1536 return;
1537
1538 Vector<UChar> transformed_text(U16_LENGTH(transformed_char));
1539 int i = 0;
1540 U16_APPEND_UNSAFE(transformed_text, i, transformed_char);
1541 *text = String(transformed_text);
1542 }
1543
1544 } // namespace
1545
ApplyTextTransform(String * text,UChar previous_character) const1546 void ComputedStyle::ApplyTextTransform(String* text,
1547 UChar previous_character) const {
1548 switch (TextTransform()) {
1549 case ETextTransform::kNone:
1550 return;
1551 case ETextTransform::kCapitalize:
1552 *text = Capitalize(*text, previous_character);
1553 return;
1554 case ETextTransform::kUppercase: {
1555 const LayoutLocale* locale = GetFontDescription().Locale();
1556 CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale());
1557 *text = DisableNewGeorgianCapitalLetters(case_map.ToUpper(*text));
1558 return;
1559 }
1560 case ETextTransform::kLowercase: {
1561 const LayoutLocale* locale = GetFontDescription().Locale();
1562 CaseMap case_map(locale ? locale->CaseMapLocale() : CaseMap::Locale());
1563 *text = case_map.ToLower(*text);
1564 return;
1565 }
1566 case ETextTransform::kMathAuto:
1567 if (text->length() == 1)
1568 ApplyMathTransform(text, ETextTransform::kMathAuto);
1569 return;
1570 }
1571 NOTREACHED();
1572 }
1573
TextEmphasisMarkString() const1574 const AtomicString& ComputedStyle::TextEmphasisMarkString() const {
1575 switch (GetTextEmphasisMark()) {
1576 case TextEmphasisMark::kNone:
1577 return g_null_atom;
1578 case TextEmphasisMark::kCustom:
1579 return TextEmphasisCustomMark();
1580 case TextEmphasisMark::kDot: {
1581 DEFINE_STATIC_LOCAL(AtomicString, filled_dot_string,
1582 (&kBulletCharacter, 1));
1583 DEFINE_STATIC_LOCAL(AtomicString, open_dot_string,
1584 (&kWhiteBulletCharacter, 1));
1585 return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1586 ? filled_dot_string
1587 : open_dot_string;
1588 }
1589 case TextEmphasisMark::kCircle: {
1590 DEFINE_STATIC_LOCAL(AtomicString, filled_circle_string,
1591 (&kBlackCircleCharacter, 1));
1592 DEFINE_STATIC_LOCAL(AtomicString, open_circle_string,
1593 (&kWhiteCircleCharacter, 1));
1594 return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1595 ? filled_circle_string
1596 : open_circle_string;
1597 }
1598 case TextEmphasisMark::kDoubleCircle: {
1599 DEFINE_STATIC_LOCAL(AtomicString, filled_double_circle_string,
1600 (&kFisheyeCharacter, 1));
1601 DEFINE_STATIC_LOCAL(AtomicString, open_double_circle_string,
1602 (&kBullseyeCharacter, 1));
1603 return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1604 ? filled_double_circle_string
1605 : open_double_circle_string;
1606 }
1607 case TextEmphasisMark::kTriangle: {
1608 DEFINE_STATIC_LOCAL(AtomicString, filled_triangle_string,
1609 (&kBlackUpPointingTriangleCharacter, 1));
1610 DEFINE_STATIC_LOCAL(AtomicString, open_triangle_string,
1611 (&kWhiteUpPointingTriangleCharacter, 1));
1612 return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1613 ? filled_triangle_string
1614 : open_triangle_string;
1615 }
1616 case TextEmphasisMark::kSesame: {
1617 DEFINE_STATIC_LOCAL(AtomicString, filled_sesame_string,
1618 (&kSesameDotCharacter, 1));
1619 DEFINE_STATIC_LOCAL(AtomicString, open_sesame_string,
1620 (&kWhiteSesameDotCharacter, 1));
1621 return GetTextEmphasisFill() == TextEmphasisFill::kFilled
1622 ? filled_sesame_string
1623 : open_sesame_string;
1624 }
1625 case TextEmphasisMark::kAuto:
1626 NOTREACHED();
1627 return g_null_atom;
1628 }
1629
1630 NOTREACHED();
1631 return g_null_atom;
1632 }
1633
GetTextEmphasisLineLogicalSide() const1634 LineLogicalSide ComputedStyle::GetTextEmphasisLineLogicalSide() const {
1635 TextEmphasisPosition position = GetTextEmphasisPosition();
1636 if (IsHorizontalWritingMode()) {
1637 return position == TextEmphasisPosition::kOverRight ||
1638 position == TextEmphasisPosition::kOverLeft
1639 ? LineLogicalSide::kOver
1640 : LineLogicalSide::kUnder;
1641 }
1642 if (GetWritingMode() != WritingMode::kSidewaysLr) {
1643 return position == TextEmphasisPosition::kOverRight ||
1644 position == TextEmphasisPosition::kUnderRight
1645 ? LineLogicalSide::kOver
1646 : LineLogicalSide::kUnder;
1647 }
1648 return position == TextEmphasisPosition::kOverLeft ||
1649 position == TextEmphasisPosition::kUnderLeft
1650 ? LineLogicalSide::kOver
1651 : LineLogicalSide::kUnder;
1652 }
1653
AccessAnimations()1654 CSSAnimationData& ComputedStyle::AccessAnimations() {
1655 std::unique_ptr<CSSAnimationData>& animations = MutableAnimationsInternal();
1656 if (!animations)
1657 animations = std::make_unique<CSSAnimationData>();
1658 return *animations;
1659 }
1660
AccessTransitions()1661 CSSTransitionData& ComputedStyle::AccessTransitions() {
1662 std::unique_ptr<CSSTransitionData>& transitions =
1663 MutableTransitionsInternal();
1664 if (!transitions)
1665 transitions = std::make_unique<CSSTransitionData>();
1666 return *transitions;
1667 }
1668
GetFontBaseline() const1669 FontBaseline ComputedStyle::GetFontBaseline() const {
1670 // TODO(kojii): Incorporate 'dominant-baseline' when we support it.
1671 // https://www.w3.org/TR/css-inline-3/#dominant-baseline-property
1672
1673 // Vertical flow (except 'text-orientation: sideways') uses ideographic
1674 // baseline. https://drafts.csswg.org/css-writing-modes-3/#intro-baselines
1675 return !GetFontDescription().IsVerticalAnyUpright() ? kAlphabeticBaseline
1676 : kIdeographicBaseline;
1677 }
1678
GetFontHeight(FontBaseline baseline) const1679 FontHeight ComputedStyle::GetFontHeight(FontBaseline baseline) const {
1680 if (const SimpleFontData* font_data = GetFont().PrimaryFont())
1681 return font_data->GetFontMetrics().GetFontHeight(baseline);
1682 NOTREACHED();
1683 return FontHeight();
1684 }
1685
ComputeFontOrientation() const1686 FontOrientation ComputedStyle::ComputeFontOrientation() const {
1687 if (IsHorizontalWritingMode())
1688 return FontOrientation::kHorizontal;
1689
1690 switch (GetTextOrientation()) {
1691 case ETextOrientation::kMixed:
1692 return FontOrientation::kVerticalMixed;
1693 case ETextOrientation::kUpright:
1694 return FontOrientation::kVerticalUpright;
1695 case ETextOrientation::kSideways:
1696 return FontOrientation::kVerticalRotated;
1697 default:
1698 NOTREACHED();
1699 return FontOrientation::kVerticalMixed;
1700 }
1701 }
1702
UpdateFontOrientation()1703 void ComputedStyle::UpdateFontOrientation() {
1704 FontOrientation orientation = ComputeFontOrientation();
1705 if (GetFontDescription().Orientation() == orientation)
1706 return;
1707 FontDescription font_description = GetFontDescription();
1708 font_description.SetOrientation(orientation);
1709 SetFontDescription(font_description);
1710 }
1711
TextDecorationVisualOverflowEqual(const ComputedStyle & o) const1712 bool ComputedStyle::TextDecorationVisualOverflowEqual(
1713 const ComputedStyle& o) const {
1714 const Vector<AppliedTextDecoration>& applied_with_this =
1715 AppliedTextDecorations();
1716 const Vector<AppliedTextDecoration>& applied_with_other =
1717 o.AppliedTextDecorations();
1718 if (applied_with_this.size() != applied_with_other.size())
1719 return false;
1720 for (auto decoration_index = 0u; decoration_index < applied_with_this.size();
1721 ++decoration_index) {
1722 const AppliedTextDecoration& decoration_from_this =
1723 applied_with_this[decoration_index];
1724 const AppliedTextDecoration& decoration_from_other =
1725 applied_with_other[decoration_index];
1726 if (decoration_from_this.Thickness() != decoration_from_other.Thickness() ||
1727 decoration_from_this.UnderlineOffset() !=
1728 decoration_from_other.UnderlineOffset() ||
1729 decoration_from_this.Style() != decoration_from_other.Style() ||
1730 decoration_from_this.Lines() != decoration_from_other.Lines())
1731 return false;
1732 }
1733 if (TextUnderlinePosition() != o.TextUnderlinePosition())
1734 return false;
1735
1736 return true;
1737 }
1738
TextDecorationsInEffect() const1739 TextDecoration ComputedStyle::TextDecorationsInEffect() const {
1740 if (HasSimpleUnderlineInternal())
1741 return TextDecoration::kUnderline;
1742 if (!AppliedTextDecorationsInternal())
1743 return TextDecoration::kNone;
1744
1745 TextDecoration decorations = TextDecoration::kNone;
1746
1747 const Vector<AppliedTextDecoration>& applied = AppliedTextDecorations();
1748
1749 for (const AppliedTextDecoration& decoration : applied)
1750 decorations |= decoration.Lines();
1751
1752 return decorations;
1753 }
1754
AppliedTextDecorations() const1755 const Vector<AppliedTextDecoration>& ComputedStyle::AppliedTextDecorations()
1756 const {
1757 if (HasSimpleUnderlineInternal()) {
1758 DEFINE_STATIC_LOCAL(
1759 Vector<AppliedTextDecoration>, underline,
1760 (1, AppliedTextDecoration(
1761 TextDecoration::kUnderline, ETextDecorationStyle::kSolid,
1762 VisitedDependentColor(GetCSSPropertyTextDecorationColor()),
1763 TextDecorationThickness(), Length::Auto())));
1764 // Since we only have one of these in memory, just update the color before
1765 // returning.
1766 underline.at(0).SetColor(
1767 VisitedDependentColor(GetCSSPropertyTextDecorationColor()));
1768 return underline;
1769 }
1770 if (!AppliedTextDecorationsInternal()) {
1771 DEFINE_STATIC_LOCAL(Vector<AppliedTextDecoration>, empty, ());
1772 return empty;
1773 }
1774
1775 return AppliedTextDecorationsInternal()->data;
1776 }
1777
HasInitialVariables(const StyleInitialData * initial_data)1778 static bool HasInitialVariables(const StyleInitialData* initial_data) {
1779 return initial_data && initial_data->HasInitialVariables();
1780 }
1781
HasVariables() const1782 bool ComputedStyle::HasVariables() const {
1783 return InheritedVariables() || NonInheritedVariables() ||
1784 HasInitialVariables(InitialDataInternal().get());
1785 }
1786
GetVariableNames() const1787 HashSet<AtomicString> ComputedStyle::GetVariableNames() const {
1788 HashSet<AtomicString> names;
1789 if (auto* initial_data = InitialDataInternal().get())
1790 initial_data->CollectVariableNames(names);
1791 if (auto* inherited_variables = InheritedVariables())
1792 inherited_variables->CollectNames(names);
1793 if (auto* non_inherited_variables = NonInheritedVariables())
1794 non_inherited_variables->CollectNames(names);
1795 return names;
1796 }
1797
InheritedVariables() const1798 StyleInheritedVariables* ComputedStyle::InheritedVariables() const {
1799 return InheritedVariablesInternal().get();
1800 }
1801
NonInheritedVariables() const1802 StyleNonInheritedVariables* ComputedStyle::NonInheritedVariables() const {
1803 return NonInheritedVariablesInternal().get();
1804 }
1805
MutableInheritedVariables()1806 StyleInheritedVariables& ComputedStyle::MutableInheritedVariables() {
1807 scoped_refptr<StyleInheritedVariables>& variables =
1808 MutableInheritedVariablesInternal();
1809 if (!variables)
1810 variables = StyleInheritedVariables::Create();
1811 else if (!variables->HasOneRef())
1812 variables = variables->Copy();
1813 return *variables;
1814 }
1815
MutableNonInheritedVariables()1816 StyleNonInheritedVariables& ComputedStyle::MutableNonInheritedVariables() {
1817 std::unique_ptr<StyleNonInheritedVariables>& variables =
1818 MutableNonInheritedVariablesInternal();
1819 if (!variables)
1820 variables = std::make_unique<StyleNonInheritedVariables>();
1821 return *variables;
1822 }
1823
SetInitialData(scoped_refptr<StyleInitialData> data)1824 void ComputedStyle::SetInitialData(scoped_refptr<StyleInitialData> data) {
1825 MutableInitialDataInternal() = std::move(data);
1826 }
1827
SetVariableData(const AtomicString & name,scoped_refptr<CSSVariableData> value,bool is_inherited_property)1828 void ComputedStyle::SetVariableData(const AtomicString& name,
1829 scoped_refptr<CSSVariableData> value,
1830 bool is_inherited_property) {
1831 if (is_inherited_property)
1832 MutableInheritedVariables().SetData(name, std::move(value));
1833 else
1834 MutableNonInheritedVariables().SetData(name, std::move(value));
1835 }
1836
SetVariableValue(const AtomicString & name,const CSSValue * value,bool is_inherited_property)1837 void ComputedStyle::SetVariableValue(const AtomicString& name,
1838 const CSSValue* value,
1839 bool is_inherited_property) {
1840 if (is_inherited_property)
1841 MutableInheritedVariables().SetValue(name, value);
1842 else
1843 MutableNonInheritedVariables().SetValue(name, value);
1844 }
1845
GetInitialVariableData(const AtomicString & name,const StyleInitialData * initial_data)1846 static CSSVariableData* GetInitialVariableData(
1847 const AtomicString& name,
1848 const StyleInitialData* initial_data) {
1849 if (!initial_data)
1850 return nullptr;
1851 return initial_data->GetVariableData(name);
1852 }
1853
GetVariableData(const AtomicString & name) const1854 CSSVariableData* ComputedStyle::GetVariableData(
1855 const AtomicString& name) const {
1856 if (InheritedVariables()) {
1857 if (auto data = InheritedVariables()->GetData(name))
1858 return *data;
1859 }
1860 if (NonInheritedVariables()) {
1861 if (auto data = NonInheritedVariables()->GetData(name))
1862 return *data;
1863 }
1864 return GetInitialVariableData(name, InitialDataInternal().get());
1865 }
1866
GetVariableData(const AtomicString & name,bool is_inherited_property) const1867 CSSVariableData* ComputedStyle::GetVariableData(
1868 const AtomicString& name,
1869 bool is_inherited_property) const {
1870 if (is_inherited_property) {
1871 if (InheritedVariables()) {
1872 if (auto data = InheritedVariables()->GetData(name))
1873 return *data;
1874 }
1875 } else {
1876 if (NonInheritedVariables()) {
1877 if (auto data = NonInheritedVariables()->GetData(name))
1878 return *data;
1879 }
1880 }
1881 return GetInitialVariableData(name, InitialDataInternal().get());
1882 }
1883
GetInitialVariableValue(const AtomicString & name,const StyleInitialData * initial_data)1884 static const CSSValue* GetInitialVariableValue(
1885 const AtomicString& name,
1886 const StyleInitialData* initial_data) {
1887 if (!initial_data)
1888 return nullptr;
1889 return initial_data->GetVariableValue(name);
1890 }
1891
GetVariableValue(const AtomicString & name) const1892 const CSSValue* ComputedStyle::GetVariableValue(
1893 const AtomicString& name) const {
1894 if (InheritedVariables()) {
1895 if (auto value = InheritedVariables()->GetValue(name))
1896 return *value;
1897 }
1898 if (NonInheritedVariables()) {
1899 if (auto value = NonInheritedVariables()->GetValue(name))
1900 return *value;
1901 }
1902 return GetInitialVariableValue(name, InitialDataInternal().get());
1903 }
1904
GetVariableValue(const AtomicString & name,bool is_inherited_property) const1905 const CSSValue* ComputedStyle::GetVariableValue(
1906 const AtomicString& name,
1907 bool is_inherited_property) const {
1908 if (is_inherited_property) {
1909 if (InheritedVariables()) {
1910 if (auto value = InheritedVariables()->GetValue(name))
1911 return *value;
1912 }
1913 } else {
1914 if (NonInheritedVariables()) {
1915 if (auto value = NonInheritedVariables()->GetValue(name))
1916 return *value;
1917 }
1918 }
1919 return GetInitialVariableValue(name, InitialDataInternal().get());
1920 }
1921
SetFontDescription(const FontDescription & v)1922 bool ComputedStyle::SetFontDescription(const FontDescription& v) {
1923 if (FontInternal().GetFontDescription() != v) {
1924 SetFontInternal(Font(v, FontInternal().GetFontSelector()));
1925 return true;
1926 }
1927 return false;
1928 }
1929
HasIdenticalAscentDescentAndLineGap(const ComputedStyle & other) const1930 bool ComputedStyle::HasIdenticalAscentDescentAndLineGap(
1931 const ComputedStyle& other) const {
1932 const SimpleFontData* font_data = GetFont().PrimaryFont();
1933 const SimpleFontData* other_font_data = other.GetFont().PrimaryFont();
1934 return font_data && other_font_data &&
1935 font_data->GetFontMetrics().HasIdenticalAscentDescentAndLineGap(
1936 other_font_data->GetFontMetrics());
1937 }
1938
LineHeight() const1939 Length ComputedStyle::LineHeight() const {
1940 const Length& lh = LineHeightInternal();
1941 // Unlike getFontDescription().computedSize() and hence fontSize(), this is
1942 // recalculated on demand as we only store the specified line height.
1943 // FIXME: Should consider scaling the fixed part of any calc expressions
1944 // too, though this involves messily poking into CalcExpressionLength.
1945 if (lh.IsFixed()) {
1946 float multiplier = TextAutosizingMultiplier();
1947 return Length::Fixed(TextAutosizer::ComputeAutosizedFontSize(
1948 lh.Value(), multiplier, EffectiveZoom()));
1949 }
1950
1951 return lh;
1952 }
1953
ComputedLineHeight() const1954 int ComputedStyle::ComputedLineHeight() const {
1955 const Length& lh = LineHeight();
1956
1957 // Negative value means the line height is not set. Use the font's built-in
1958 // spacing, if avalible.
1959 if (lh.IsNegative() && GetFont().PrimaryFont())
1960 return GetFont().PrimaryFont()->GetFontMetrics().LineSpacing();
1961
1962 if (lh.IsPercentOrCalc())
1963 return MinimumValueForLength(lh, LayoutUnit(ComputedFontSize())).ToInt();
1964
1965 return std::min(lh.Value(), LayoutUnit::Max().ToFloat());
1966 }
1967
ComputedLineHeightAsFixed() const1968 LayoutUnit ComputedStyle::ComputedLineHeightAsFixed() const {
1969 const Length& lh = LineHeight();
1970
1971 // Negative value means the line height is not set. Use the font's built-in
1972 // spacing, if avalible.
1973 if (lh.IsNegative() && GetFont().PrimaryFont())
1974 return GetFont().PrimaryFont()->GetFontMetrics().FixedLineSpacing();
1975
1976 if (lh.IsPercentOrCalc()) {
1977 return LayoutUnit(
1978 MinimumValueForLength(lh, ComputedFontSizeAsFixed()).ToInt());
1979 }
1980
1981 return LayoutUnit(floorf(lh.Value()));
1982 }
1983
SetWordSpacing(float word_spacing)1984 void ComputedStyle::SetWordSpacing(float word_spacing) {
1985 FontDescription desc(GetFontDescription());
1986 desc.SetWordSpacing(word_spacing);
1987 SetFontDescription(desc);
1988 }
1989
SetLetterSpacing(float letter_spacing)1990 void ComputedStyle::SetLetterSpacing(float letter_spacing) {
1991 FontDescription desc(GetFontDescription());
1992 desc.SetLetterSpacing(letter_spacing);
1993 SetFontDescription(desc);
1994 }
1995
SetTextAutosizingMultiplier(float multiplier)1996 void ComputedStyle::SetTextAutosizingMultiplier(float multiplier) {
1997 SetTextAutosizingMultiplierInternal(multiplier);
1998
1999 float size = SpecifiedFontSize();
2000
2001 DCHECK(std::isfinite(size));
2002 if (!std::isfinite(size) || size < 0)
2003 size = 0;
2004 else
2005 size = std::min(kMaximumAllowedFontSize, size);
2006
2007 FontDescription desc(GetFontDescription());
2008 desc.SetSpecifiedSize(size);
2009
2010 float computed_size = size * EffectiveZoom();
2011
2012 float autosized_font_size = TextAutosizer::ComputeAutosizedFontSize(
2013 computed_size, multiplier, EffectiveZoom());
2014 desc.SetComputedSize(std::min(kMaximumAllowedFontSize, autosized_font_size));
2015
2016 SetFontDescription(desc);
2017 }
2018
AddAppliedTextDecoration(const AppliedTextDecoration & decoration)2019 void ComputedStyle::AddAppliedTextDecoration(
2020 const AppliedTextDecoration& decoration) {
2021 scoped_refptr<AppliedTextDecorationList>& list =
2022 MutableAppliedTextDecorationsInternal();
2023
2024 if (!list)
2025 list = base::MakeRefCounted<AppliedTextDecorationList>();
2026 else if (!list->HasOneRef())
2027 list = base::MakeRefCounted<AppliedTextDecorationList>(list->data);
2028
2029 list->data.push_back(decoration);
2030 }
2031
OverrideTextDecorationColors(Color override_color)2032 void ComputedStyle::OverrideTextDecorationColors(Color override_color) {
2033 scoped_refptr<AppliedTextDecorationList>& list =
2034 MutableAppliedTextDecorationsInternal();
2035 DCHECK(list);
2036 if (!list->HasOneRef())
2037 list = base::MakeRefCounted<AppliedTextDecorationList>(list->data);
2038
2039 for (AppliedTextDecoration& decoration : list->data)
2040 decoration.SetColor(override_color);
2041 }
2042
ApplyTextDecorations(const Color & parent_text_decoration_color,bool override_existing_colors)2043 void ComputedStyle::ApplyTextDecorations(
2044 const Color& parent_text_decoration_color,
2045 bool override_existing_colors) {
2046 if (GetTextDecoration() == TextDecoration::kNone &&
2047 !HasSimpleUnderlineInternal() && !AppliedTextDecorationsInternal())
2048 return;
2049
2050 // If there are any color changes or decorations set by this element, stop
2051 // using m_hasSimpleUnderline.
2052 Color current_text_decoration_color =
2053 VisitedDependentColor(GetCSSPropertyTextDecorationColor());
2054 if (HasSimpleUnderlineInternal() &&
2055 (GetTextDecoration() != TextDecoration::kNone ||
2056 current_text_decoration_color != parent_text_decoration_color)) {
2057 SetHasSimpleUnderlineInternal(false);
2058 AddAppliedTextDecoration(AppliedTextDecoration(
2059 TextDecoration::kUnderline, ETextDecorationStyle::kSolid,
2060 parent_text_decoration_color, TextDecorationThickness(),
2061 Length::Auto()));
2062 }
2063 if (override_existing_colors && AppliedTextDecorationsInternal())
2064 OverrideTextDecorationColors(current_text_decoration_color);
2065 if (GetTextDecoration() == TextDecoration::kNone)
2066 return;
2067 DCHECK(!HasSimpleUnderlineInternal());
2068 // To save memory, we don't use AppliedTextDecoration objects in the common
2069 // case of a single simple underline of currentColor.
2070 TextDecoration decoration_lines = GetTextDecoration();
2071 ETextDecorationStyle decoration_style = TextDecorationStyle();
2072 bool is_simple_underline = decoration_lines == TextDecoration::kUnderline &&
2073 decoration_style == ETextDecorationStyle::kSolid &&
2074 TextDecorationColor().IsCurrentColor() &&
2075 TextUnderlineOffset().IsAuto();
2076 if (is_simple_underline && !AppliedTextDecorationsInternal()) {
2077 SetHasSimpleUnderlineInternal(true);
2078 return;
2079 }
2080
2081 AddAppliedTextDecoration(AppliedTextDecoration(
2082 decoration_lines, decoration_style, current_text_decoration_color,
2083 GetTextDecorationThickness(), TextUnderlineOffset()));
2084 }
2085
ClearAppliedTextDecorations()2086 void ComputedStyle::ClearAppliedTextDecorations() {
2087 SetHasSimpleUnderlineInternal(false);
2088
2089 if (AppliedTextDecorationsInternal())
2090 SetAppliedTextDecorationsInternal(nullptr);
2091 }
2092
RestoreParentTextDecorations(const ComputedStyle & parent_style)2093 void ComputedStyle::RestoreParentTextDecorations(
2094 const ComputedStyle& parent_style) {
2095 SetHasSimpleUnderlineInternal(parent_style.HasSimpleUnderlineInternal());
2096 if (AppliedTextDecorationsInternal() !=
2097 parent_style.AppliedTextDecorationsInternal()) {
2098 SetAppliedTextDecorationsInternal(scoped_refptr<AppliedTextDecorationList>(
2099 parent_style.AppliedTextDecorationsInternal()));
2100 }
2101 }
2102
ClearMultiCol()2103 void ComputedStyle::ClearMultiCol() {
2104 SetColumnGap(ComputedStyleInitialValues::InitialColumnGap());
2105 SetColumnWidthInternal(ComputedStyleInitialValues::InitialColumnWidth());
2106 SetColumnRuleStyle(ComputedStyleInitialValues::InitialColumnRuleStyle());
2107 SetColumnRuleWidthInternal(
2108 LayoutUnit(ComputedStyleInitialValues::InitialColumnRuleWidth()));
2109 SetColumnRuleColorInternal(
2110 ComputedStyleInitialValues::InitialColumnRuleColor());
2111 SetInternalVisitedColumnRuleColorInternal(
2112 ComputedStyleInitialValues::InitialInternalVisitedColumnRuleColor());
2113 SetColumnCountInternal(ComputedStyleInitialValues::InitialColumnCount());
2114 SetHasAutoColumnCountInternal(
2115 ComputedStyleInitialValues::InitialHasAutoColumnCount());
2116 SetHasAutoColumnWidthInternal(
2117 ComputedStyleInitialValues::InitialHasAutoColumnWidth());
2118 ResetColumnFill();
2119 ResetColumnSpan();
2120 }
2121
DecorationColorIncludingFallback(bool visited_link) const2122 StyleColor ComputedStyle::DecorationColorIncludingFallback(
2123 bool visited_link) const {
2124 StyleColor style_color = visited_link ? InternalVisitedTextDecorationColor()
2125 : TextDecorationColor();
2126
2127 if (!style_color.IsCurrentColor())
2128 return style_color;
2129
2130 if (TextStrokeWidth()) {
2131 // Prefer stroke color if possible, but not if it's fully transparent.
2132 StyleColor text_stroke_style_color =
2133 visited_link ? InternalVisitedTextStrokeColor() : TextStrokeColor();
2134 if (!text_stroke_style_color.IsCurrentColor() &&
2135 text_stroke_style_color.Resolve(Color(), UsedColorScheme()).Alpha()) {
2136 return text_stroke_style_color;
2137 }
2138 }
2139
2140 return visited_link ? InternalVisitedTextFillColor() : TextFillColor();
2141 }
2142
VisitedDependentColor(const CSSProperty & color_property) const2143 Color ComputedStyle::VisitedDependentColor(
2144 const CSSProperty& color_property) const {
2145 DCHECK(!color_property.IsVisited());
2146
2147 Color unvisited_color =
2148 To<Longhand>(color_property).ColorIncludingFallback(false, *this);
2149 if (InsideLink() != EInsideLink::kInsideVisitedLink)
2150 return unvisited_color;
2151
2152 // Properties that provide a GetVisitedProperty() must use the
2153 // ColorIncludingFallback function on that property.
2154 //
2155 // TODO(andruud): Simplify this when all properties support
2156 // GetVisitedProperty.
2157 const CSSProperty* visited_property = &color_property;
2158 if (const CSSProperty* visited = color_property.GetVisitedProperty())
2159 visited_property = visited;
2160
2161 Color visited_color =
2162 To<Longhand>(*visited_property).ColorIncludingFallback(true, *this);
2163
2164 // Take the alpha from the unvisited color, but get the RGB values from the
2165 // visited color.
2166 return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
2167 unvisited_color.Alpha());
2168 }
2169
ResolvedColor(const StyleColor & color) const2170 Color ComputedStyle::ResolvedColor(const StyleColor& color) const {
2171 bool visited_link = (InsideLink() == EInsideLink::kInsideVisitedLink);
2172 Color current_color =
2173 visited_link ? GetInternalVisitedCurrentColor() : GetCurrentColor();
2174 return color.Resolve(current_color, UsedColorScheme());
2175 }
2176
SetMarginStart(const Length & margin)2177 void ComputedStyle::SetMarginStart(const Length& margin) {
2178 if (IsHorizontalWritingMode()) {
2179 if (IsLeftToRightDirection())
2180 SetMarginLeft(margin);
2181 else
2182 SetMarginRight(margin);
2183 } else {
2184 if (IsLeftToRightDirection())
2185 SetMarginTop(margin);
2186 else
2187 SetMarginBottom(margin);
2188 }
2189 }
2190
SetMarginEnd(const Length & margin)2191 void ComputedStyle::SetMarginEnd(const Length& margin) {
2192 if (IsHorizontalWritingMode()) {
2193 if (IsLeftToRightDirection())
2194 SetMarginRight(margin);
2195 else
2196 SetMarginLeft(margin);
2197 } else {
2198 if (IsLeftToRightDirection())
2199 SetMarginBottom(margin);
2200 else
2201 SetMarginTop(margin);
2202 }
2203 }
2204
OutlineOutsetExtent() const2205 int ComputedStyle::OutlineOutsetExtent() const {
2206 if (!HasOutline())
2207 return 0;
2208 if (OutlineStyleIsAuto()) {
2209 return GraphicsContext::FocusRingOutsetExtent(
2210 OutlineOffsetInt(), std::ceil(GetOutlineStrokeWidthForFocusRing()));
2211 }
2212 return base::ClampAdd(OutlineWidthInt(), OutlineOffsetInt()).Max(0);
2213 }
2214
GetOutlineStrokeWidthForFocusRing() const2215 float ComputedStyle::GetOutlineStrokeWidthForFocusRing() const {
2216 if (::features::IsFormControlsRefreshEnabled() && OutlineStyleIsAuto()) {
2217 return std::max(EffectiveZoom(), 3.f);
2218 }
2219
2220 #if defined(OS_MAC)
2221 return OutlineWidthInt();
2222 #else
2223 // Draw an outline with thickness in proportion to the zoom level, but never
2224 // so narrow that it becomes invisible.
2225 return std::max(EffectiveZoom(), 1.f);
2226 #endif
2227 }
2228
ColumnRuleEquivalent(const ComputedStyle & other_style) const2229 bool ComputedStyle::ColumnRuleEquivalent(
2230 const ComputedStyle& other_style) const {
2231 return ColumnRuleStyle() == other_style.ColumnRuleStyle() &&
2232 ColumnRuleWidth() == other_style.ColumnRuleWidth() &&
2233 VisitedDependentColor(GetCSSPropertyColumnRuleColor()) ==
2234 other_style.VisitedDependentColor(GetCSSPropertyColumnRuleColor());
2235 }
2236
GetTextEmphasisMark() const2237 TextEmphasisMark ComputedStyle::GetTextEmphasisMark() const {
2238 TextEmphasisMark mark = TextEmphasisMarkInternal();
2239 if (mark != TextEmphasisMark::kAuto)
2240 return mark;
2241
2242 if (IsHorizontalWritingMode())
2243 return TextEmphasisMark::kDot;
2244
2245 return TextEmphasisMark::kSesame;
2246 }
2247
ImageOutsets(const NinePieceImage & image) const2248 LayoutRectOutsets ComputedStyle::ImageOutsets(
2249 const NinePieceImage& image) const {
2250 return LayoutRectOutsets(
2251 NinePieceImage::ComputeOutset(image.Outset().Top(), BorderTopWidth()),
2252 NinePieceImage::ComputeOutset(image.Outset().Right(), BorderRightWidth()),
2253 NinePieceImage::ComputeOutset(image.Outset().Bottom(),
2254 BorderBottomWidth()),
2255 NinePieceImage::ComputeOutset(image.Outset().Left(), BorderLeftWidth()));
2256 }
2257
SetBorderImageSource(StyleImage * image)2258 void ComputedStyle::SetBorderImageSource(StyleImage* image) {
2259 if (BorderImage().GetImage() == image)
2260 return;
2261 MutableBorderImageInternal().SetImage(image);
2262 }
2263
SetBorderImageSlices(const LengthBox & slices)2264 void ComputedStyle::SetBorderImageSlices(const LengthBox& slices) {
2265 if (BorderImage().ImageSlices() == slices)
2266 return;
2267 MutableBorderImageInternal().SetImageSlices(slices);
2268 }
2269
SetBorderImageSlicesFill(bool fill)2270 void ComputedStyle::SetBorderImageSlicesFill(bool fill) {
2271 if (BorderImage().Fill() == fill)
2272 return;
2273 MutableBorderImageInternal().SetFill(fill);
2274 }
2275
SetBorderImageWidth(const BorderImageLengthBox & slices)2276 void ComputedStyle::SetBorderImageWidth(const BorderImageLengthBox& slices) {
2277 if (BorderImage().BorderSlices() == slices)
2278 return;
2279 MutableBorderImageInternal().SetBorderSlices(slices);
2280 }
2281
SetBorderImageOutset(const BorderImageLengthBox & outset)2282 void ComputedStyle::SetBorderImageOutset(const BorderImageLengthBox& outset) {
2283 if (BorderImage().Outset() == outset)
2284 return;
2285 MutableBorderImageInternal().SetOutset(outset);
2286 }
2287
BorderObscuresBackground() const2288 bool ComputedStyle::BorderObscuresBackground() const {
2289 if (!HasBorder())
2290 return false;
2291
2292 // Bail if we have any border-image for now. We could look at the image alpha
2293 // to improve this.
2294 if (BorderImage().GetImage())
2295 return false;
2296
2297 BorderEdge edges[4];
2298 GetBorderEdgeInfo(edges);
2299
2300 for (unsigned int i = static_cast<unsigned>(BoxSide::kTop);
2301 i <= static_cast<unsigned>(BoxSide::kLeft); ++i) {
2302 const BorderEdge& curr_edge = edges[i];
2303 if (!curr_edge.ObscuresBackground())
2304 return false;
2305 }
2306
2307 return true;
2308 }
2309
BoxDecorationOutsets() const2310 LayoutRectOutsets ComputedStyle::BoxDecorationOutsets() const {
2311 DCHECK(HasVisualOverflowingEffect());
2312 LayoutRectOutsets outsets;
2313
2314 if (const ShadowList* box_shadow = BoxShadow())
2315 outsets = LayoutRectOutsets(box_shadow->RectOutsetsIncludingOriginal());
2316
2317 if (HasBorderImageOutsets())
2318 outsets.Unite(BorderImageOutsets());
2319
2320 if (HasMaskBoxImageOutsets())
2321 outsets.Unite(MaskBoxImageOutsets());
2322
2323 return outsets;
2324 }
2325
GetBorderEdgeInfo(BorderEdge edges[],PhysicalBoxSides sides_to_include) const2326 void ComputedStyle::GetBorderEdgeInfo(BorderEdge edges[],
2327 PhysicalBoxSides sides_to_include) const {
2328 edges[static_cast<unsigned>(BoxSide::kTop)] = BorderEdge(
2329 BorderTopWidth(), VisitedDependentColor(GetCSSPropertyBorderTopColor()),
2330 BorderTopStyle(), sides_to_include.top);
2331
2332 edges[static_cast<unsigned>(BoxSide::kRight)] =
2333 BorderEdge(BorderRightWidth(),
2334 VisitedDependentColor(GetCSSPropertyBorderRightColor()),
2335 BorderRightStyle(), sides_to_include.right);
2336
2337 edges[static_cast<unsigned>(BoxSide::kBottom)] =
2338 BorderEdge(BorderBottomWidth(),
2339 VisitedDependentColor(GetCSSPropertyBorderBottomColor()),
2340 BorderBottomStyle(), sides_to_include.bottom);
2341
2342 edges[static_cast<unsigned>(BoxSide::kLeft)] = BorderEdge(
2343 BorderLeftWidth(), VisitedDependentColor(GetCSSPropertyBorderLeftColor()),
2344 BorderLeftStyle(), sides_to_include.left);
2345 }
2346
CopyChildDependentFlagsFrom(const ComputedStyle & other)2347 void ComputedStyle::CopyChildDependentFlagsFrom(const ComputedStyle& other) {
2348 if (other.ChildHasExplicitInheritance())
2349 SetChildHasExplicitInheritance();
2350 }
2351
GetCurrentColor() const2352 Color ComputedStyle::GetCurrentColor() const {
2353 DCHECK(!GetColor().IsCurrentColor());
2354 return GetColor().Resolve(Color(), UsedColorScheme());
2355 }
2356
GetInternalVisitedCurrentColor() const2357 Color ComputedStyle::GetInternalVisitedCurrentColor() const {
2358 DCHECK(!InternalVisitedColor().IsCurrentColor());
2359 return InternalVisitedColor().Resolve(Color(), UsedColorScheme());
2360 }
2361
ShadowListHasCurrentColor(const ShadowList * shadow_list)2362 bool ComputedStyle::ShadowListHasCurrentColor(const ShadowList* shadow_list) {
2363 if (!shadow_list)
2364 return false;
2365 return std::any_of(shadow_list->Shadows().begin(),
2366 shadow_list->Shadows().end(),
2367 [](const ShadowData& shadow) {
2368 return shadow.GetColor().IsCurrentColor();
2369 });
2370 }
2371
2372 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kAuto,
2373 EOverscrollBehavior::kAuto);
2374 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kContain,
2375 EOverscrollBehavior::kContain);
2376 STATIC_ASSERT_ENUM(cc::OverscrollBehavior::Type::kNone,
2377 EOverscrollBehavior::kNone);
2378
2379 } // namespace blink
2380