summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval/value.rs2
-rw-r--r--src/export/pdf.rs115
-rw-r--r--src/font.rs14
-rw-r--r--src/frame.rs59
-rw-r--r--src/geom/paint.rs17
-rw-r--r--src/geom/path.rs25
-rw-r--r--src/library/deco.rs27
-rw-r--r--src/library/page.rs8
-rw-r--r--src/library/shape.rs76
-rw-r--r--src/library/text.rs32
-rw-r--r--src/library/utility.rs4
-rw-r--r--src/style/mod.rs2
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(),