/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ComputedStyle.h" #include "mozilla/ComputedStyleInlines.h" #include "mozilla/StaticPrefs_layout.h" #include "mozilla/StyleColorInlines.h" #include "nsIFrame.h" #include "nsStyleStruct.h" #include "nsStyleUtil.h" namespace mozilla { template <> bool StyleColor::MaybeTransparent() const { // We know that the color is opaque when it's a numeric color with // alpha == 1.0. return !IsAbsolute() || AsAbsolute().alpha != 1.0f; } template <> bool StyleColor::DependsOnCurrentColor() const; static bool OptionalDependsOnCurrentColor(const StyleOptional& o) { return o.IsSome() && o.AsSome().DependsOnCurrentColor(); } using ColorFunction = StyleColorFunction; template <> bool ColorFunction::DependsOnCurrentColor() const { switch (tag) { case Tag::Rgb: return OptionalDependsOnCurrentColor(AsRgb()._0); case Tag::Hsl: return OptionalDependsOnCurrentColor(AsHsl()._0); case Tag::Hwb: return OptionalDependsOnCurrentColor(AsHwb()._0); case Tag::Lab: return OptionalDependsOnCurrentColor(AsLab()._0); case Tag::Lch: return OptionalDependsOnCurrentColor(AsLch()._0); case Tag::Oklab: return OptionalDependsOnCurrentColor(AsOklab()._0); case Tag::Oklch: return OptionalDependsOnCurrentColor(AsOklch()._0); case Tag::Color: return OptionalDependsOnCurrentColor(AsColor()._0); case Tag::Alpha: return AsAlpha()._0.DependsOnCurrentColor(); } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown color function type"); } using ColorMix = StyleGenericColorMix; template <> bool ColorMix::DependsOnCurrentColor() const { for (const auto& colorMixItem : items.AsSpan()) { if (colorMixItem.color.DependsOnCurrentColor()) { return true; } } return false; } template <> bool StyleColor::DependsOnCurrentColor() const { switch (tag) { case Tag::Absolute: return false; case Tag::ColorFunction: return AsColorFunction()->DependsOnCurrentColor(); case Tag::CurrentColor: return true; case Tag::ColorMix: return AsColorMix()->DependsOnCurrentColor(); case Tag::ContrastColor: return AsContrastColor()->DependsOnCurrentColor(); } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown color type"); } template <> StyleAbsoluteColor StyleColor::ResolveColor( const StyleAbsoluteColor& aForegroundColor) const { if (IsAbsolute()) { return AsAbsolute(); } if (IsCurrentColor()) { return aForegroundColor; } return Servo_ResolveColor(this, &aForegroundColor); } template <> nscolor StyleColor::CalcColor(nscolor aColor) const { return ResolveColor(StyleAbsoluteColor::FromColor(aColor)).ToColor(); } template <> nscolor StyleColor::CalcColor( const StyleAbsoluteColor& aForegroundColor) const { return ResolveColor(aForegroundColor).ToColor(); } template <> nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const { return ResolveColor(aStyle.StyleText()->mColor).ToColor(); } template <> nscolor StyleColor::CalcColor(const nsIFrame* aFrame) const { return ResolveColor(aFrame->StyleText()->mColor).ToColor(); } StyleAbsoluteColor StyleAbsoluteColor::ToColorSpace( StyleColorSpace aColorSpace) const { return Servo_ConvertColorSpace(this, aColorSpace); } nscolor StyleAbsoluteColor::ToColor() const { constexpr StyleColorSpace DEST_COLOR_SPACE = StyleColorSpace::Srgb; constexpr float MIN = 0.0f; constexpr float MAX = 1.0f; auto translatedColor = ToColorSpace(DEST_COLOR_SPACE); // We KNOW the values are in srgb so we can do a quick gamut limit check // here and avoid calling into Servo_GamutMapColorUsing* and let it // return early anyway. auto isColorInGamut = translatedColor.components._0 >= MIN && translatedColor.components._0 <= MAX && translatedColor.components._1 >= MIN && translatedColor.components._1 <= MAX && translatedColor.components._2 >= MIN && translatedColor.components._2 <= MAX; if (!isColorInGamut) { switch (StaticPrefs::layout_css_gamut_mapping_method()) { case 1: translatedColor = Servo_GamutMapColorUsingBinarySearchMINDE(this, DEST_COLOR_SPACE); break; case 2: translatedColor = Servo_GamutMapColorUsingRaytrace(this, DEST_COLOR_SPACE); break; default: // 0 (default), or any other value // If gamut mapping is not enabled, we just naively clip the colors at // sRGB gamut limits. This will go away completely when gamut mapping is // enabled. translatedColor.components._0 = std::clamp(translatedColor.components._0, MIN, MAX); translatedColor.components._1 = std::clamp(translatedColor.components._1, MIN, MAX); translatedColor.components._2 = std::clamp(translatedColor.components._2, MIN, MAX); } } return NS_RGBA( nsStyleUtil::FloatToColorComponent(translatedColor.components._0), nsStyleUtil::FloatToColorComponent(translatedColor.components._1), nsStyleUtil::FloatToColorComponent(translatedColor.components._2), nsStyleUtil::FloatToColorComponent(translatedColor.alpha)); } } // namespace mozilla