mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Backed out changeset 09a6e2a57a02 (bug 1847503) for causing canvas failures on canvas-display-p3-drawImage.https.html
This commit is contained in:
parent
d34ac63bb2
commit
458130d63a
@ -46,14 +46,16 @@ fuzzy(0-1,0-580) == anim-css-fill-3-from-by-ident-ident.svg anim-css-fill-3-ref.
|
||||
fuzzy(0-1,0-580) == anim-css-fill-3-from-by-rgb-ident.svg anim-css-fill-3-ref.svg
|
||||
|
||||
# check handling of overflowing color values
|
||||
# Gamut mapping is now available and presentation colors are not clipped
|
||||
# any more. Because the result is dependent on hardware, we use a fairly high
|
||||
# fuzzy for now.
|
||||
# NOTE: Some of the tests below fail in Gecko because we compute
|
||||
# "from + by" as the animation end-point, and we clamp that final color value
|
||||
# (due to bug 515919) and use the clamped value for interpolation.
|
||||
# That's earlier than the SVG spec wants us to clamp -- we're only supposed to
|
||||
# clamp *final presentation values*.
|
||||
# (Reference: SVG 1.1 Appendix F.4)
|
||||
fuzzy(0-19,0-900) == anim-css-fill-overflow-1-by.svg anim-css-fill-overflow-1-ref.svg
|
||||
fuzzy(0-19,0-900) == anim-css-fill-overflow-1-from-by.svg anim-css-fill-overflow-1-ref.svg
|
||||
fuzzy(0-19,0-900) == anim-css-stopcolor-overflow-1-from-by.svg anim-css-stopcolor-overflow-1-ref.svg
|
||||
fuzzy(0-19,0-1444) == anim-css-floodcolor-overflow-1-from-by.svg anim-css-floodcolor-overflow-1-ref.svg
|
||||
== anim-css-fill-overflow-1-by.svg anim-css-fill-overflow-1-ref.svg
|
||||
== anim-css-fill-overflow-1-from-by.svg anim-css-fill-overflow-1-ref.svg # bug 515919
|
||||
== anim-css-stopcolor-overflow-1-from-by.svg anim-css-stopcolor-overflow-1-ref.svg # bug 515919
|
||||
== anim-css-floodcolor-overflow-1-from-by.svg anim-css-floodcolor-overflow-1-ref.svg # bug 515919
|
||||
|
||||
# 'fill-opacity' property
|
||||
fuzzy(0-1,0-885) == anim-css-fillopacity-1-by.svg anim-css-fillopacity-1-ref.svg
|
||||
|
@ -7,7 +7,8 @@
|
||||
#include "mozilla/StyleColorInlines.h"
|
||||
|
||||
#include "mozilla/ComputedStyle.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/ComputedStyleInlines.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsStyleStruct.h"
|
||||
|
||||
@ -64,33 +65,16 @@ StyleAbsoluteColor StyleAbsoluteColor::ToColorSpace(
|
||||
nscolor StyleAbsoluteColor::ToColor() const {
|
||||
auto srgb = ToColorSpace(StyleColorSpace::Srgb);
|
||||
|
||||
constexpr float MIN = 0.0f;
|
||||
constexpr float MAX = 1.0f;
|
||||
// TODO(tlouw): Needs gamut mapping here. Right now we just hard clip the
|
||||
// components to [0..1], which will yield invalid colors.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1626624
|
||||
auto red = std::clamp(srgb.components._0, 0.0f, 1.0f);
|
||||
auto green = std::clamp(srgb.components._1, 0.0f, 1.0f);
|
||||
auto blue = std::clamp(srgb.components._2, 0.0f, 1.0f);
|
||||
|
||||
// We KNOW the values are in srgb so we can do a quick gamut limit check
|
||||
// here and avoid calling into Servo_MapColorIntoGamutLimits and let it
|
||||
// return early anyway.
|
||||
auto isColorInGamut =
|
||||
(srgb.components._0 >= MIN && srgb.components._0 <= MAX &&
|
||||
srgb.components._1 >= MIN && srgb.components._1 <= MAX &&
|
||||
srgb.components._2 >= MIN && srgb.components._2 <= MAX);
|
||||
|
||||
if (!isColorInGamut) {
|
||||
if (StaticPrefs::layout_css_gamut_map_for_rendering_enabled()) {
|
||||
srgb = Servo_MapColorIntoGamutLimits(&srgb);
|
||||
} else {
|
||||
// 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.
|
||||
srgb.components._0 = std::clamp(srgb.components._0, 0.0f, 1.0f);
|
||||
srgb.components._1 = std::clamp(srgb.components._1, 0.0f, 1.0f);
|
||||
srgb.components._2 = std::clamp(srgb.components._2, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_RGBA(nsStyleUtil::FloatToColorComponent(srgb.components._0),
|
||||
nsStyleUtil::FloatToColorComponent(srgb.components._1),
|
||||
nsStyleUtil::FloatToColorComponent(srgb.components._2),
|
||||
return NS_RGBA(nsStyleUtil::FloatToColorComponent(red),
|
||||
nsStyleUtil::FloatToColorComponent(green),
|
||||
nsStyleUtil::FloatToColorComponent(blue),
|
||||
nsStyleUtil::FloatToColorComponent(srgb.alpha));
|
||||
}
|
||||
|
||||
|
@ -8413,12 +8413,6 @@
|
||||
value: 3
|
||||
mirror: always
|
||||
|
||||
# Should colors that are out of gamut for sRGB mapped to within limits?
|
||||
- name: layout.css.gamut-map-for-rendering.enabled
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
||||
# Is support for GeometryUtils.getBoxQuads enabled?
|
||||
- name: layout.css.getBoxQuads.enabled
|
||||
type: bool
|
||||
|
@ -1,196 +0,0 @@
|
||||
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Gamut mapping.
|
||||
//! <https://drafts.csswg.org/css-color-4/#gamut-mapping>
|
||||
|
||||
use super::{AbsoluteColor, ColorSpace};
|
||||
|
||||
impl AbsoluteColor {
|
||||
/// Map the components of this color into it's gamut limits if needed.
|
||||
/// <https://drafts.csswg.org/css-color-4/#binsearch>
|
||||
pub fn map_into_gamut_limits(&self) -> Self {
|
||||
// 1. if destination has no gamut limits (XYZ-D65, XYZ-D50, Lab, LCH,
|
||||
// Oklab, Oklch) return origin.
|
||||
if matches!(
|
||||
self.color_space,
|
||||
ColorSpace::Lab |
|
||||
ColorSpace::Lch |
|
||||
ColorSpace::Oklab |
|
||||
ColorSpace::Oklch |
|
||||
ColorSpace::XyzD50 |
|
||||
ColorSpace::XyzD65
|
||||
) {
|
||||
return self.clone();
|
||||
}
|
||||
|
||||
// If the color does have gamut limits, then we can check it here and
|
||||
// possibly skip the binary search.
|
||||
if self.in_gamut() {
|
||||
return self.clone();
|
||||
}
|
||||
|
||||
// 2. let origin_Oklch be origin converted from origin color space to
|
||||
// the Oklch color space.
|
||||
let origin_oklch = self.to_color_space(ColorSpace::Oklch);
|
||||
|
||||
// 3. if the Lightness of origin_Oklch is greater than or equal to
|
||||
// 100%, return { 1 1 1 origin.alpha } in destination.
|
||||
if origin_oklch.components.1 >= 1.0 {
|
||||
return AbsoluteColor::new(self.color_space, 1.0, 1.0, 1.0, self.alpha);
|
||||
}
|
||||
|
||||
// 4. if the Lightness of origin_Oklch is less than than or equal to
|
||||
// 0%, return { 0 0 0 origin.alpha } in destination.
|
||||
if origin_oklch.components.1 <= 0.0 {
|
||||
return AbsoluteColor::new(self.color_space, 0.0, 0.0, 0.0, self.alpha);
|
||||
}
|
||||
|
||||
// 5. let inGamut(color) be a function which returns true if, when
|
||||
// passed a color, that color is inside the gamut of destination.
|
||||
// For HSL and HWB, it returns true if the color is inside the gamut
|
||||
// of sRGB.
|
||||
// See [`Color::in_gamut`].
|
||||
|
||||
// 6. if inGamut(origin_Oklch) is true, convert origin_Oklch to
|
||||
// destination and return it as the gamut mapped color.
|
||||
// We already checked if the color is in gamut limits above.
|
||||
|
||||
// 7. otherwise, let delta(one, two) be a function which returns the
|
||||
// deltaEOK of color one compared to color two.
|
||||
// See the [`delta_eok`] function.
|
||||
|
||||
// 8. let JND be 0.02
|
||||
const JND: f32 = 0.02;
|
||||
|
||||
// 9. let epsilon be 0.0001
|
||||
const EPSILON: f32 = 0.0001;
|
||||
|
||||
// 10. let clip(color) be a function which converts color to
|
||||
// destination, converts all negative components to zero, converts
|
||||
// all components greater that one to one, and returns the result.
|
||||
// See [`Color::clip`].
|
||||
|
||||
// 11. set min to zero
|
||||
let mut min = 0.0;
|
||||
|
||||
// 12. set max to the Oklch chroma of origin_Oklch.
|
||||
let mut max = origin_oklch.components.1;
|
||||
|
||||
// 13. let min_inGamut be a boolean that represents when min is still
|
||||
// in gamut, and set it to true
|
||||
let mut min_in_gamut = true;
|
||||
|
||||
let mut current = origin_oklch.clone();
|
||||
let mut current_in_space = self.clone();
|
||||
|
||||
// If we are already within the JND threshold, return the clipped color
|
||||
// and skip the binary search.
|
||||
let clipped = current_in_space.clip();
|
||||
if delta_eok(&clipped, ¤t) < JND {
|
||||
return clipped;
|
||||
}
|
||||
|
||||
// 14. while (max - min is greater than epsilon) repeat the following
|
||||
// steps.
|
||||
while max - min > EPSILON {
|
||||
// 14.1. set chroma to (min + max) / 2
|
||||
let chroma = (min + max) / 2.0;
|
||||
|
||||
// 14.2. set current to origin_Oklch and then set the chroma
|
||||
// component to chroma
|
||||
current.components.1 = chroma;
|
||||
|
||||
current_in_space = current.to_color_space(self.color_space);
|
||||
|
||||
// 14.3. if min_inGamut is true and also if inGamut(current) is
|
||||
// true, set min to chroma and continue to repeat these steps.
|
||||
if min_in_gamut && current_in_space.in_gamut() {
|
||||
min = chroma;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 14.4. otherwise, if inGamut(current) is false carry out these
|
||||
// steps:
|
||||
|
||||
// 14.4.1. set clipped to clip(current)
|
||||
let clipped = current_in_space.clip();
|
||||
|
||||
// 14.4.2. set E to delta(clipped, current)
|
||||
let e = delta_eok(&clipped, ¤t);
|
||||
|
||||
// 14.4.3. if E < JND
|
||||
if e < JND {
|
||||
// 14.4.3.1. if (JND - E < epsilon) return clipped as the gamut
|
||||
// mapped color
|
||||
if JND - e < EPSILON {
|
||||
return clipped;
|
||||
}
|
||||
|
||||
// 14.4.3.2. otherwise
|
||||
|
||||
// 14.4.3.2.1. set min_inGamut to false
|
||||
min_in_gamut = false;
|
||||
|
||||
// 14.4.3.2.2. set min to chroma
|
||||
min = chroma;
|
||||
} else {
|
||||
// 14.4.4. otherwise, set max to chroma and continue to repeat
|
||||
// these steps
|
||||
max = chroma;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. return current as the gamut mapped color current
|
||||
current_in_space
|
||||
}
|
||||
|
||||
/// Clamp this color to within the [0..1] range.
|
||||
fn clip(&self) -> Self {
|
||||
let mut result = self.clone();
|
||||
result.components = result.components.map(|c| c.clamp(0.0, 1.0));
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns true if this color is within its gamut limits.
|
||||
fn in_gamut(&self) -> bool {
|
||||
macro_rules! in_range {
|
||||
($c:expr) => {{
|
||||
$c >= 0.0 && $c <= 1.0
|
||||
}};
|
||||
}
|
||||
|
||||
match self.color_space {
|
||||
ColorSpace::Hsl | ColorSpace::Hwb => self.to_color_space(ColorSpace::Srgb).in_gamut(),
|
||||
ColorSpace::Srgb |
|
||||
ColorSpace::SrgbLinear |
|
||||
ColorSpace::DisplayP3 |
|
||||
ColorSpace::A98Rgb |
|
||||
ColorSpace::ProphotoRgb |
|
||||
ColorSpace::Rec2020 => {
|
||||
in_range!(self.components.0) &&
|
||||
in_range!(self.components.1) &&
|
||||
in_range!(self.components.2)
|
||||
},
|
||||
ColorSpace::Lab |
|
||||
ColorSpace::Lch |
|
||||
ColorSpace::Oklab |
|
||||
ColorSpace::Oklch |
|
||||
ColorSpace::XyzD50 |
|
||||
ColorSpace::XyzD65 => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate deltaE OK (simple root sum of squares).
|
||||
/// <https://drafts.csswg.org/css-color-4/#color-difference-OK>
|
||||
fn delta_eok(reference: &AbsoluteColor, sample: &AbsoluteColor) -> f32 {
|
||||
// Delta is calculated in the oklab color space.
|
||||
let reference = reference.to_color_space(ColorSpace::Oklab);
|
||||
let sample = sample.to_color_space(ColorSpace::Oklab);
|
||||
|
||||
let diff = reference.components - sample.components;
|
||||
let diff = diff * diff;
|
||||
(diff.0 + diff.1 + diff.2).sqrt()
|
||||
}
|
@ -9,8 +9,6 @@ pub mod convert;
|
||||
pub mod mix;
|
||||
pub mod parsing;
|
||||
|
||||
mod gamut;
|
||||
|
||||
use cssparser::color::PredefinedColorSpace;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
@ -28,14 +26,6 @@ impl ColorComponents {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for ColorComponents {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for ColorComponents {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -7855,13 +7855,6 @@ pub extern "C" fn Servo_ConvertColorSpace(
|
||||
color.to_color_space(color_space)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_MapColorIntoGamutLimits(
|
||||
color: &AbsoluteColor
|
||||
) -> AbsoluteColor {
|
||||
color.map_into_gamut_limits()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
|
||||
value: &nsACString,
|
||||
|
@ -9,15 +9,15 @@ div { color: black; }
|
||||
<body>
|
||||
<script>
|
||||
const TEST_CASES = [
|
||||
["red", "green", "xyz", "color(xyz 0.24479 0.183508 0.0225301)"],
|
||||
["red", "green", "lab", "lab(50.2841 16.6263 59.2386)"],
|
||||
["red", "green", "lch", "lch(50.2841 87.4108 87.6208)"],
|
||||
["red", "green 90%", "xyz", "color(xyz 0.110709 0.160203 0.0250896)"],
|
||||
["red", "green 90%", "lab", "lab(47.079 -34.7167 50.7168)"],
|
||||
["red", "green 90%", "lch", "lch(47.079 71.8696 125.031)"],
|
||||
["red 90%", "green", "xyz", "color(xyz 0.378871 0.206813 0.0199707)"],
|
||||
["red 90%", "green", "lab", "lab(53.4893 67.9692 67.7605)"],
|
||||
["red 90%", "green", "lch", "lch(53.4893 102.952 50.2103)"],
|
||||
["red", "green", "xyz", "rgb(188, 92, 0)"],
|
||||
["red", "green", "lab", "rgb(161, 108, 0)"],
|
||||
["red", "green", "lch", "rgb(145, 116, 0)"],
|
||||
["red", "green 90%", "xyz", "rgb(89, 122, 0)"],
|
||||
["red", "green 90%", "lab", "rgb(65, 126, 0)"],
|
||||
["red", "green 90%", "lch", "rgb(49, 128, 0)"],
|
||||
["red 90%", "green", "xyz", "rgb(243, 40, 0)"],
|
||||
["red 90%", "green", "lab", "rgb(237, 55, 0)"],
|
||||
["red 90%", "green", "lch", "rgb(235, 59, 0)"],
|
||||
];
|
||||
|
||||
for (let [from, to, space, expected] of TEST_CASES) {
|
||||
|
@ -12,15 +12,15 @@ div { color: black; }
|
||||
<body>
|
||||
<script>
|
||||
const TEST_CASES = [
|
||||
["red", "green", "xyz", "color(xyz 0.24479 0.183508 0.0225301)"],
|
||||
["red", "green", "lab", "lab(50.2841 16.6263 59.2386)"],
|
||||
["red", "green", "lch", "lch(50.2841 87.4108 87.6208)"],
|
||||
["red", "green 90%", "xyz", "color(xyz 0.110709 0.160203 0.0250896)"],
|
||||
["red", "green 90%", "lab", "lab(47.079 -34.7167 50.7168)"],
|
||||
["red", "green 90%", "lch", "lch(47.079 71.8696 125.031)"],
|
||||
["red 90%", "green", "xyz", "color(xyz 0.378871 0.206813 0.0199707)"],
|
||||
["red 90%", "green", "lab", "lab(53.4893 67.9692 67.7605)"],
|
||||
["red 90%", "green", "lch", "lch(53.4893 102.952 50.2103)"],
|
||||
["red", "green", "xyz", "rgb(188, 92, 0)"],
|
||||
["red", "green", "lab", "rgb(161, 108, 0)"],
|
||||
["red", "green", "lch", "rgb(145, 116, 0)"],
|
||||
["red", "green 90%", "xyz", "rgb(89, 122, 0)"],
|
||||
["red", "green 90%", "lab", "rgb(65, 126, 0)"],
|
||||
["red", "green 90%", "lch", "rgb(49, 128, 0)"],
|
||||
["red 90%", "green", "xyz", "rgb(243, 40, 0)"],
|
||||
["red 90%", "green", "lab", "rgb(237, 55, 0)"],
|
||||
["red 90%", "green", "lch", "rgb(235, 59, 0)"],
|
||||
];
|
||||
|
||||
for (let [from, to, space, expected] of TEST_CASES) {
|
||||
|
Loading…
Reference in New Issue
Block a user