mirror of
https://github.com/typst/typst
synced 2025-08-24 19:54:14 +08:00
Compare commits
6 Commits
f364b3c323
...
3602d06a15
Author | SHA1 | Date | |
---|---|---|---|
|
3602d06a15 | ||
|
15302dbe7a | ||
|
4580daf307 | ||
|
d821633f50 | ||
|
3b35f0cecf | ||
|
fee6844045 |
@ -69,6 +69,10 @@ fn write_element(w: &mut Writer, element: &HtmlElement) -> SourceResult<()> {
|
||||
for (attr, value) in &element.attrs.0 {
|
||||
w.buf.push(' ');
|
||||
w.buf.push_str(&attr.resolve());
|
||||
|
||||
// If the string is empty, we can use shorthand syntax.
|
||||
// `<elem attr="">..</div` is equivalent to `<elem attr>..</div>`
|
||||
if !value.is_empty() {
|
||||
w.buf.push('=');
|
||||
w.buf.push('"');
|
||||
for c in value.chars() {
|
||||
@ -80,6 +84,7 @@ fn write_element(w: &mut Writer, element: &HtmlElement) -> SourceResult<()> {
|
||||
}
|
||||
w.buf.push('"');
|
||||
}
|
||||
}
|
||||
|
||||
w.buf.push('>');
|
||||
|
||||
|
@ -16,6 +16,21 @@ impl Duration {
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
|
||||
/// Decomposes the time into whole weeks, days, hours, minutes, and seconds.
|
||||
pub fn decompose(&self) -> [i64; 5] {
|
||||
let mut tmp = self.0;
|
||||
let weeks = tmp.whole_weeks();
|
||||
tmp -= weeks.weeks();
|
||||
let days = tmp.whole_days();
|
||||
tmp -= days.days();
|
||||
let hours = tmp.whole_hours();
|
||||
tmp -= hours.hours();
|
||||
let minutes = tmp.whole_minutes();
|
||||
tmp -= minutes.minutes();
|
||||
let seconds = tmp.whole_seconds();
|
||||
[weeks, days, hours, minutes, seconds]
|
||||
}
|
||||
}
|
||||
|
||||
#[scope]
|
||||
@ -118,34 +133,25 @@ impl Debug for Duration {
|
||||
|
||||
impl Repr for Duration {
|
||||
fn repr(&self) -> EcoString {
|
||||
let mut tmp = self.0;
|
||||
let [weeks, days, hours, minutes, seconds] = self.decompose();
|
||||
let mut vec = Vec::with_capacity(5);
|
||||
|
||||
let weeks = tmp.whole_seconds() / 604_800.0 as i64;
|
||||
if weeks != 0 {
|
||||
vec.push(eco_format!("weeks: {}", weeks.repr()));
|
||||
}
|
||||
tmp -= weeks.weeks();
|
||||
|
||||
let days = tmp.whole_days();
|
||||
if days != 0 {
|
||||
vec.push(eco_format!("days: {}", days.repr()));
|
||||
}
|
||||
tmp -= days.days();
|
||||
|
||||
let hours = tmp.whole_hours();
|
||||
if hours != 0 {
|
||||
vec.push(eco_format!("hours: {}", hours.repr()));
|
||||
}
|
||||
tmp -= hours.hours();
|
||||
|
||||
let minutes = tmp.whole_minutes();
|
||||
if minutes != 0 {
|
||||
vec.push(eco_format!("minutes: {}", minutes.repr()));
|
||||
}
|
||||
tmp -= minutes.minutes();
|
||||
|
||||
let seconds = tmp.whole_seconds();
|
||||
if seconds != 0 {
|
||||
vec.push(eco_format!("seconds: {}", seconds.repr()));
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ impl Func {
|
||||
) -> SourceResult<Value> {
|
||||
match &self.repr {
|
||||
Repr::Native(native) => {
|
||||
let value = (native.function)(engine, context, &mut args)?;
|
||||
let value = (native.function.0)(engine, context, &mut args)?;
|
||||
args.finish()?;
|
||||
Ok(value)
|
||||
}
|
||||
@ -491,8 +491,8 @@ pub trait NativeFunc {
|
||||
/// Defines a native function.
|
||||
#[derive(Debug)]
|
||||
pub struct NativeFuncData {
|
||||
/// Invokes the function from Typst.
|
||||
pub function: fn(&mut Engine, Tracked<Context>, &mut Args) -> SourceResult<Value>,
|
||||
/// The implementation of the function.
|
||||
pub function: NativeFuncPtr,
|
||||
/// The function's normal name (e.g. `align`), as exposed to Typst.
|
||||
pub name: &'static str,
|
||||
/// The function's title case name (e.g. `Align`).
|
||||
@ -504,11 +504,11 @@ pub struct NativeFuncData {
|
||||
/// Whether this function makes use of context.
|
||||
pub contextual: bool,
|
||||
/// Definitions in the scope of the function.
|
||||
pub scope: LazyLock<Scope>,
|
||||
pub scope: DynLazyLock<Scope>,
|
||||
/// A list of parameter information for each parameter.
|
||||
pub params: LazyLock<Vec<ParamInfo>>,
|
||||
pub params: DynLazyLock<Vec<ParamInfo>>,
|
||||
/// Information about the return value of this function.
|
||||
pub returns: LazyLock<CastInfo>,
|
||||
pub returns: DynLazyLock<CastInfo>,
|
||||
}
|
||||
|
||||
cast! {
|
||||
@ -516,6 +516,28 @@ cast! {
|
||||
self => Func::from(self).into_value(),
|
||||
}
|
||||
|
||||
/// A pointer to a native function's implementation.
|
||||
pub struct NativeFuncPtr(pub &'static NativeFuncSignature);
|
||||
|
||||
/// The signature of a native function's implementation.
|
||||
type NativeFuncSignature =
|
||||
dyn Fn(&mut Engine, Tracked<Context>, &mut Args) -> SourceResult<Value> + Send + Sync;
|
||||
|
||||
impl Debug for NativeFuncPtr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.pad("NativeFuncPtr(..)")
|
||||
}
|
||||
}
|
||||
|
||||
/// A `LazyLock` that uses a static closure for initialization instead of only
|
||||
/// working with function pointers.
|
||||
///
|
||||
/// Can be created from a normal function or closure by prepending with a `&`,
|
||||
/// e.g. `LazyLock::new(&|| "hello")`. Can be created from a dynamic closure
|
||||
/// by allocating and then leaking it. This is equivalent to having it
|
||||
/// statically allocated, but allows for it to be generated at runtime.
|
||||
type DynLazyLock<T> = LazyLock<T, &'static (dyn Fn() -> T + Send + Sync)>;
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParamInfo {
|
||||
|
@ -4,9 +4,12 @@ use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref, Not};
|
||||
|
||||
use typst_utils::Get;
|
||||
|
||||
use crate::diag::bail;
|
||||
use crate::foundations::{array, cast, Array, Resolve, Smart, StyleChain};
|
||||
use crate::layout::{Abs, Dir, Length, Ratio, Rel, Size};
|
||||
use crate::diag::{bail, HintedStrResult};
|
||||
use crate::foundations::{
|
||||
array, cast, Array, CastInfo, FromValue, IntoValue, Reflect, Resolve, Smart,
|
||||
StyleChain, Value,
|
||||
};
|
||||
use crate::layout::{Abs, Dir, Rel, Size};
|
||||
|
||||
/// A container with a horizontal and vertical component.
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
@ -275,40 +278,39 @@ impl BitAndAssign for Axes<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
cast! {
|
||||
Axes<Rel<Length>>,
|
||||
self => array![self.x, self.y].into_value(),
|
||||
array: Array => {
|
||||
let mut iter = array.into_iter();
|
||||
match (iter.next(), iter.next(), iter.next()) {
|
||||
(Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
|
||||
_ => bail!("point array must contain exactly two entries"),
|
||||
}
|
||||
},
|
||||
impl<T: Reflect> Reflect for Axes<T> {
|
||||
fn input() -> CastInfo {
|
||||
Array::input()
|
||||
}
|
||||
|
||||
cast! {
|
||||
Axes<Ratio>,
|
||||
self => array![self.x, self.y].into_value(),
|
||||
array: Array => {
|
||||
let mut iter = array.into_iter();
|
||||
match (iter.next(), iter.next(), iter.next()) {
|
||||
(Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
|
||||
_ => bail!("ratio array must contain exactly two entries"),
|
||||
}
|
||||
},
|
||||
fn output() -> CastInfo {
|
||||
Array::output()
|
||||
}
|
||||
|
||||
cast! {
|
||||
Axes<Length>,
|
||||
self => array![self.x, self.y].into_value(),
|
||||
array: Array => {
|
||||
fn castable(value: &Value) -> bool {
|
||||
Array::castable(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Axes<T> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
let array = value.cast::<Array>()?;
|
||||
let mut iter = array.into_iter();
|
||||
match (iter.next(), iter.next(), iter.next()) {
|
||||
(Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?),
|
||||
_ => bail!("length array must contain exactly two entries"),
|
||||
(Some(a), Some(b), None) => Ok(Axes::new(a.cast()?, b.cast()?)),
|
||||
_ => bail!(
|
||||
"array must contain exactly two items";
|
||||
hint: "the first item determines the value for the X axis \
|
||||
and the second item the value for the Y axis"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoValue> IntoValue for Axes<T> {
|
||||
fn into_value(self) -> Value {
|
||||
array![self.x.into_value(), self.y.into_value()].into_value()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
impl<T: Resolve> Resolve for Axes<T> {
|
||||
|
@ -836,7 +836,7 @@ fn to_typst(synt::Color { r, g, b, a }: synt::Color) -> Color {
|
||||
}
|
||||
|
||||
fn to_syn(color: Color) -> synt::Color {
|
||||
let [r, g, b, a] = color.to_rgb().to_vec4_u8();
|
||||
let (r, g, b, a) = color.to_rgb().into_format::<u8, u8>().into_components();
|
||||
synt::Color { r, g, b, a }
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_luma()
|
||||
Color::Luma(color.to_luma())
|
||||
} else {
|
||||
let Component(gray) =
|
||||
args.expect("gray component").unwrap_or(Component(Ratio::one()));
|
||||
@ -318,7 +318,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_oklab()
|
||||
Color::Oklab(color.to_oklab())
|
||||
} else {
|
||||
let RatioComponent(l) = args.expect("lightness component")?;
|
||||
let ChromaComponent(a) = args.expect("A component")?;
|
||||
@ -374,7 +374,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_oklch()
|
||||
Color::Oklch(color.to_oklch())
|
||||
} else {
|
||||
let RatioComponent(l) = args.expect("lightness component")?;
|
||||
let ChromaComponent(c) = args.expect("chroma component")?;
|
||||
@ -434,7 +434,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_linear_rgb()
|
||||
Color::LinearRgb(color.to_linear_rgb())
|
||||
} else {
|
||||
let Component(r) = args.expect("red component")?;
|
||||
let Component(g) = args.expect("green component")?;
|
||||
@ -505,7 +505,7 @@ impl Color {
|
||||
Ok(if let Some(string) = args.find::<Spanned<Str>>()? {
|
||||
Self::from_str(&string.v).at(string.span)?
|
||||
} else if let Some(color) = args.find::<Color>()? {
|
||||
color.to_rgb()
|
||||
Color::Rgb(color.to_rgb())
|
||||
} else {
|
||||
let Component(r) = args.expect("red component")?;
|
||||
let Component(g) = args.expect("green component")?;
|
||||
@ -565,7 +565,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_cmyk()
|
||||
Color::Cmyk(color.to_cmyk())
|
||||
} else {
|
||||
let RatioComponent(c) = args.expect("cyan component")?;
|
||||
let RatioComponent(m) = args.expect("magenta component")?;
|
||||
@ -622,7 +622,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_hsl()
|
||||
Color::Hsl(color.to_hsl())
|
||||
} else {
|
||||
let h: Angle = args.expect("hue component")?;
|
||||
let Component(s) = args.expect("saturation component")?;
|
||||
@ -679,7 +679,7 @@ impl Color {
|
||||
color: Color,
|
||||
) -> SourceResult<Color> {
|
||||
Ok(if let Some(color) = args.find::<Color>()? {
|
||||
color.to_hsv()
|
||||
Color::Hsv(color.to_hsv())
|
||||
} else {
|
||||
let h: Angle = args.expect("hue component")?;
|
||||
let Component(s) = args.expect("saturation component")?;
|
||||
@ -830,7 +830,7 @@ impl Color {
|
||||
/// omitted if it is equal to `ff` (255 / 100%).
|
||||
#[func]
|
||||
pub fn to_hex(self) -> EcoString {
|
||||
let [r, g, b, a] = self.to_rgb().to_vec4_u8();
|
||||
let (r, g, b, a) = self.to_rgb().into_format::<u8, u8>().into_components();
|
||||
if a != 255 {
|
||||
eco_format!("#{:02x}{:02x}{:02x}{:02x}", r, g, b, a)
|
||||
} else {
|
||||
@ -886,20 +886,21 @@ impl Color {
|
||||
/// The factor to saturate the color by.
|
||||
factor: Ratio,
|
||||
) -> SourceResult<Color> {
|
||||
let f = factor.get() as f32;
|
||||
Ok(match self {
|
||||
Self::Luma(_) => {
|
||||
bail!(
|
||||
Self::Luma(_) => bail!(
|
||||
span, "cannot saturate grayscale color";
|
||||
hint: "try converting your color to RGB first"
|
||||
);
|
||||
),
|
||||
Self::Hsl(c) => Self::Hsl(c.saturate(f)),
|
||||
Self::Hsv(c) => Self::Hsv(c.saturate(f)),
|
||||
Self::Oklab(_)
|
||||
| Self::Oklch(_)
|
||||
| Self::LinearRgb(_)
|
||||
| Self::Rgb(_)
|
||||
| Self::Cmyk(_) => {
|
||||
Color::Hsv(self.to_hsv().saturate(f)).to_space(self.space())
|
||||
}
|
||||
Self::Oklab(_) => self.to_hsv().saturate(span, factor)?.to_oklab(),
|
||||
Self::Oklch(_) => self.to_hsv().saturate(span, factor)?.to_oklch(),
|
||||
Self::LinearRgb(_) => self.to_hsv().saturate(span, factor)?.to_linear_rgb(),
|
||||
Self::Rgb(_) => self.to_hsv().saturate(span, factor)?.to_rgb(),
|
||||
Self::Cmyk(_) => self.to_hsv().saturate(span, factor)?.to_cmyk(),
|
||||
Self::Hsl(c) => Self::Hsl(c.saturate(factor.get() as f32)),
|
||||
Self::Hsv(c) => Self::Hsv(c.saturate(factor.get() as f32)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -911,20 +912,21 @@ impl Color {
|
||||
/// The factor to desaturate the color by.
|
||||
factor: Ratio,
|
||||
) -> SourceResult<Color> {
|
||||
let f = factor.get() as f32;
|
||||
Ok(match self {
|
||||
Self::Luma(_) => {
|
||||
bail!(
|
||||
Self::Luma(_) => bail!(
|
||||
span, "cannot desaturate grayscale color";
|
||||
hint: "try converting your color to RGB first"
|
||||
);
|
||||
),
|
||||
Self::Hsl(c) => Self::Hsl(c.desaturate(f)),
|
||||
Self::Hsv(c) => Self::Hsv(c.desaturate(f)),
|
||||
Self::Oklab(_)
|
||||
| Self::Oklch(_)
|
||||
| Self::LinearRgb(_)
|
||||
| Self::Rgb(_)
|
||||
| Self::Cmyk(_) => {
|
||||
Color::Hsv(self.to_hsv().desaturate(f)).to_space(self.space())
|
||||
}
|
||||
Self::Oklab(_) => self.to_hsv().desaturate(span, factor)?.to_oklab(),
|
||||
Self::Oklch(_) => self.to_hsv().desaturate(span, factor)?.to_oklch(),
|
||||
Self::LinearRgb(_) => self.to_hsv().desaturate(span, factor)?.to_linear_rgb(),
|
||||
Self::Rgb(_) => self.to_hsv().desaturate(span, factor)?.to_rgb(),
|
||||
Self::Cmyk(_) => self.to_hsv().desaturate(span, factor)?.to_cmyk(),
|
||||
Self::Hsl(c) => Self::Hsl(c.desaturate(factor.get() as f32)),
|
||||
Self::Hsv(c) => Self::Hsv(c.desaturate(factor.get() as f32)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -994,23 +996,17 @@ impl Color {
|
||||
) -> SourceResult<Color> {
|
||||
Ok(match space {
|
||||
ColorSpace::Oklch => {
|
||||
let Self::Oklch(oklch) = self.to_oklch() else {
|
||||
unreachable!();
|
||||
};
|
||||
let oklch = self.to_oklch();
|
||||
let rotated = oklch.shift_hue(angle.to_deg() as f32);
|
||||
Self::Oklch(rotated).to_space(self.space())
|
||||
}
|
||||
ColorSpace::Hsl => {
|
||||
let Self::Hsl(hsl) = self.to_hsl() else {
|
||||
unreachable!();
|
||||
};
|
||||
let hsl = self.to_hsl();
|
||||
let rotated = hsl.shift_hue(angle.to_deg() as f32);
|
||||
Self::Hsl(rotated).to_space(self.space())
|
||||
}
|
||||
ColorSpace::Hsv => {
|
||||
let Self::Hsv(hsv) = self.to_hsv() else {
|
||||
unreachable!();
|
||||
};
|
||||
let hsv = self.to_hsv();
|
||||
let rotated = hsv.shift_hue(angle.to_deg() as f32);
|
||||
Self::Hsv(rotated).to_space(self.space())
|
||||
}
|
||||
@ -1281,19 +1277,19 @@ impl Color {
|
||||
|
||||
pub fn to_space(self, space: ColorSpace) -> Self {
|
||||
match space {
|
||||
ColorSpace::Oklab => self.to_oklab(),
|
||||
ColorSpace::Oklch => self.to_oklch(),
|
||||
ColorSpace::Srgb => self.to_rgb(),
|
||||
ColorSpace::LinearRgb => self.to_linear_rgb(),
|
||||
ColorSpace::Hsl => self.to_hsl(),
|
||||
ColorSpace::Hsv => self.to_hsv(),
|
||||
ColorSpace::Cmyk => self.to_cmyk(),
|
||||
ColorSpace::D65Gray => self.to_luma(),
|
||||
ColorSpace::D65Gray => Self::Luma(self.to_luma()),
|
||||
ColorSpace::Oklab => Self::Oklab(self.to_oklab()),
|
||||
ColorSpace::Oklch => Self::Oklch(self.to_oklch()),
|
||||
ColorSpace::Srgb => Self::Rgb(self.to_rgb()),
|
||||
ColorSpace::LinearRgb => Self::LinearRgb(self.to_linear_rgb()),
|
||||
ColorSpace::Cmyk => Self::Cmyk(self.to_cmyk()),
|
||||
ColorSpace::Hsl => Self::Hsl(self.to_hsl()),
|
||||
ColorSpace::Hsv => Self::Hsv(self.to_hsv()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_luma(self) -> Self {
|
||||
Self::Luma(match self {
|
||||
pub fn to_luma(self) -> Luma {
|
||||
match self {
|
||||
Self::Luma(c) => c,
|
||||
Self::Oklab(c) => Luma::from_color(c),
|
||||
Self::Oklch(c) => Luma::from_color(c),
|
||||
@ -1302,11 +1298,11 @@ impl Color {
|
||||
Self::Cmyk(c) => Luma::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Luma::from_color(c),
|
||||
Self::Hsv(c) => Luma::from_color(c),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_oklab(self) -> Self {
|
||||
Self::Oklab(match self {
|
||||
pub fn to_oklab(self) -> Oklab {
|
||||
match self {
|
||||
Self::Luma(c) => Oklab::from_color(c),
|
||||
Self::Oklab(c) => c,
|
||||
Self::Oklch(c) => Oklab::from_color(c),
|
||||
@ -1315,11 +1311,11 @@ impl Color {
|
||||
Self::Cmyk(c) => Oklab::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Oklab::from_color(c),
|
||||
Self::Hsv(c) => Oklab::from_color(c),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_oklch(self) -> Self {
|
||||
Self::Oklch(match self {
|
||||
pub fn to_oklch(self) -> Oklch {
|
||||
match self {
|
||||
Self::Luma(c) => Oklch::from_color(c),
|
||||
Self::Oklab(c) => Oklch::from_color(c),
|
||||
Self::Oklch(c) => c,
|
||||
@ -1328,11 +1324,11 @@ impl Color {
|
||||
Self::Cmyk(c) => Oklch::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Oklch::from_color(c),
|
||||
Self::Hsv(c) => Oklch::from_color(c),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_rgb(self) -> Self {
|
||||
Self::Rgb(match self {
|
||||
pub fn to_rgb(self) -> Rgb {
|
||||
match self {
|
||||
Self::Luma(c) => Rgb::from_color(c),
|
||||
Self::Oklab(c) => Rgb::from_color(c),
|
||||
Self::Oklch(c) => Rgb::from_color(c),
|
||||
@ -1341,11 +1337,11 @@ impl Color {
|
||||
Self::Cmyk(c) => Rgb::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Rgb::from_color(c),
|
||||
Self::Hsv(c) => Rgb::from_color(c),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_linear_rgb(self) -> Self {
|
||||
Self::LinearRgb(match self {
|
||||
pub fn to_linear_rgb(self) -> LinearRgb {
|
||||
match self {
|
||||
Self::Luma(c) => LinearRgb::from_color(c),
|
||||
Self::Oklab(c) => LinearRgb::from_color(c),
|
||||
Self::Oklch(c) => LinearRgb::from_color(c),
|
||||
@ -1354,11 +1350,11 @@ impl Color {
|
||||
Self::Cmyk(c) => LinearRgb::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Rgb::from_color(c).into_linear(),
|
||||
Self::Hsv(c) => Rgb::from_color(c).into_linear(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_cmyk(self) -> Self {
|
||||
Self::Cmyk(match self {
|
||||
pub fn to_cmyk(self) -> Cmyk {
|
||||
match self {
|
||||
Self::Luma(c) => Cmyk::from_luma(c),
|
||||
Self::Oklab(c) => Cmyk::from_rgba(Rgb::from_color(c)),
|
||||
Self::Oklch(c) => Cmyk::from_rgba(Rgb::from_color(c)),
|
||||
@ -1367,11 +1363,11 @@ impl Color {
|
||||
Self::Cmyk(c) => c,
|
||||
Self::Hsl(c) => Cmyk::from_rgba(Rgb::from_color(c)),
|
||||
Self::Hsv(c) => Cmyk::from_rgba(Rgb::from_color(c)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_hsl(self) -> Self {
|
||||
Self::Hsl(match self {
|
||||
pub fn to_hsl(self) -> Hsl {
|
||||
match self {
|
||||
Self::Luma(c) => Hsl::from_color(c),
|
||||
Self::Oklab(c) => Hsl::from_color(c),
|
||||
Self::Oklch(c) => Hsl::from_color(c),
|
||||
@ -1380,11 +1376,11 @@ impl Color {
|
||||
Self::Cmyk(c) => Hsl::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => c,
|
||||
Self::Hsv(c) => Hsl::from_color(c),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_hsv(self) -> Self {
|
||||
Self::Hsv(match self {
|
||||
pub fn to_hsv(self) -> Hsv {
|
||||
match self {
|
||||
Self::Luma(c) => Hsv::from_color(c),
|
||||
Self::Oklab(c) => Hsv::from_color(c),
|
||||
Self::Oklch(c) => Hsv::from_color(c),
|
||||
@ -1393,7 +1389,7 @@ impl Color {
|
||||
Self::Cmyk(c) => Hsv::from_color(c.to_rgba()),
|
||||
Self::Hsl(c) => Hsv::from_color(c),
|
||||
Self::Hsv(c) => c,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,15 +315,15 @@ fn create_func_data(func: &Func) -> TokenStream {
|
||||
|
||||
quote! {
|
||||
#foundations::NativeFuncData {
|
||||
function: #closure,
|
||||
function: #foundations::NativeFuncPtr(&#closure),
|
||||
name: #name,
|
||||
title: #title,
|
||||
docs: #docs,
|
||||
keywords: &[#(#keywords),*],
|
||||
contextual: #contextual,
|
||||
scope: ::std::sync::LazyLock::new(|| #scope),
|
||||
params: ::std::sync::LazyLock::new(|| ::std::vec![#(#params),*]),
|
||||
returns: ::std::sync::LazyLock::new(|| <#returns as #foundations::Reflect>::output()),
|
||||
scope: ::std::sync::LazyLock::new(&|| #scope),
|
||||
params: ::std::sync::LazyLock::new(&|| ::std::vec![#(#params),*]),
|
||||
returns: ::std::sync::LazyLock::new(&|| <#returns as #foundations::Reflect>::output()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,13 +255,13 @@ pub fn to_sk_paint<'a>(
|
||||
}
|
||||
|
||||
pub fn to_sk_color(color: Color) -> sk::Color {
|
||||
let [r, g, b, a] = color.to_rgb().to_vec4();
|
||||
let (r, g, b, a) = color.to_rgb().into_components();
|
||||
sk::Color::from_rgba(r, g, b, a)
|
||||
.expect("components must always be in the range [0..=1]")
|
||||
}
|
||||
|
||||
pub fn to_sk_color_u8(color: Color) -> sk::ColorU8 {
|
||||
let [r, g, b, a] = color.to_rgb().to_vec4_u8();
|
||||
let (r, g, b, a) = color.to_rgb().into_format::<u8, u8>().into_components();
|
||||
sk::ColorU8::from_rgba(r, g, b, a)
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub use self::scalar::Scalar;
|
||||
#[doc(hidden)]
|
||||
pub use once_cell;
|
||||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::iter::{Chain, Flatten, Rev};
|
||||
use std::num::{NonZeroU32, NonZeroUsize};
|
||||
@ -52,6 +52,25 @@ where
|
||||
Wrapper(f)
|
||||
}
|
||||
|
||||
/// Turn a closure into a struct implementing [`Display`].
|
||||
pub fn display<F>(f: F) -> impl Display
|
||||
where
|
||||
F: Fn(&mut Formatter) -> std::fmt::Result,
|
||||
{
|
||||
struct Wrapper<F>(F);
|
||||
|
||||
impl<F> Display for Wrapper<F>
|
||||
where
|
||||
F: Fn(&mut Formatter) -> std::fmt::Result,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.0(f)
|
||||
}
|
||||
}
|
||||
|
||||
Wrapper(f)
|
||||
}
|
||||
|
||||
/// Calculate a 128-bit siphash of a value.
|
||||
pub fn hash128<T: Hash + ?Sized>(value: &T) -> u128 {
|
||||
let mut state = SipHasher13::new();
|
||||
|
@ -84,7 +84,8 @@
|
||||
--- line-bad-point-array ---
|
||||
// Test errors.
|
||||
|
||||
// Error: 12-19 point array must contain exactly two entries
|
||||
// Error: 12-19 array must contain exactly two items
|
||||
// Hint: 12-19 the first item determines the value for the X axis and the second item the value for the Y axis
|
||||
#line(end: (50pt,))
|
||||
|
||||
--- line-bad-point-component-type ---
|
||||
|
@ -76,7 +76,8 @@
|
||||
#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%)))
|
||||
|
||||
--- path-bad-point-array ---
|
||||
// Error: 7-31 point array must contain exactly two entries
|
||||
// Error: 7-31 array must contain exactly two items
|
||||
// Hint: 7-31 the first item determines the value for the X axis and the second item the value for the Y axis
|
||||
// Warning: 2-6 the `path` function is deprecated, use `curve` instead
|
||||
#path(((0%, 0%), (0%, 0%, 0%)))
|
||||
|
||||
|
@ -49,7 +49,8 @@
|
||||
)
|
||||
|
||||
--- polygon-bad-point-array ---
|
||||
// Error: 10-17 point array must contain exactly two entries
|
||||
// Error: 10-17 array must contain exactly two items
|
||||
// Hint: 10-17 the first item determines the value for the X axis and the second item the value for the Y axis
|
||||
#polygon((50pt,))
|
||||
|
||||
--- polygon-infinite-size ---
|
||||
|
Loading…
x
Reference in New Issue
Block a user