diff --git a/crates/typst/src/geom/color.rs b/crates/typst/src/geom/color.rs index ab827c19..3c86a306 100644 --- a/crates/typst/src/geom/color.rs +++ b/crates/typst/src/geom/color.rs @@ -295,8 +295,10 @@ impl Color { /// A linear Oklab color is represented internally by an array of four /// components: /// - lightness ([`ratio`]($ratio)) - /// - a ([`float`]($float) in the range `[-0.4..0.4]`) - /// - b ([`float`]($float) in the range `[-0.4..0.4]`) + /// - a ([`float`]($float) in the range `[-0.4..0.4]` + /// or [`ratio`]($ratio) in the range `[-100%..100%]`) + /// - b ([`float`]($float) in the range `[-0.4..0.4]` + /// or [`ratio`]($ratio) in the range `[-100%..100%]`) /// - alpha ([`ratio`]($ratio)) /// /// These components are also available using the @@ -317,10 +319,10 @@ impl Color { lightness: RatioComponent, /// The a ("green/red") component. #[external] - a: ABComponent, + a: ChromaComponent, /// The b ("blue/yellow") component. #[external] - b: ABComponent, + b: ChromaComponent, /// The alpha component. #[external] alpha: RatioComponent, @@ -334,8 +336,8 @@ impl Color { color.to_oklab() } else { let RatioComponent(l) = args.expect("lightness component")?; - let ABComponent(a) = args.expect("A component")?; - let ABComponent(b) = args.expect("B component")?; + let ChromaComponent(a) = args.expect("A component")?; + let ChromaComponent(b) = args.expect("B component")?; let RatioComponent(alpha) = args.eat()?.unwrap_or(RatioComponent(Ratio::one())); Self::Oklab(Oklab::new( @@ -357,7 +359,8 @@ impl Color { /// A linear Oklch color is represented internally by an array of four /// components: /// - lightness ([`ratio`]($ratio)) - /// - chroma ([`float`]($float) in the range `[-0.4..0.4]`) + /// - chroma ([`float`]($float) in the range `[0.0..0.4]` + /// or [`ratio`]($ratio) in the range `[0%..100%]`) /// - hue ([`angle`]($angle)) /// - alpha ([`ratio`]($ratio)) /// @@ -379,7 +382,7 @@ impl Color { lightness: RatioComponent, /// The chroma component. #[external] - chroma: ABComponent, + chroma: ChromaComponent, /// The hue component. #[external] hue: Angle, @@ -396,7 +399,7 @@ impl Color { color.to_oklch() } else { let RatioComponent(l) = args.expect("lightness component")?; - let ABComponent(c) = args.expect("chroma component")?; + let ChromaComponent(c) = args.expect("chroma component")?; let h: Angle = args.expect("hue component")?; let RatioComponent(alpha) = args.eat()?.unwrap_or(RatioComponent(Ratio::one())); @@ -1730,15 +1733,17 @@ cast! { }, } -/// A component that must be a ratio between -40% and 40%. -pub struct ABComponent(Ratio); +/// A component that must either be a value between: +/// - -100% and 100%, in which case it is relative to 0.4. +/// - -0.4 and 0.4, in which case it is taken literally. +pub struct ChromaComponent(Ratio); cast! { - ABComponent, - v: Ratio => if (-0.4 ..= 0.4).contains(&v.get()) { - Self(v) + ChromaComponent, + v: Ratio => if (-1.0 ..= 1.0).contains(&v.get()) { + Self(v * 0.4) } else { - bail!("ratio must be between -40% and 40%"); + bail!("ratio must be between -100% and 100%"); }, v: f64 => if (-0.4 ..= 0.4).contains(&v) { Self(Ratio::new(v)) diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ index 0ae17ae7..4c483786 100644 --- a/tests/typ/compiler/methods.typ +++ b/tests/typ/compiler/methods.typ @@ -109,6 +109,8 @@ #test-repr(cmyk(4%, 5%, 6%, 7%).components(), (4%, 5%, 6%, 7%)) #test-repr(oklab(10%, 0.2, 0.3).components(), (10%, 0.2, 0.3, 100%)) #test-repr(oklch(10%, 0.2, 90deg).components(), (10%, 0.2, 90deg, 100%)) +#test-repr(oklab(10%, 50%, 75%).components(), (10%, 0.2, 0.3, 100%)) +#test-repr(oklch(10%, 50%, 90deg).components(), (10%, 0.2, 90deg, 100%)) #test-repr(color.linear-rgb(10%, 20%, 30%).components(), (10%, 20%, 30%, 100%)) #test-repr(color.hsv(10deg, 20%, 30%).components(), (10deg, 20%, 30%, 100%)) #test-repr(color.hsl(10deg, 20%, 30%).components(), (10deg, 20%, 30%, 100%))