Files
Emilio Cobos Álvarez f6fe253bcf Bug 2054303 - Minor tweaks to attribute selector matching. r=firefox-style-system-reviewers,layout-reviewers,dshin
See the discussion in bug 2052936. The comparators are relatively
expensive.

Cleanup a bit nsStyleUtil includes while at it.

Differential Revision: https://phabricator.services.mozilla.com/D311685
2026-07-22 14:36:22 +00:00

175 lines
5.4 KiB
C++

/* 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<StyleColor>& o) {
return o.IsSome() && o.AsSome().DependsOnCurrentColor();
}
using ColorFunction = StyleColorFunction<StyleColor>;
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<StyleColor, StylePercentage>;
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