// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/renderer/core/style/computed_style.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/css/css_font_selector.h" #include "third_party/blink/renderer/core/css/css_gradient_value.h" #include "third_party/blink/renderer/core/css/css_identifier_value.h" #include "third_party/blink/renderer/core/css/css_math_expression_node.h" #include "third_party/blink/renderer/core/css/css_math_function_value.h" #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h" #include "third_party/blink/renderer/core/css/css_test_helpers.h" #include "third_party/blink/renderer/core/css/css_value_list.h" #include "third_party/blink/renderer/core/css/parser/css_parser.h" #include "third_party/blink/renderer/core/css/properties/css_property_ref.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/style/clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h" #include "third_party/blink/renderer/core/style/shape_value.h" #include "third_party/blink/renderer/core/style/style_difference.h" #include "third_party/blink/renderer/core/style/style_generated_image.h" #include "third_party/blink/renderer/core/testing/color_scheme_helper.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "ui/base/ui_base_features.h" namespace blink { TEST(ComputedStyleTest, ShapeOutsideBoxEqual) { auto* shape1 = MakeGarbageCollected(CSSBoxType::kContent); auto* shape2 = MakeGarbageCollected(CSSBoxType::kContent); scoped_refptr style1 = ComputedStyle::Create(); scoped_refptr style2 = ComputedStyle::Create(); style1->SetShapeOutside(shape1); style2->SetShapeOutside(shape2); EXPECT_EQ(*style1, *style2); } TEST(ComputedStyleTest, ShapeOutsideCircleEqual) { scoped_refptr circle1 = BasicShapeCircle::Create(); scoped_refptr circle2 = BasicShapeCircle::Create(); auto* shape1 = MakeGarbageCollected(std::move(circle1), CSSBoxType::kContent); auto* shape2 = MakeGarbageCollected(std::move(circle2), CSSBoxType::kContent); scoped_refptr style1 = ComputedStyle::Create(); scoped_refptr style2 = ComputedStyle::Create(); style1->SetShapeOutside(shape1); style2->SetShapeOutside(shape2); EXPECT_EQ(*style1, *style2); } TEST(ComputedStyleTest, ClipPathEqual) { scoped_refptr shape = BasicShapeCircle::Create(); scoped_refptr path1 = ShapeClipPathOperation::Create(shape); scoped_refptr path2 = ShapeClipPathOperation::Create(shape); scoped_refptr style1 = ComputedStyle::Create(); scoped_refptr style2 = ComputedStyle::Create(); style1->SetClipPath(path1); style2->SetClipPath(path2); EXPECT_EQ(*style1, *style2); } TEST(ComputedStyleTest, FocusRingWidth) { scoped_refptr style = ComputedStyle::Create(); if (::features::IsFormControlsRefreshEnabled()) { style->SetOutlineStyleIsAuto(static_cast(OutlineIsAuto::kOn)); EXPECT_EQ(3, style->GetOutlineStrokeWidthForFocusRing()); style->SetEffectiveZoom(3.5); style->SetOutlineWidth(4); EXPECT_EQ(3.5, style->GetOutlineStrokeWidthForFocusRing()); } else { style->SetEffectiveZoom(3.5); style->SetOutlineStyle(EBorderStyle::kSolid); #if defined(OS_MACOSX) EXPECT_EQ(3, style->GetOutlineStrokeWidthForFocusRing()); #else style->SetOutlineStyleIsAuto(static_cast(OutlineIsAuto::kOn)); static uint16_t outline_width = 4; style->SetOutlineWidth(outline_width); double expected_width = LayoutTheme::GetTheme().IsFocusRingOutset() ? outline_width : 3.5; EXPECT_EQ(expected_width, style->GetOutlineStrokeWidthForFocusRing()); expected_width = LayoutTheme::GetTheme().IsFocusRingOutset() ? outline_width : 1.0; style->SetEffectiveZoom(0.5); EXPECT_EQ(expected_width, style->GetOutlineStrokeWidthForFocusRing()); #endif } } TEST(ComputedStyleTest, FocusRingOutset) { scoped_refptr style = ComputedStyle::Create(); style->SetOutlineStyle(EBorderStyle::kSolid); style->SetOutlineStyleIsAuto(static_cast(OutlineIsAuto::kOn)); style->SetEffectiveZoom(4.75); if (::features::IsFormControlsRefreshEnabled()) { EXPECT_EQ(4, style->OutlineOutsetExtent()); style->SetEffectiveAppearance(kRadioPart); EXPECT_EQ(6, style->OutlineOutsetExtent()); } else { #if defined(OS_MACOSX) EXPECT_EQ(4, style->OutlineOutsetExtent()); #else EXPECT_EQ(3, style->OutlineOutsetExtent()); #endif } } TEST(ComputedStyleTest, SVGStackingContext) { scoped_refptr style = ComputedStyle::Create(); style->UpdateIsStackingContext(false, false, true); EXPECT_TRUE(style->IsStackingContext()); } TEST(ComputedStyleTest, Preserve3dForceStackingContext) { scoped_refptr style = ComputedStyle::Create(); style->SetTransformStyle3D(ETransformStyle3D::kPreserve3d); style->SetOverflowX(EOverflow::kHidden); style->SetOverflowY(EOverflow::kHidden); style->UpdateIsStackingContext(false, false, false); EXPECT_EQ(ETransformStyle3D::kFlat, style->UsedTransformStyle3D()); EXPECT_TRUE(style->IsStackingContext()); } TEST(ComputedStyleTest, LayoutContainmentStackingContext) { scoped_refptr style = ComputedStyle::Create(); EXPECT_FALSE(style->IsStackingContext()); style->SetContain(kContainsLayout); style->UpdateIsStackingContext(false, false, false); EXPECT_TRUE(style->IsStackingContext()); } TEST(ComputedStyleTest, FirstPublicPseudoStyle) { scoped_refptr style = ComputedStyle::Create(); style->SetHasPseudoElementStyle(kPseudoIdFirstLine); EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdFirstLine)); EXPECT_TRUE(style->HasAnyPseudoElementStyles()); } TEST(ComputedStyleTest, LastPublicPseudoElementStyle) { scoped_refptr style = ComputedStyle::Create(); style->SetHasPseudoElementStyle(kPseudoIdScrollbar); EXPECT_TRUE(style->HasPseudoElementStyle(kPseudoIdScrollbar)); EXPECT_TRUE(style->HasAnyPseudoElementStyles()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesRespectsTransformAnimation) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetHasCurrentTransformAnimation(true); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.TransformChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsTransforom) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); TransformOperations operations(true); style->SetTransform(operations); other->SetTransform(operations); other->SetHasCurrentTransformAnimation(true); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_FALSE(diff.TransformChanged()); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsOpacity) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetHasCurrentOpacityAnimation(true); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsFilter) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetHasCurrentFilterAnimation(true); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsBackdropFilter) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetHasCurrentBackdropFilterAnimation(true); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsBackfaceVisibility) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetBackfaceVisibility(EBackfaceVisibility::kHidden); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsWillChange) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetBackfaceVisibility(EBackfaceVisibility::kHidden); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsUsedStylePreserve3D) { scoped_refptr style = ComputedStyle::Create(); style->SetTransformStyle3D(ETransformStyle3D::kPreserve3d); scoped_refptr other = ComputedStyle::Clone(*style); // This induces a flat used transform style. other->SetOpacity(0.5); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsOverflow) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); other->SetOverflowX(EOverflow::kHidden); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdatePropertySpecificDifferencesCompositingReasonsContainsPaint) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); // This induces a flat used transform style. other->SetContain(kContainsPaint); StyleDifference diff; style->UpdatePropertySpecificDifferences(*other, diff); EXPECT_TRUE(diff.CompositingReasonsChanged()); } TEST(ComputedStyleTest, UpdateBackgroundColorDifferencesHasAlpha) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); StyleDifference diff; style->AdjustDiffForBackgroundVisuallyEqual(*other, diff); EXPECT_FALSE(diff.HasAlphaChanged()); style->SetBackgroundColor(StyleColor(Color(255, 255, 255, 255))); other->SetBackgroundColor(StyleColor(Color(255, 255, 255, 128))); EXPECT_FALSE( style->VisitedDependentColor(GetCSSPropertyBackgroundColor()).HasAlpha()); EXPECT_TRUE( other->VisitedDependentColor(GetCSSPropertyBackgroundColor()).HasAlpha()); style->AdjustDiffForBackgroundVisuallyEqual(*other, diff); EXPECT_TRUE(diff.HasAlphaChanged()); } TEST(ComputedStyleTest, UpdateBackgroundLayerDifferencesHasAlpha) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Clone(*style); StyleDifference diff; style->AdjustDiffForBackgroundVisuallyEqual(*other, diff); EXPECT_FALSE(diff.HasAlphaChanged()); other->AccessBackgroundLayers().EnsureNext(); style->AdjustDiffForBackgroundVisuallyEqual(*other, diff); EXPECT_TRUE(diff.HasAlphaChanged()); } TEST(ComputedStyleTest, HasOutlineWithCurrentColor) { scoped_refptr style = ComputedStyle::Create(); EXPECT_FALSE(style->HasOutline()); EXPECT_FALSE(style->HasOutlineWithCurrentColor()); style->SetOutlineColor(StyleColor::CurrentColor()); EXPECT_FALSE(style->HasOutlineWithCurrentColor()); style->SetOutlineWidth(5); EXPECT_FALSE(style->HasOutlineWithCurrentColor()); style->SetOutlineStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->HasOutlineWithCurrentColor()); } TEST(ComputedStyleTest, HasBorderColorReferencingCurrentColor) { scoped_refptr style = ComputedStyle::Create(); EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor()); style->SetBorderBottomColor(StyleColor::CurrentColor()); EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor()); style->SetBorderBottomWidth(5); EXPECT_FALSE(style->HasBorderColorReferencingCurrentColor()); style->SetBorderBottomStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->HasBorderColorReferencingCurrentColor()); } TEST(ComputedStyleTest, BorderWidth) { scoped_refptr style = ComputedStyle::Create(); style->SetBorderBottomWidth(5); EXPECT_EQ(style->BorderBottomWidth(), 0); EXPECT_EQ(style->BorderBottom().Width(), 5); style->SetBorderBottomStyle(EBorderStyle::kSolid); EXPECT_EQ(style->BorderBottomWidth(), 5); EXPECT_EQ(style->BorderBottom().Width(), 5); } TEST(ComputedStyleTest, CursorList) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Create(); auto* gradient = MakeGarbageCollected( nullptr, nullptr, nullptr, nullptr, nullptr, cssvalue::kRepeating); auto* image_value = MakeGarbageCollected(*gradient); auto* other_image_value = MakeGarbageCollected(*gradient); EXPECT_TRUE(DataEquivalent(image_value, other_image_value)); style->AddCursor(image_value, false); other->AddCursor(other_image_value, false); EXPECT_EQ(*style, *other); } TEST(ComputedStyleTest, BorderStyle) { scoped_refptr style = ComputedStyle::Create(); scoped_refptr other = ComputedStyle::Create(); style->SetBorderLeftStyle(EBorderStyle::kSolid); style->SetBorderTopStyle(EBorderStyle::kSolid); style->SetBorderRightStyle(EBorderStyle::kSolid); style->SetBorderBottomStyle(EBorderStyle::kSolid); other->SetBorderLeftStyle(EBorderStyle::kSolid); other->SetBorderTopStyle(EBorderStyle::kSolid); other->SetBorderRightStyle(EBorderStyle::kSolid); other->SetBorderBottomStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderLeftWidth(1.0); EXPECT_FALSE(style->BorderSizeEquals(*other)); other->SetBorderLeftWidth(1.0); EXPECT_TRUE(style->BorderSizeEquals(*other)); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderTopWidth(1.0); EXPECT_FALSE(style->BorderSizeEquals(*other)); other->SetBorderTopWidth(1.0); EXPECT_TRUE(style->BorderSizeEquals(*other)); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderRightWidth(1.0); EXPECT_FALSE(style->BorderSizeEquals(*other)); other->SetBorderRightWidth(1.0); EXPECT_TRUE(style->BorderSizeEquals(*other)); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderBottomWidth(1.0); EXPECT_FALSE(style->BorderSizeEquals(*other)); other->SetBorderBottomWidth(1.0); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderLeftStyle(EBorderStyle::kHidden); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderLeftStyle(EBorderStyle::kNone); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderLeftStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderTopStyle(EBorderStyle::kHidden); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderTopStyle(EBorderStyle::kNone); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderTopStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderRightStyle(EBorderStyle::kHidden); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderRightStyle(EBorderStyle::kNone); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderRightStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->BorderSizeEquals(*other)); style->SetBorderBottomStyle(EBorderStyle::kHidden); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderBottomStyle(EBorderStyle::kNone); EXPECT_FALSE(style->BorderSizeEquals(*other)); style->SetBorderBottomStyle(EBorderStyle::kSolid); EXPECT_TRUE(style->BorderSizeEquals(*other)); } #define TEST_ANIMATION_FLAG(flag, inherited) \ do { \ auto style = ComputedStyle::Create(); \ auto other = ComputedStyle::Create(); \ EXPECT_FALSE(style->flag()); \ EXPECT_FALSE(other->flag()); \ style->Set##flag(true); \ EXPECT_TRUE(style->flag()); \ EXPECT_EQ(ComputedStyle::Difference::inherited, \ ComputedStyle::ComputeDifference(style.get(), other.get())); \ auto diff = style->VisualInvalidationDiff(*document, *other); \ EXPECT_TRUE(diff.HasDifference()); \ EXPECT_TRUE(diff.CompositingReasonsChanged()); \ } while (false) #define TEST_ANIMATION_FLAG_NO_DIFF(flag) \ do { \ auto style = ComputedStyle::Create(); \ auto other = ComputedStyle::Create(); \ EXPECT_FALSE(style->flag()); \ EXPECT_FALSE(other->flag()); \ style->Set##flag(true); \ EXPECT_TRUE(style->flag()); \ EXPECT_EQ(ComputedStyle::Difference::kEqual, \ ComputedStyle::ComputeDifference(style.get(), other.get())); \ auto diff = style->VisualInvalidationDiff(*document, *other); \ EXPECT_FALSE(diff.HasDifference()); \ EXPECT_FALSE(diff.CompositingReasonsChanged()); \ } while (false) TEST(ComputedStyleTest, AnimationFlags) { Persistent document = MakeGarbageCollected(); TEST_ANIMATION_FLAG(HasCurrentTransformAnimation, kNonInherited); TEST_ANIMATION_FLAG(HasCurrentOpacityAnimation, kNonInherited); TEST_ANIMATION_FLAG(HasCurrentFilterAnimation, kNonInherited); TEST_ANIMATION_FLAG(HasCurrentBackdropFilterAnimation, kNonInherited); TEST_ANIMATION_FLAG(SubtreeWillChangeContents, kInherited); TEST_ANIMATION_FLAG_NO_DIFF(IsRunningTransformAnimationOnCompositor); TEST_ANIMATION_FLAG_NO_DIFF(IsRunningOpacityAnimationOnCompositor); TEST_ANIMATION_FLAG_NO_DIFF(IsRunningFilterAnimationOnCompositor); TEST_ANIMATION_FLAG_NO_DIFF(IsRunningBackdropFilterAnimationOnCompositor); } TEST(ComputedStyleTest, CustomPropertiesEqual_Values) { auto dummy = std::make_unique(IntSize(0, 0)); css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "", "0px", false); scoped_refptr style1 = ComputedStyle::Create(); scoped_refptr style2 = ComputedStyle::Create(); using UnitType = CSSPrimitiveValue::UnitType; const auto* value1 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels); const auto* value2 = CSSNumericLiteralValue::Create(2.0, UnitType::kPixels); const auto* value3 = CSSNumericLiteralValue::Create(1.0, UnitType::kPixels); Vector properties; properties.push_back("--x"); style1->SetVariableValue("--x", value1, false); style2->SetVariableValue("--x", value1, false); EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2)); style1->SetVariableValue("--x", value1, false); style2->SetVariableValue("--x", value3, false); EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2)); style1->SetVariableValue("--x", value1, false); style2->SetVariableValue("--x", value2, false); EXPECT_FALSE(style1->CustomPropertiesEqual(properties, *style2)); } TEST(ComputedStyleTest, CustomPropertiesEqual_Data) { auto dummy = std::make_unique(IntSize(0, 0)); css_test_helpers::RegisterProperty(dummy->GetDocument(), "--x", "", "0px", false); scoped_refptr style1 = ComputedStyle::Create(); scoped_refptr style2 = ComputedStyle::Create(); auto value1 = css_test_helpers::CreateVariableData("foo"); auto value2 = css_test_helpers::CreateVariableData("bar"); auto value3 = css_test_helpers::CreateVariableData("foo"); Vector properties; properties.push_back("--x"); style1->SetVariableData("--x", value1, false); style2->SetVariableData("--x", value1, false); EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2)); style1->SetVariableData("--x", value1, false); style2->SetVariableData("--x", value3, false); EXPECT_TRUE(style1->CustomPropertiesEqual(properties, *style2)); style1->SetVariableData("--x", value1, false); style2->SetVariableData("--x", value2, false); EXPECT_FALSE(style1->CustomPropertiesEqual(properties, *style2)); } TEST(ComputedStyleTest, ApplyColorSchemeLightOnDark) { ScopedCSSColorSchemeForTest scoped_property_enabled(true); ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true); std::unique_ptr dummy_page_holder_ = std::make_unique(IntSize(0, 0), nullptr); const ComputedStyle* initial = &ComputedStyle::InitialStyle(); ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument()); color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark); StyleResolverState state(dummy_page_holder_->GetDocument(), *dummy_page_holder_->GetDocument().documentElement(), initial, initial); scoped_refptr style = ComputedStyle::Create(); state.SetStyle(style); CSSPropertyRef ref("color-scheme", state.GetDocument()); CSSValueList* dark_value = CSSValueList::CreateSpaceSeparated(); dark_value->Append(*CSSIdentifierValue::Create(CSSValueID::kDark)); CSSValueList* light_value = CSSValueList::CreateSpaceSeparated(); light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight)); To(ref.GetProperty()).ApplyValue(state, *dark_value); EXPECT_EQ(WebColorScheme::kDark, style->UsedColorScheme()); To(ref.GetProperty()).ApplyValue(state, *light_value); EXPECT_EQ(WebColorScheme::kLight, style->UsedColorScheme()); } TEST(ComputedStyleTest, ApplyInternalLightDarkColor) { using css_test_helpers::ParseDeclarationBlock; ScopedCSSColorSchemeForTest scoped_property_enabled(true); ScopedCSSColorSchemeUARenderingForTest scoped_ua_enabled(true); std::unique_ptr dummy_page_holder_ = std::make_unique(IntSize(0, 0), nullptr); const ComputedStyle* initial = &ComputedStyle::InitialStyle(); auto* ua_context = MakeGarbageCollected( kUASheetMode, SecureContextMode::kInsecureContext); const CSSValue* internal_light_dark = CSSParser::ParseSingleValue( CSSPropertyID::kColor, "-internal-light-dark-color(black, white)", ua_context); ColorSchemeHelper color_scheme_helper(dummy_page_holder_->GetDocument()); color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark); StyleResolverState state(dummy_page_holder_->GetDocument(), *dummy_page_holder_->GetDocument().documentElement(), initial, initial); StyleResolver& resolver = dummy_page_holder_->GetDocument().EnsureStyleResolver(); scoped_refptr style = ComputedStyle::Create(); state.SetStyle(style); CSSValueList* dark_value = CSSValueList::CreateSpaceSeparated(); dark_value->Append(*CSSIdentifierValue::Create(CSSValueID::kDark)); CSSValueList* light_value = CSSValueList::CreateSpaceSeparated(); light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight)); { ScopedCSSCascadeForTest scoped_cascade_enabled(false); To(GetCSSPropertyColor()).ApplyValue(state, *internal_light_dark); To(GetCSSPropertyColorScheme()).ApplyValue(state, *dark_value); resolver.ApplyCascadedColorValue(state); EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor())); To(GetCSSPropertyColor()).ApplyValue(state, *internal_light_dark); To(GetCSSPropertyColorScheme()).ApplyValue(state, *light_value); resolver.ApplyCascadedColorValue(state); EXPECT_EQ(Color::kBlack, style->VisitedDependentColor(GetCSSPropertyColor())); } { ScopedCSSCascadeForTest scoped_cascade_enabled(true); auto* color_declaration = ParseDeclarationBlock("color:-internal-light-dark-color(black, white)"); auto* dark_declaration = ParseDeclarationBlock("color-scheme:dark"); auto* light_declaration = ParseDeclarationBlock("color-scheme:light"); StyleCascade cascade1(state); cascade1.MutableMatchResult().AddMatchedProperties(color_declaration); cascade1.MutableMatchResult().AddMatchedProperties(dark_declaration); cascade1.Apply(); EXPECT_EQ(Color::kWhite, style->VisitedDependentColor(GetCSSPropertyColor())); StyleCascade cascade2(state); cascade2.MutableMatchResult().AddMatchedProperties(color_declaration); cascade2.MutableMatchResult().AddMatchedProperties(light_declaration); cascade2.Apply(); EXPECT_EQ(Color::kBlack, style->VisitedDependentColor(GetCSSPropertyColor())); } } TEST(ComputedStyleTest, StrokeWidthZoomAndCalc) { std::unique_ptr dummy_page_holder_ = std::make_unique(IntSize(0, 0), nullptr); const ComputedStyle* initial = &ComputedStyle::InitialStyle(); StyleResolverState state(dummy_page_holder_->GetDocument(), *dummy_page_holder_->GetDocument().documentElement(), initial, initial); scoped_refptr style = ComputedStyle::Create(); style->SetEffectiveZoom(1.5); state.SetStyle(style); auto* calc_value = CSSMathFunctionValue::Create(CSSMathExpressionNumericLiteral::Create( CSSNumericLiteralValue::Create(10, CSSPrimitiveValue::UnitType::kNumber), true)); To(GetCSSPropertyStrokeWidth()).ApplyValue(state, *calc_value); auto* computed_value = To(GetCSSPropertyStrokeWidth()) .CSSValueFromComputedStyleInternal(*style, style->SvgStyle(), nullptr /* layout_object */, false /* allow_visited_style */); ASSERT_TRUE(computed_value); auto* numeric_value = DynamicTo(computed_value); ASSERT_TRUE(numeric_value); EXPECT_TRUE(numeric_value->IsPx()); EXPECT_EQ(10, numeric_value->DoubleValue()); } } // namespace blink