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