mirror of
https://github.com/typst/typst
synced 2025-06-28 08:12:53 +08:00
Test [rgb] 🎨
This commit is contained in:
parent
0adbfe894a
commit
b02ba84264
17
src/color.rs
17
src/color.rs
@ -29,14 +29,14 @@ pub struct RgbaColor {
|
||||
}
|
||||
|
||||
impl RgbaColor {
|
||||
/// Constructs a new color.
|
||||
/// Constructs a new, unhealed color.
|
||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self { r, g, b, a, healed: false }
|
||||
}
|
||||
|
||||
/// Constructs a new color with the healed property set to true.
|
||||
pub fn new_healed(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self { r, g, b, a, healed: true }
|
||||
/// Constructs a new color with a configurable healed status.
|
||||
pub fn with_healed(r: u8, g: u8, b: u8, a: u8, healed: bool) -> Self {
|
||||
Self { r, g, b, a, healed }
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,11 +87,10 @@ impl Debug for RgbaColor {
|
||||
self.r, self.g, self.b, self.a,
|
||||
)?;
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"#{:02x}{:02x}{:02x}{:02x}",
|
||||
self.r, self.g, self.b, self.a,
|
||||
)?;
|
||||
write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
|
||||
if self.a != 255 {
|
||||
write!(f, "{:02x}", self.a)?;
|
||||
}
|
||||
}
|
||||
if self.healed {
|
||||
f.write_str(" [healed]")?;
|
||||
|
@ -117,30 +117,33 @@ pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
/// `rgb`: Create an RGB(A) color.
|
||||
///
|
||||
/// # Positional arguments
|
||||
/// - The red component (integer between 0 and 255).
|
||||
/// - The green component (integer between 0 and 255).
|
||||
/// - The blue component (integer between 0 and 255).
|
||||
/// - The alpha component (optional, integer between 0 and 255).
|
||||
/// - The red component (float between 0.0 and 1.0).
|
||||
/// - The green component (float between 0.0 and 1.0).
|
||||
/// - The blue component (float between 0.0 and 1.0).
|
||||
/// - The alpha component (optional, float between 0.0 and 1.0).
|
||||
pub fn rgb(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
let r = args.need::<_, Spanned<i64>>(ctx, 0, "red value");
|
||||
let g = args.need::<_, Spanned<i64>>(ctx, 1, "green value");
|
||||
let b = args.need::<_, Spanned<i64>>(ctx, 2, "blue value");
|
||||
let a = args.get::<_, Spanned<i64>>(ctx, 3);
|
||||
let r = args.need::<_, Spanned<f64>>(ctx, 0, "red component");
|
||||
let g = args.need::<_, Spanned<f64>>(ctx, 1, "green component");
|
||||
let b = args.need::<_, Spanned<f64>>(ctx, 2, "blue component");
|
||||
let a = args.get::<_, Spanned<f64>>(ctx, 3);
|
||||
args.done(ctx);
|
||||
|
||||
let mut clamp = |component: Option<Spanned<i64>>, default| {
|
||||
let mut healed = r.is_none() || g.is_none() || b.is_none();
|
||||
let mut clamp = |component: Option<Spanned<f64>>, default| {
|
||||
component.map_or(default, |c| {
|
||||
if c.v < 0 || c.v > 255 {
|
||||
ctx.diag(error!(c.span, "should be between 0 and 255"));
|
||||
if c.v < 0.0 || c.v > 1.0 {
|
||||
ctx.diag(error!(c.span, "should be between 0.0 and 1.0"));
|
||||
healed = true;
|
||||
}
|
||||
c.v.max(0).min(255) as u8
|
||||
(c.v.max(0.0).min(1.0) * 255.0).round() as u8
|
||||
})
|
||||
};
|
||||
|
||||
Value::Color(RgbaColor::new(
|
||||
Value::Color(RgbaColor::with_healed(
|
||||
clamp(r, 0),
|
||||
clamp(g, 0),
|
||||
clamp(b, 0),
|
||||
clamp(a, 255),
|
||||
healed,
|
||||
))
|
||||
}
|
||||
|
@ -196,6 +196,7 @@ fn bracket_subheader(p: &mut Parser) -> ExprCall {
|
||||
|
||||
p.skip_white();
|
||||
let args = if p.eat_if(Token::Colon) {
|
||||
p.skip_white();
|
||||
p.span(|p| dict_contents(p).0)
|
||||
} else {
|
||||
// Ignore the rest if there's no colon.
|
||||
@ -488,7 +489,7 @@ fn color(p: &mut Parser, hex: &str, start: Pos) -> RgbaColor {
|
||||
RgbaColor::from_str(hex).unwrap_or_else(|_| {
|
||||
// Heal color by assuming black.
|
||||
p.diag(error!(start .. p.pos(), "invalid color"));
|
||||
RgbaColor::new_healed(0, 0, 0, 255)
|
||||
RgbaColor::with_healed(0, 0, 0, 255, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -193,6 +193,7 @@ macro_rules! d {
|
||||
/// and the source of their test case if they aren't.
|
||||
///
|
||||
/// When `cmp_spans` is false, spans are ignored.
|
||||
#[track_caller]
|
||||
pub fn check<T>(src: &str, exp: T, found: T, cmp_spans: bool)
|
||||
where
|
||||
T: Debug + PartialEq,
|
||||
@ -435,7 +436,7 @@ fn test_parse_values() {
|
||||
e!("[val: [hi]]" => );
|
||||
|
||||
// Healed colors.
|
||||
v!("#12345" => Color(RgbaColor::new_healed(0, 0, 0, 0xff)));
|
||||
v!("#12345" => Color(RgbaColor::with_healed(0, 0, 0, 0xff, true)));
|
||||
e!("[val: #12345]" => s(6, 12, "invalid color"));
|
||||
e!("[val: #a5]" => s(6, 9, "invalid color"));
|
||||
e!("[val: #14b2ah]" => s(6, 13, "invalid color"));
|
||||
@ -447,7 +448,7 @@ fn test_parse_values() {
|
||||
s(13, 13, "expected closing bracket"));
|
||||
|
||||
// Spanned.
|
||||
ts!("[val: 1.4]" => s(0, 10, F!(s(1, 4, "val"), 5 .. 9; s(6, 9, Float(1.4)))));
|
||||
ts!("[val: 1.4]" => s(0, 10, F!(s(1, 4, "val"), 6 .. 9; s(6, 9, Float(1.4)))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -485,7 +486,7 @@ fn test_parse_expressions() {
|
||||
|
||||
// Spanned.
|
||||
ts!("[val: 1 + 3]" => s(0, 12, F!(
|
||||
s(1, 4, "val"), 5 .. 11; s(6, 11, Binary(
|
||||
s(1, 4, "val"), 6 .. 11; s(6, 11, Binary(
|
||||
s(8, 9, Add),
|
||||
s(6, 7, Int(1)),
|
||||
s(10, 11, Int(3))
|
||||
@ -493,7 +494,7 @@ fn test_parse_expressions() {
|
||||
)));
|
||||
|
||||
// Span of parenthesized expression contains parens.
|
||||
ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"), 5 .. 9; s(6, 9, Int(1)))));
|
||||
ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"), 6 .. 9; s(6, 9, Int(1)))));
|
||||
|
||||
// Invalid expressions.
|
||||
v!("4pt--" => Length(4.0, Pt));
|
||||
@ -522,7 +523,7 @@ fn test_parse_dicts() {
|
||||
// Spanned with spacing around keyword arguments.
|
||||
ts!("[val: \n hi \n = /* //\n */ \"s\n\"]" => s(0, 30, F!(
|
||||
s(1, 4, "val"),
|
||||
5 .. 29; s(8, 10, "hi") => s(25, 29, Str("s\n"))
|
||||
8 .. 29; s(8, 10, "hi") => s(25, 29, Str("s\n"))
|
||||
)));
|
||||
e!("[val: \n hi \n = /* //\n */ \"s\n\"]" => );
|
||||
}
|
||||
|
BIN
tests/ref/rgb.png
Normal file
BIN
tests/ref/rgb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
24
tests/typ/rgb.typ
Normal file
24
tests/typ/rgb.typ
Normal file
@ -0,0 +1,24 @@
|
||||
// Test the `rgb` function.
|
||||
|
||||
// Check the output.
|
||||
[rgb: 0.0, 0.3, 0.7] [val: #004db3]
|
||||
|
||||
// Alpha channel.
|
||||
[rgb: 1.0, 0.0, 0.0, 0.5]
|
||||
|
||||
// Value smaller than 0.0 and larger than 1.0
|
||||
[rgb: -30, 15.5, 0.5]
|
||||
|
||||
// Missing blue component.
|
||||
[rgb: 0, 1]
|
||||
|
||||
// Missing all components.
|
||||
[rgb]
|
||||
|
||||
// error: 4:23-4:26 unknown function
|
||||
// error: 10:7-10:10 should be between 0.0 and 1.0
|
||||
// error: 10:12-10:16 should be between 0.0 and 1.0
|
||||
// error: 13:7-13:11 missing argument: blue component
|
||||
// error: 16:5-16:5 missing argument: red component
|
||||
// error: 16:5-16:5 missing argument: green component
|
||||
// error: 16:5-16:5 missing argument: blue component
|
@ -290,15 +290,16 @@ fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) {
|
||||
let mut builder = WrappedPathBuilder(PathBuilder::new());
|
||||
face.outline_glyph(glyph, &mut builder);
|
||||
|
||||
let path = builder.0.finish().unwrap();
|
||||
let placed = path
|
||||
.transform(&Transform::from_row(scale, 0.0, 0.0, -scale, x, y).unwrap())
|
||||
.unwrap();
|
||||
if let Some(path) = builder.0.finish() {
|
||||
let placed = path
|
||||
.transform(&Transform::from_row(scale, 0.0, 0.0, -scale, x, y).unwrap())
|
||||
.unwrap();
|
||||
|
||||
let mut paint = Paint::default();
|
||||
paint.anti_alias = true;
|
||||
let mut paint = Paint::default();
|
||||
paint.anti_alias = true;
|
||||
|
||||
canvas.fill_path(&placed, &paint, FillRule::default());
|
||||
canvas.fill_path(&placed, &paint, FillRule::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user