diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-20 15:51:07 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-20 15:51:07 +0100 |
| commit | cef46e6c40fed0089a20e44ff2f251c06878891c (patch) | |
| tree | a4f12ced1441a014f0446f5b01e3f0f87bdd21b5 /src | |
| parent | 70c0dd767452772d29167e39b1c4f919519422ce (diff) | |
Strokes
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/value.rs | 2 | ||||
| -rw-r--r-- | src/export/pdf.rs | 115 | ||||
| -rw-r--r-- | src/font.rs | 14 | ||||
| -rw-r--r-- | src/frame.rs | 59 | ||||
| -rw-r--r-- | src/geom/paint.rs | 17 | ||||
| -rw-r--r-- | src/geom/path.rs | 25 | ||||
| -rw-r--r-- | src/library/deco.rs | 27 | ||||
| -rw-r--r-- | src/library/page.rs | 8 | ||||
| -rw-r--r-- | src/library/shape.rs | 76 | ||||
| -rw-r--r-- | src/library/text.rs | 32 | ||||
| -rw-r--r-- | src/library/utility.rs | 4 | ||||
| -rw-r--r-- | src/style/mod.rs | 2 |
12 files changed, 222 insertions, 159 deletions
diff --git a/src/eval/value.rs b/src/eval/value.rs index 0fcc4bfc..e224438a 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -147,7 +147,7 @@ impl From<usize> for Value { impl From<RgbaColor> for Value { fn from(v: RgbaColor) -> Self { - Self::Color(Color::Rgba(v)) + Self::Color(v.into()) } } diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 05f73e52..b807d059 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -14,7 +14,7 @@ use ttf_parser::{name_id, GlyphId, Tag}; use super::subset; use crate::font::{find_name, FaceId, FontStore}; -use crate::frame::{Element, Frame, Geometry, Text}; +use crate::frame::{Element, Frame, Geometry, Shape, Stroke, Text}; use crate::geom::{self, Color, Em, Length, Paint, Size}; use crate::image::{Image, ImageId, ImageStore}; use crate::Context; @@ -389,7 +389,7 @@ impl<'a> PageExporter<'a> { self.in_text_state = true; } - Element::Geometry(..) | Element::Image(..) if self.in_text_state => { + Element::Shape(_) | Element::Image(..) if self.in_text_state => { self.content.end_text(); self.in_text_state = false; } @@ -401,19 +401,11 @@ impl<'a> PageExporter<'a> { let y = y - offset.y.to_f32(); match *element { - Element::Text(ref text) => { - self.write_text(x, y, text); - } - Element::Geometry(ref geometry, paint) => { - self.write_geometry(x, y, geometry, paint); - } - Element::Image(id, size) => { - self.write_image(x, y, id, size); - } + Element::Text(ref text) => self.write_text(x, y, text), + Element::Shape(ref shape) => self.write_shape(x, y, shape), + Element::Image(id, size) => self.write_image(x, y, id, size), + Element::Frame(ref frame) => self.write_frame(x, y, frame), Element::Link(_, _) => {} - Element::Frame(ref frame) => { - self.write_frame(x, y, frame); - } } } @@ -482,79 +474,92 @@ impl<'a> PageExporter<'a> { } } - /// Write an image into the content stream. - fn write_image(&mut self, x: f32, y: f32, id: ImageId, size: Size) { - let name = format!("Im{}", self.image_map.map(id)); - let w = size.w.to_f32(); - let h = size.h.to_f32(); - - self.content.save_state(); - self.content.concat_matrix([w, 0.0, 0.0, h, x, y - h]); - self.content.x_object(Name(name.as_bytes())); - self.content.restore_state(); - } - /// Write a geometrical shape into the content stream. - fn write_geometry(&mut self, x: f32, y: f32, geometry: &Geometry, paint: Paint) { - self.content.save_state(); + fn write_shape(&mut self, x: f32, y: f32, shape: &Shape) { + if shape.fill.is_none() && shape.stroke.is_none() { + return; + } - match *geometry { - Geometry::Rect(Size { w, h }) => { - let w = w.to_f32(); - let h = h.to_f32(); + match shape.geometry { + Geometry::Rect(size) => { + let w = size.w.to_f32(); + let h = size.h.to_f32(); if w > 0.0 && h > 0.0 { - self.write_fill(paint); self.content.rect(x, y - h, w, h); - self.content.fill_nonzero(); } } Geometry::Ellipse(size) => { - let path = geom::Path::ellipse(size); - self.write_fill(paint); - self.write_filled_path(x, y, &path); + let approx = geom::Path::ellipse(size); + self.write_path(x, y, &approx); } - Geometry::Line(target, thickness) => { - self.write_stroke(paint, thickness.to_f32()); + Geometry::Line(target) => { + let dx = target.x.to_f32(); + let dy = target.y.to_f32(); self.content.move_to(x, y); - self.content.line_to(x + target.x.to_f32(), y - target.y.to_f32()); - self.content.stroke(); + self.content.line_to(x + dx, y - dy); } Geometry::Path(ref path) => { - self.write_fill(paint); - self.write_filled_path(x, y, path) + self.write_path(x, y, path); } } + self.content.save_state(); + + if let Some(fill) = shape.fill { + self.write_fill(fill); + } + + if let Some(stroke) = shape.stroke { + self.write_stroke(stroke); + } + + match (shape.fill, shape.stroke) { + (None, None) => unreachable!(), + (Some(_), None) => self.content.fill_nonzero(), + (None, Some(_)) => self.content.stroke(), + (Some(_), Some(_)) => self.content.fill_nonzero_and_stroke(), + }; + + self.content.restore_state(); + } + + /// Write an image into the content stream. + fn write_image(&mut self, x: f32, y: f32, id: ImageId, size: Size) { + let name = format!("Im{}", self.image_map.map(id)); + let w = size.w.to_f32(); + let h = size.h.to_f32(); + self.content.save_state(); + self.content.concat_matrix([w, 0.0, 0.0, h, x, y - h]); + self.content.x_object(Name(name.as_bytes())); self.content.restore_state(); } - /// Write and fill path into a content stream. - fn write_filled_path(&mut self, x: f32, y: f32, path: &geom::Path) { + /// Write a path into a content stream. + fn write_path(&mut self, x: f32, y: f32, path: &geom::Path) { for elem in &path.0 { match elem { geom::PathElement::MoveTo(p) => { - self.content.move_to(x + p.x.to_f32(), y + p.y.to_f32()) + self.content.move_to(x + p.x.to_f32(), y - p.y.to_f32()) } geom::PathElement::LineTo(p) => { - self.content.line_to(x + p.x.to_f32(), y + p.y.to_f32()) + self.content.line_to(x + p.x.to_f32(), y - p.y.to_f32()) } geom::PathElement::CubicTo(p1, p2, p3) => self.content.cubic_to( x + p1.x.to_f32(), - y + p1.y.to_f32(), + y - p1.y.to_f32(), x + p2.x.to_f32(), - y + p2.y.to_f32(), + y - p2.y.to_f32(), x + p3.x.to_f32(), - y + p3.y.to_f32(), + y - p3.y.to_f32(), ), geom::PathElement::ClosePath => self.content.close_path(), }; } - self.content.fill_nonzero(); } /// Write a fill change into a content stream. fn write_fill(&mut self, fill: Paint) { - let Paint::Color(Color::Rgba(c)) = fill; + let Paint::Solid(Color::Rgba(c)) = fill; self.content.set_fill_rgb( c.r as f32 / 255.0, c.g as f32 / 255.0, @@ -563,14 +568,14 @@ impl<'a> PageExporter<'a> { } /// Write a stroke change into a content stream. - fn write_stroke(&mut self, stroke: Paint, thickness: f32) { - let Paint::Color(Color::Rgba(c)) = stroke; + fn write_stroke(&mut self, stroke: Stroke) { + let Paint::Solid(Color::Rgba(c)) = stroke.paint; self.content.set_stroke_rgb( c.r as f32 / 255.0, c.g as f32 / 255.0, c.b as f32 / 255.0, ); - self.content.set_line_width(thickness); + self.content.set_line_width(stroke.thickness.to_f32()); } } diff --git a/src/font.rs b/src/font.rs index fb93d5c9..5afd1aca 100644 --- a/src/font.rs +++ b/src/font.rs @@ -187,11 +187,11 @@ pub struct Face { /// Metrics for a decorative line. #[derive(Debug, Copy, Clone)] pub struct LineMetrics { - /// The thickness of the line. - pub strength: Em, /// The vertical offset of the line from the baseline. Positive goes /// upwards, negative downwards. pub position: Em, + /// The thickness of the line. + pub thickness: Em, } impl Face { @@ -218,22 +218,22 @@ impl Face { let underline = ttf.underline_metrics(); let strikethrough = LineMetrics { - strength: strikeout + position: strikeout.map_or(Em::new(0.25), |s| to_em(s.position)), + thickness: strikeout .or(underline) .map_or(Em::new(0.06), |s| to_em(s.thickness)), - position: strikeout.map_or(Em::new(0.25), |s| to_em(s.position)), }; let underline = LineMetrics { - strength: underline + position: underline.map_or(Em::new(-0.2), |s| to_em(s.position)), + thickness: underline .or(strikeout) .map_or(Em::new(0.06), |s| to_em(s.thickness)), - position: underline.map_or(Em::new(-0.2), |s| to_em(s.position)), }; let overline = LineMetrics { - strength: underline.strength, position: cap_height + Em::new(0.1), + thickness: underline.thickness, }; Some(Self { diff --git a/src/frame.rs b/src/frame.rs index 9feb6959..9f1b1c28 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -128,14 +128,13 @@ impl<'a> Iterator for Elements<'a> { /// The building block frames are composed of. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Element { - /// Shaped text. + /// A run of shaped text. Text(Text), - /// A geometric shape and the paint which with it should be filled or - /// stroked (which one depends on the kind of geometry). - Geometry(Geometry, Paint), - /// A raster image. + /// A geometric shape with optional fill and stroke. + Shape(Shape), + /// A raster image and its size. Image(ImageId, Size), - /// A link to an external resource. + /// A link to an external resource and its trigger region. Link(String, Size), /// A subframe, which can be a clipping boundary. Frame(Rc<Frame>), @@ -167,15 +166,51 @@ pub struct Glyph { pub x_offset: Em, } -/// A geometric shape. +/// A geometric shape with optional fill and stroke. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct Shape { + /// The shape's geometry. + pub geometry: Geometry, + /// The shape's background fill. + pub fill: Option<Paint>, + /// The shape's border stroke. + pub stroke: Option<Stroke>, +} + +impl Shape { + /// Create a filled shape without a stroke. + pub fn filled(geometry: Geometry, fill: Paint) -> Self { + Self { geometry, fill: Some(fill), stroke: None } + } + + /// Create a stroked shape without a fill. + pub fn stroked(geometry: Geometry, stroke: Stroke) -> Self { + Self { + geometry, + fill: None, + stroke: Some(stroke), + } + } +} + +/// A shape's geometry. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Geometry { - /// A filled rectangle with its origin in the topleft corner. + /// A line to a point (relative to its position). + Line(Point), + /// A rectangle with its origin in the topleft corner. Rect(Size), - /// A filled ellipse with its origin in the center. + /// A ellipse with its origin in the topleft corner. Ellipse(Size), - /// A stroked line to a point (relative to its position) with a thickness. - Line(Point, Length), - /// A filled bezier path. + /// A bezier path. Path(Path), } + +/// A stroke of a geometric shape. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Stroke { + /// The stroke's paint. + pub paint: Paint, + /// The stroke's thickness. + pub thickness: Length, +} diff --git a/src/geom/paint.rs b/src/geom/paint.rs index 74d7d147..66bfb17c 100644 --- a/src/geom/paint.rs +++ b/src/geom/paint.rs @@ -7,7 +7,16 @@ use super::*; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum Paint { /// A solid color. - Color(Color), + Solid(Color), +} + +impl<T> From<T> for Paint +where + T: Into<Color>, +{ + fn from(t: T) -> Self { + Self::Solid(t.into()) + } } /// A color in a dynamic format. @@ -25,6 +34,12 @@ impl Debug for Color { } } +impl From<RgbaColor> for Color { + fn from(rgba: RgbaColor) -> Self { + Self::Rgba(rgba) + } +} + /// An 8-bit RGBA color. #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct RgbaColor { diff --git a/src/geom/path.rs b/src/geom/path.rs index bc0d3f2d..39e75312 100644 --- a/src/geom/path.rs +++ b/src/geom/path.rs @@ -20,22 +20,35 @@ impl Path { Self(vec![]) } + /// Create a path that describes a rectangle. + pub fn rect(size: Size) -> Self { + let z = Length::zero(); + let point = Point::new; + let mut path = Self::new(); + path.move_to(point(z, z)); + path.line_to(point(size.w, z)); + path.line_to(point(size.w, size.h)); + path.line_to(point(z, size.h)); + path.close_path(); + path + } + /// Create a path that approximates an axis-aligned ellipse. pub fn ellipse(size: Size) -> Self { // https://stackoverflow.com/a/2007782 + let z = Length::zero(); let rx = size.w / 2.0; let ry = size.h / 2.0; let m = 0.551784; let mx = m * rx; let my = m * ry; - let z = Length::zero(); - let point = Point::new; + let point = |x, y| Point::new(x + rx, y + ry); let mut path = Self::new(); path.move_to(point(-rx, z)); - path.cubic_to(point(-rx, my), point(-mx, ry), point(z, ry)); - path.cubic_to(point(mx, ry), point(rx, my), point(rx, z)); - path.cubic_to(point(rx, -my), point(mx, -ry), point(z, -ry)); - path.cubic_to(point(-mx, -ry), point(-rx, -my), point(z - rx, z)); + path.cubic_to(point(-rx, -my), point(-mx, -ry), point(z, -ry)); + path.cubic_to(point(mx, -ry), point(rx, -my), point(rx, z)); + path.cubic_to(point(rx, my), point(mx, ry), point(z, ry)); + path.cubic_to(point(-mx, ry), point(-rx, my), point(-rx, z)); path } diff --git a/src/library/deco.rs b/src/library/deco.rs index 2722fd68..1f8c051f 100644 --- a/src/library/deco.rs +++ b/src/library/deco.rs @@ -17,20 +17,13 @@ pub fn overline(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } fn line_impl(args: &mut Args, kind: LineKind) -> TypResult<Value> { - let stroke = args.named("stroke")?.or_else(|| args.find()); + let stroke = args.named("stroke")?.or_else(|| args.find()).map(Paint::Solid); let thickness = args.named::<Linear>("thickness")?.or_else(|| args.find()); let offset = args.named("offset")?; let extent = args.named("extent")?.unwrap_or_default(); let body: Template = args.expect("body")?; - Ok(Value::Template(body.decorate(Decoration::Line( - LineDecoration { - kind, - stroke: stroke.map(Paint::Color), - thickness, - offset, - extent, - }, + LineDecoration { kind, stroke, thickness, offset, extent }, )))) } @@ -112,12 +105,15 @@ impl LineDecoration { LineKind::Overline => face.overline, }; - let stroke = self.stroke.unwrap_or(text.fill); - let thickness = self .thickness .map(|s| s.resolve(text.size)) - .unwrap_or(metrics.strength.to_length(text.size)); + .unwrap_or(metrics.thickness.to_length(text.size)); + + let stroke = Stroke { + paint: self.stroke.unwrap_or(text.fill), + thickness, + }; let offset = self .offset @@ -127,10 +123,9 @@ impl LineDecoration { let extent = self.extent.resolve(text.size); let subpos = Point::new(pos.x - extent, pos.y + offset); - let vector = Point::new(text.width + 2.0 * extent, Length::zero()); - let line = Geometry::Line(vector, thickness); - - frame.push(subpos, Element::Geometry(line, stroke)); + let target = Point::new(text.width + 2.0 * extent, Length::zero()); + let shape = Shape::stroked(Geometry::Line(target), stroke); + frame.push(subpos, Element::Shape(shape)); } } } diff --git a/src/library/page.rs b/src/library/page.rs index b760e76a..20871bd9 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -18,7 +18,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let right = args.named("right")?; let bottom = args.named("bottom")?; let flip = args.named("flip")?; - let fill = args.named("fill")?; + let fill = args.named("fill")?.map(Paint::Solid); ctx.template.modify(move |style| { let page = style.page_mut(); @@ -63,7 +63,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { } if let Some(fill) = fill { - page.fill = Some(Paint::Color(fill)); + page.fill = Some(fill); } }); @@ -105,8 +105,8 @@ impl PageNode { // Add background fill if requested. if let Some(fill) = self.fill { for frame in &mut frames { - let element = Element::Geometry(Geometry::Rect(frame.size), fill); - Rc::make_mut(frame).prepend(Point::zero(), element); + let shape = Shape::filled(Geometry::Rect(frame.size), fill); + Rc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape)); } } diff --git a/src/library/shape.rs b/src/library/shape.rs index d0df5f48..abf927e4 100644 --- a/src/library/shape.rs +++ b/src/library/shape.rs @@ -7,9 +7,7 @@ use crate::util::RcExt; pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let width = args.named("width")?; let height = args.named("height")?; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Rect, width, height, fill, body)) + shape_impl(args, ShapeKind::Rect, width, height) } /// `square`: A square with optional content. @@ -23,18 +21,14 @@ pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { None => args.named("height")?, size => size, }; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Square, width, height, fill, body)) + shape_impl(args, ShapeKind::Square, width, height) } /// `ellipse`: An ellipse with optional content. pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let width = args.named("width")?; let height = args.named("height")?; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Ellipse, width, height, fill, body)) + shape_impl(args, ShapeKind::Ellipse, width, height) } /// `circle`: A circle with optional content. @@ -48,30 +42,44 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { None => args.named("height")?, diameter => diameter, }; - let fill = args.named("fill")?; - let body = args.find(); - Ok(shape_impl(ShapeKind::Circle, width, height, fill, body)) + shape_impl(args, ShapeKind::Circle, width, height) } fn shape_impl( + args: &mut Args, kind: ShapeKind, width: Option<Linear>, height: Option<Linear>, - fill: Option<Color>, - body: Option<Template>, -) -> Value { - // Set default fill if there's no fill. - let fill = fill.unwrap_or(Color::Rgba(RgbaColor::gray(175))); +) -> TypResult<Value> { + // The default appearance of a shape. + let default = Stroke { + paint: RgbaColor::BLACK.into(), + thickness: Length::pt(1.0), + }; + + // Parse fill & stroke. + let fill = args.named("fill")?.map(Paint::Solid); + let stroke = match (args.named("stroke")?, args.named("thickness")?) { + (None, None) => fill.is_none().then(|| default), + (color, thickness) => Some(Stroke { + paint: color.map(Paint::Solid).unwrap_or(default.paint), + thickness: thickness.unwrap_or(default.thickness), + }), + }; - Value::Template(Template::from_inline(move |style| { + let padding = Sides::splat(args.named("padding")?.unwrap_or_default()); + let body = args.find::<Template>(); + + Ok(Value::Template(Template::from_inline(move |style| { ShapeNode { kind, - fill: Some(Paint::Color(fill)), - child: body.as_ref().map(|body| body.pack(style)), + fill, + stroke, + child: body.as_ref().map(|body| body.pack(style).padded(padding)), } .pack() .sized(width, height) - })) + }))) } /// Places its child into a sizable and fillable shape. @@ -79,8 +87,10 @@ fn shape_impl( pub struct ShapeNode { /// Which shape to place the child into. pub kind: ShapeKind, - /// How to fill the shape, if at all. + /// How to fill the shape. pub fill: Option<Paint>, + /// How the stroke the shape. + pub stroke: Option<Stroke>, /// The child node to place into the shape, if any. pub child: Option<PackedNode>, } @@ -160,18 +170,20 @@ impl Layout for ShapeNode { Frame::new(size, size.h) }; - // Add background fill if desired. - if let Some(fill) = self.fill { - let (pos, geometry) = match self.kind { - ShapeKind::Square | ShapeKind::Rect => { - (Point::zero(), Geometry::Rect(frame.size)) - } - ShapeKind::Circle | ShapeKind::Ellipse => { - (frame.size.to_point() / 2.0, Geometry::Ellipse(frame.size)) - } + // Add fill and/or stroke. + if self.fill.is_some() || self.stroke.is_some() { + let geometry = match self.kind { + ShapeKind::Square | ShapeKind::Rect => Geometry::Rect(frame.size), + ShapeKind::Circle | ShapeKind::Ellipse => Geometry::Ellipse(frame.size), + }; + + let shape = Shape { + geometry, + fill: self.fill, + stroke: self.stroke, }; - frame.prepend(pos, Element::Geometry(geometry, fill)); + frame.prepend(Point::zero(), Element::Shape(shape)); } // Ensure frame size matches regions size if expansion is on. diff --git a/src/library/text.rs b/src/library/text.rs index cdcc7509..d0b5c8e6 100644 --- a/src/library/text.rs +++ b/src/library/text.rs @@ -163,12 +163,12 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let fallback = args.named("fallback")?; let style = args.named("style")?; let weight = args.named("weight")?; - let tracking = args.named("tracking")?; let stretch = args.named("stretch")?; let size = args.named::<Linear>("size")?.or_else(|| args.find()); + let tracking = args.named("tracking")?.map(Em::new); let top_edge = args.named("top-edge")?; let bottom_edge = args.named("bottom-edge")?; - let fill = args.named("fill")?.or_else(|| args.find()); + let fill = args.named("fill")?.or_else(|| args.find()).map(Paint::Solid); let kerning = args.named("kerning")?; let smallcaps = args.named("smallcaps")?; let alternates = args.named("alternates")?; @@ -182,7 +182,6 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let slashed_zero = args.named("slashed-zero")?; let fractions = args.named("fractions")?; let features = args.named("features")?; - let body = args.find::<Template>(); macro_rules! set { @@ -195,30 +194,19 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> { let f = move |style_: &mut Style| { let text = style_.text_mut(); - - if let Some(size) = size { - text.size = size.resolve(text.size); - } - - if let Some(fill) = fill { - text.fill = Paint::Color(fill); - } - - if let Some(tracking) = tracking { - text.tracking = Em::new(tracking); - } - + set!(text.families_mut().list => list.clone()); + set!(text.families_mut().serif => serif.clone()); + set!(text.families_mut().sans_serif => sans_serif.clone()); + set!(text.families_mut().monospace => monospace.clone()); + set!(text.fallback => fallback); set!(text.variant.style => style); set!(text.variant.weight => weight); set!(text.variant.stretch => stretch); + set!(text.size => size.map(|v| v.resolve(text.size))); + set!(text.tracking => tracking); set!(text.top_edge => top_edge); set!(text.bottom_edge => bottom_edge); - set!(text.fallback => fallback); - - set!(text.families_mut().list => list.clone()); - set!(text.families_mut().serif => serif.clone()); - set!(text.families_mut().sans_serif => sans_serif.clone()); - set!(text.families_mut().monospace => monospace.clone()); + set!(text.fill => fill); set!(text.features_mut().kerning => kerning); set!(text.features_mut().smallcaps => smallcaps); set!(text.features_mut().alternates => alternates); diff --git a/src/library/utility.rs b/src/library/utility.rs index 6d15a823..b2435e8a 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -86,7 +86,7 @@ pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { /// `rgb`: Create an RGB(A) color. pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { - Ok(Value::Color(Color::Rgba( + Ok(Value::from( if let Some(string) = args.find::<Spanned<EcoString>>() { match RgbaColor::from_str(&string.v) { Ok(color) => color, @@ -106,7 +106,7 @@ pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> { }; RgbaColor::new(f(r)?, f(g)?, f(b)?, f(a)?) }, - ))) + )) } /// `abs`: The absolute value of a numeric value. diff --git a/src/style/mod.rs b/src/style/mod.rs index 4588163b..4a8830f8 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -224,7 +224,7 @@ impl Default for TextStyle { }, top_edge: VerticalFontMetric::CapHeight, bottom_edge: VerticalFontMetric::Baseline, - fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)), + fill: RgbaColor::BLACK.into(), families: Rc::new(FamilyStyle::default()), features: Rc::new(FontFeatures::default()), tracking: Em::zero(), |
