diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs index ef7def7ad..bac0cb7ff 100644 --- a/library/src/layout/container.rs +++ b/library/src/layout/container.rs @@ -383,7 +383,13 @@ impl Layout for BlockElem { let outset = self.outset(styles); let radius = self.radius(styles); for frame in frames.iter_mut().skip(skip as usize) { - frame.fill_and_stroke(fill, stroke, outset, radius, self.span()); + frame.fill_and_stroke( + fill.clone(), + stroke.clone(), + outset, + radius, + self.span(), + ); } } diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs index 66d2bcc01..8ad85c79b 100644 --- a/library/src/layout/page.rs +++ b/library/src/layout/page.rs @@ -362,8 +362,8 @@ impl PageElem { } } - if let Some(fill) = fill { - frame.fill(fill); + if let Some(fill) = &fill { + frame.fill(fill.clone()); } } diff --git a/library/src/layout/table.rs b/library/src/layout/table.rs index 3b1f7247e..d4238839e 100644 --- a/library/src/layout/table.rs +++ b/library/src/layout/table.rs @@ -167,14 +167,14 @@ impl Layout for TableElem { // Add lines and backgrounds. for (frame, rows) in layout.fragment.iter_mut().zip(&layout.rows) { // Render table lines. - if let Some(stroke) = stroke { + if let Some(stroke) = &stroke { let thickness = stroke.thickness; let half = thickness / 2.0; // Render horizontal lines. for offset in points(rows.iter().map(|piece| piece.height)) { let target = Point::with_x(frame.width() + thickness); - let hline = Geometry::Line(target).stroked(stroke); + let hline = Geometry::Line(target).stroked(stroke.clone()); frame.prepend( Point::new(-half, offset), FrameItem::Shape(hline, self.span()), @@ -184,7 +184,7 @@ impl Layout for TableElem { // Render vertical lines. for offset in points(layout.cols.iter().copied()) { let target = Point::with_y(frame.height() + thickness); - let vline = Geometry::Line(target).stroked(stroke); + let vline = Geometry::Line(target).stroked(stroke.clone()); frame.prepend( Point::new(offset, -half), FrameItem::Shape(vline, self.span()), diff --git a/library/src/math/fragment.rs b/library/src/math/fragment.rs index 0d663d3fd..a09514589 100644 --- a/library/src/math/fragment.rs +++ b/library/src/math/fragment.rs @@ -201,20 +201,20 @@ impl GlyphFragment { self.ascent + self.descent } - pub fn to_variant(&self) -> VariantFragment { + pub fn to_variant(self) -> VariantFragment { VariantFragment { c: self.c, id: Some(self.id), - frame: self.to_frame(), style: self.style, font_size: self.font_size, italics_correction: self.italics_correction, class: self.class, span: self.span, + frame: self.to_frame(), } } - pub fn to_frame(&self) -> Frame { + pub fn to_frame(self) -> Frame { let item = TextItem { font: self.font.clone(), size: self.font_size, diff --git a/library/src/text/deco.rs b/library/src/text/deco.rs index 90a6ca857..79917641c 100644 --- a/library/src/text/deco.rs +++ b/library/src/text/deco.rs @@ -268,8 +268,8 @@ pub(super) fn decorate( }; let offset = deco.offset.unwrap_or(-metrics.position.at(text.size)) - shift; - let stroke = deco.stroke.unwrap_or(Stroke { - paint: text.fill, + let stroke = deco.stroke.clone().unwrap_or(Stroke { + paint: text.fill.clone(), thickness: metrics.thickness.at(text.size), }); @@ -284,7 +284,7 @@ pub(super) fn decorate( let target = Point::new(to - from, Abs::zero()); if target.x >= min_width || !deco.evade { - let shape = Geometry::Line(target).stroked(stroke); + let shape = Geometry::Line(target).stroked(stroke.clone()); frame.push(origin, FrameItem::Shape(shape, Span::detached())); } }; diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs index c2630aef3..3c9f86e5f 100644 --- a/library/src/text/raw.rs +++ b/library/src/text/raw.rs @@ -134,8 +134,7 @@ impl Show for RawElem { .settings .foreground .map(to_typst) - .map_or(Color::BLACK, Color::from) - .into(); + .map_or(Color::BLACK, Color::from); let mut realized = if matches!(lang.as_deref(), Some("typ" | "typst" | "typc")) { let root = match lang.as_deref() { @@ -150,7 +149,7 @@ impl Show for RawElem { vec![], &highlighter, &mut |node, style| { - seq.push(styled(&text[node.range()], foreground, style)); + seq.push(styled(&text[node.range()], foreground.into(), style)); }, ); @@ -168,7 +167,7 @@ impl Show for RawElem { for (style, piece) in highlighter.highlight_line(line, &SYNTAXES).into_iter().flatten() { - seq.push(styled(piece, foreground, style)); + seq.push(styled(piece, foreground.into(), style)); } } diff --git a/library/src/text/shaping.rs b/library/src/text/shaping.rs index 15fbcd3f2..4a62d5389 100644 --- a/library/src/text/shaping.rs +++ b/library/src/text/shaping.rs @@ -122,7 +122,14 @@ impl<'a> ShapedText<'a> { }) .collect(); - let item = TextItem { font, size: self.size, lang, fill, glyphs }; + let item = TextItem { + font, + size: self.size, + lang, + fill: fill.clone(), + glyphs, + }; + let layer = frame.layer(); let width = item.width(); diff --git a/src/export/pdf/page.rs b/src/export/pdf/page.rs index f3c81cb87..8f767e872 100644 --- a/src/export/pdf/page.rs +++ b/src/export/pdf/page.rs @@ -215,8 +215,8 @@ impl PageContext<'_, '_> { } } - fn set_fill(&mut self, fill: Paint) { - if self.state.fill != Some(fill) { + fn set_fill(&mut self, fill: &Paint) { + if self.state.fill.as_ref() != Some(fill) { let f = |c| c as f32 / 255.0; let Paint::Solid(color) = fill; match color { @@ -233,7 +233,7 @@ impl PageContext<'_, '_> { self.content.set_fill_cmyk(f(c.c), f(c.m), f(c.y), f(c.k)); } } - self.state.fill = Some(fill); + self.state.fill = Some(fill.clone()); } } @@ -248,8 +248,8 @@ impl PageContext<'_, '_> { self.state.fill_space = None; } - fn set_stroke(&mut self, stroke: Stroke) { - if self.state.stroke != Some(stroke) { + fn set_stroke(&mut self, stroke: &Stroke) { + if self.state.stroke.as_ref() != Some(stroke) { let f = |c| c as f32 / 255.0; let Paint::Solid(color) = stroke.paint; match color { @@ -268,7 +268,7 @@ impl PageContext<'_, '_> { } self.content.set_line_width(stroke.thickness.to_f32()); - self.state.stroke = Some(stroke); + self.state.stroke = Some(stroke.clone()); } } @@ -335,7 +335,7 @@ fn write_text(ctx: &mut PageContext, x: f32, y: f32, text: &TextItem) { .or_default() .extend(text.glyphs.iter().map(|g| g.id)); - ctx.set_fill(text.fill); + ctx.set_fill(&text.fill); ctx.set_font(&text.font, text.size); ctx.content.begin_text(); @@ -386,11 +386,11 @@ fn write_shape(ctx: &mut PageContext, x: f32, y: f32, shape: &Shape) { return; } - if let Some(fill) = shape.fill { + if let Some(fill) = &shape.fill { ctx.set_fill(fill); } - if let Some(stroke) = shape.stroke { + if let Some(stroke) = &shape.stroke { ctx.set_stroke(stroke); } @@ -413,7 +413,7 @@ fn write_shape(ctx: &mut PageContext, x: f32, y: f32, shape: &Shape) { } } - match (shape.fill, shape.stroke) { + match (&shape.fill, &shape.stroke) { (None, None) => unreachable!(), (Some(_), None) => ctx.content.fill_nonzero(), (None, Some(_)) => ctx.content.stroke(), diff --git a/src/export/render.rs b/src/export/render.rs index 11ab5447f..dc87f4471 100644 --- a/src/export/render.rs +++ b/src/export/render.rs @@ -223,7 +223,7 @@ fn render_outline_glyph( builder.0.finish()? }; - let paint = text.fill.into(); + let paint = (&text.fill).into(); let rule = sk::FillRule::default(); // Flip vertically because font design coordinate @@ -302,7 +302,7 @@ fn render_shape( Geometry::Path(ref path) => convert_path(path)?, }; - if let Some(fill) = shape.fill { + if let Some(fill) = &shape.fill { let mut paint: sk::Paint = fill.into(); if matches!(shape.geometry, Geometry::Rect(_)) { paint.anti_alias = false; @@ -312,7 +312,7 @@ fn render_shape( canvas.fill_path(&path, &paint, rule, ts, mask); } - if let Some(Stroke { paint, thickness }) = shape.stroke { + if let Some(Stroke { paint, thickness }) = &shape.stroke { let paint = paint.into(); let stroke = sk::Stroke { width: thickness.to_f32(), ..Default::default() }; canvas.stroke_path(&path, &paint, &stroke, ts, mask); @@ -428,10 +428,10 @@ impl From for sk::Transform { } } -impl From for sk::Paint<'static> { - fn from(paint: Paint) -> Self { +impl From<&Paint> for sk::Paint<'static> { + fn from(paint: &Paint) -> Self { let mut sk_paint = sk::Paint::default(); - let Paint::Solid(color) = paint; + let Paint::Solid(color) = *paint; sk_paint.set_color(color.into()); sk_paint.anti_alias = true; sk_paint diff --git a/src/geom/axes.rs b/src/geom/axes.rs index 92bd03886..8bc2456ab 100644 --- a/src/geom/axes.rs +++ b/src/geom/axes.rs @@ -120,10 +120,10 @@ impl Axes { impl Get for Axes { type Component = T; - fn get(self, axis: Axis) -> T { + fn get_ref(&self, axis: Axis) -> &T { match axis { - Axis::X => self.x, - Axis::Y => self.y, + Axis::X => &self.x, + Axis::Y => &self.y, } } diff --git a/src/geom/corners.rs b/src/geom/corners.rs index 844d3047a..26d4082b6 100644 --- a/src/geom/corners.rs +++ b/src/geom/corners.rs @@ -76,12 +76,12 @@ impl Corners { impl Get for Corners { type Component = T; - fn get(self, corner: Corner) -> T { + fn get_ref(&self, corner: Corner) -> &T { match corner { - Corner::TopLeft => self.top_left, - Corner::TopRight => self.top_right, - Corner::BottomRight => self.bottom_right, - Corner::BottomLeft => self.bottom_left, + Corner::TopLeft => &self.top_left, + Corner::TopRight => &self.top_right, + Corner::BottomRight => &self.bottom_right, + Corner::BottomLeft => &self.bottom_left, } } @@ -110,7 +110,7 @@ pub enum Corner { impl Cast for Corners> where - T: Cast + Copy, + T: Cast + Clone, { fn is(value: &Value) -> bool { matches!(value, Value::Dict(_)) || T::is(value) @@ -121,15 +121,23 @@ where let mut take = |key| dict.take(key).ok().map(T::cast).transpose(); let rest = take("rest")?; - let left = take("left")?.or(rest); - let top = take("top")?.or(rest); - let right = take("right")?.or(rest); - let bottom = take("bottom")?.or(rest); + let left = take("left")?.or_else(|| rest.clone()); + let top = take("top")?.or_else(|| rest.clone()); + let right = take("right")?.or_else(|| rest.clone()); + let bottom = take("bottom")?.or_else(|| rest.clone()); let corners = Corners { - top_left: take("top-left")?.or(top).or(left), - top_right: take("top-right")?.or(top).or(right), - bottom_right: take("bottom-right")?.or(bottom).or(right), - bottom_left: take("bottom-left")?.or(bottom).or(left), + top_left: take("top-left")? + .or_else(|| top.clone()) + .or_else(|| left.clone()), + top_right: take("top-right")? + .or_else(|| top.clone()) + .or_else(|| right.clone()), + bottom_right: take("bottom-right")? + .or_else(|| bottom.clone()) + .or_else(|| right.clone()), + bottom_left: take("bottom-left")? + .or_else(|| bottom.clone()) + .or_else(|| left.clone()), }; dict.finish(&[ diff --git a/src/geom/mod.rs b/src/geom/mod.rs index b7daaa1be..8896c24c9 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -66,12 +66,21 @@ pub trait Get { /// The structure's component type. type Component; - /// Return the component for the specified index. - fn get(self, index: Index) -> Self::Component; + /// Borrow the component for the specified index. + fn get_ref(&self, index: Index) -> &Self::Component; /// Borrow the component for the specified index mutably. fn get_mut(&mut self, index: Index) -> &mut Self::Component; + /// Convenience method for getting a copy of a component. + fn get(self, index: Index) -> Self::Component + where + Self: Sized, + Self::Component: Copy, + { + *self.get_ref(index) + } + /// Convenience method for setting a component. fn set(&mut self, index: Index, component: Self::Component) { *self.get_mut(index) = component; diff --git a/src/geom/paint.rs b/src/geom/paint.rs index eacd6f95a..e9bd3a2e1 100644 --- a/src/geom/paint.rs +++ b/src/geom/paint.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use super::*; /// How a fill or stroke should be painted. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Clone, Eq, PartialEq, Hash)] pub enum Paint { /// A solid color. Solid(Color), diff --git a/src/geom/point.rs b/src/geom/point.rs index ce3a6ff2f..b31ea2965 100644 --- a/src/geom/point.rs +++ b/src/geom/point.rs @@ -72,10 +72,10 @@ impl Numeric for Point { impl Get for Point { type Component = Abs; - fn get(self, axis: Axis) -> Abs { + fn get_ref(&self, axis: Axis) -> &Abs { match axis { - Axis::X => self.x, - Axis::Y => self.y, + Axis::X => &self.x, + Axis::Y => &self.y, } } diff --git a/src/geom/rounded.rs b/src/geom/rounded.rs index dbe21ac6f..f445dfcb8 100644 --- a/src/geom/rounded.rs +++ b/src/geom/rounded.rs @@ -14,7 +14,7 @@ pub fn rounded_rect( res.push(Shape { geometry: fill_geometry(size, radius), fill, - stroke: if stroke.is_uniform() { stroke.top } else { None }, + stroke: if stroke.is_uniform() { stroke.top.clone() } else { None }, }); } @@ -55,7 +55,7 @@ fn stroke_segments( let max_radius = size.x.min(size.y) / 2.0; for side in [Side::Top, Side::Right, Side::Bottom, Side::Left] { - let continuous = stroke.get(side) == stroke.get(side.next_cw()); + let continuous = stroke.get_ref(side) == stroke.get_ref(side.next_cw()); connection = connection.advance(continuous && side != Side::Left); always_continuous &= continuous; @@ -69,7 +69,7 @@ fn stroke_segments( ); if !continuous { - res.push((mem::take(&mut path), stroke.get(side))); + res.push((mem::take(&mut path), stroke.get_ref(side).clone())); } } diff --git a/src/geom/sides.rs b/src/geom/sides.rs index 247d9a987..25b1fab50 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -91,12 +91,12 @@ impl Sides> { impl Get for Sides { type Component = T; - fn get(self, side: Side) -> T { + fn get_ref(&self, side: Side) -> &T { match side { - Side::Left => self.left, - Side::Top => self.top, - Side::Right => self.right, - Side::Bottom => self.bottom, + Side::Left => &self.left, + Side::Top => &self.top, + Side::Right => &self.right, + Side::Bottom => &self.bottom, } } @@ -180,7 +180,7 @@ impl Side { impl Cast for Sides> where - T: Default + Cast + Copy, + T: Default + Cast + Clone, { fn is(value: &Value) -> bool { matches!(value, Value::Dict(_)) || T::is(value) @@ -191,13 +191,13 @@ where let mut take = |key| dict.take(key).ok().map(T::cast).transpose(); let rest = take("rest")?; - let x = take("x")?.or(rest); - let y = take("y")?.or(rest); + let x = take("x")?.or_else(|| rest.clone()); + let y = take("y")?.or_else(|| rest.clone()); let sides = Sides { - left: take("left")?.or(x), - top: take("top")?.or(y), - right: take("right")?.or(x), - bottom: take("bottom")?.or(y), + left: take("left")?.or_else(|| x.clone()), + top: take("top")?.or_else(|| y.clone()), + right: take("right")?.or_else(|| x.clone()), + bottom: take("bottom")?.or_else(|| y.clone()), }; dict.finish(&["left", "top", "right", "bottom", "x", "y", "rest"])?; diff --git a/src/geom/stroke.rs b/src/geom/stroke.rs index 500a4c107..4dba06d9c 100644 --- a/src/geom/stroke.rs +++ b/src/geom/stroke.rs @@ -1,7 +1,7 @@ use super::*; /// A stroke of a geometric shape. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct Stroke { /// The stroke's paint. pub paint: Paint, @@ -23,7 +23,7 @@ impl Default for Stroke { /// In this representation, both fields are optional so that you can pass either /// just a paint (`red`), just a thickness (`0.1em`) or both (`2pt + red`) where /// this is expected. -#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Default, Clone, Eq, PartialEq, Hash)] pub struct PartialStroke { /// The stroke's paint. pub paint: Smart, @@ -48,7 +48,7 @@ impl PartialStroke { impl Debug for PartialStroke { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match (self.paint, &self.thickness) { + match (&self.paint, &self.thickness) { (Smart::Custom(paint), Smart::Custom(thickness)) => { write!(f, "{thickness:?} + {paint:?}") }