diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-22 15:26:56 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-22 15:26:56 +0100 |
| commit | 0a974d86ba921af781a6c9d75961b92351a5f28e (patch) | |
| tree | 618b0dd4ea554a888c9b93c769eaebe33ac2a9ec /src | |
| parent | ed50661378f356e02c6ec943bc4840091d33cfbd (diff) | |
Welcome to Tigerland
Diffstat (limited to 'src')
| -rw-r--r-- | src/export/pdf.rs | 34 | ||||
| -rw-r--r-- | src/frame.rs | 38 | ||||
| -rw-r--r-- | src/library/image.rs | 12 |
3 files changed, 49 insertions, 35 deletions
diff --git a/src/export/pdf.rs b/src/export/pdf.rs index b807d059..b12ee771 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, Shape, Stroke, Text}; +use crate::frame::{Element, Frame, Geometry, Group, Shape, Stroke, Text}; use crate::geom::{self, Color, Em, Length, Paint, Size}; use crate::image::{Image, ImageId, ImageStore}; use crate::Context; @@ -369,18 +369,6 @@ impl<'a> PageExporter<'a> { /// Write a frame into the content stream. fn write_frame(&mut self, x: f32, y: f32, frame: &Frame) { - if frame.clips { - let w = frame.size.w.to_f32(); - let h = frame.size.h.to_f32(); - self.content.save_state(); - self.content.move_to(x, y); - self.content.line_to(x + w, y); - self.content.line_to(x + w, y - h); - self.content.line_to(x, y - h); - self.content.clip_nonzero(); - self.content.end_path(); - } - for (offset, element) in &frame.elements { // Make sure the content stream is in the correct state. match element { @@ -401,10 +389,10 @@ impl<'a> PageExporter<'a> { let y = y - offset.y.to_f32(); match *element { + Element::Group(ref group) => self.write_group(x, y, group), 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(_, _) => {} } } @@ -412,8 +400,24 @@ impl<'a> PageExporter<'a> { if self.in_text_state { self.content.end_text(); } + } + + fn write_group(&mut self, x: f32, y: f32, group: &Group) { + if group.clips { + let w = group.frame.size.w.to_f32(); + let h = group.frame.size.h.to_f32(); + self.content.save_state(); + self.content.move_to(x, y); + self.content.line_to(x + w, y); + self.content.line_to(x + w, y - h); + self.content.line_to(x, y - h); + self.content.clip_nonzero(); + self.content.end_path(); + } + + self.write_frame(x, y, &group.frame); - if frame.clips { + if group.clips { self.content.restore_state(); } } diff --git a/src/frame.rs b/src/frame.rs index 9f1b1c28..7862e005 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -16,8 +16,6 @@ pub struct Frame { pub size: Size, /// The baseline of the frame measured from the top. pub baseline: Length, - /// Whether this frame should be a clipping boundary. - pub clips: bool, /// The elements composing this layout. pub elements: Vec<(Point, Element)>, } @@ -27,12 +25,7 @@ impl Frame { #[track_caller] pub fn new(size: Size, baseline: Length) -> Self { assert!(size.is_finite()); - Self { - size, - baseline, - elements: vec![], - clips: false, - } + Self { size, baseline, elements: vec![] } } /// Add an element at a position in the background. @@ -45,17 +38,16 @@ impl Frame { self.elements.push((pos, element)); } - /// Add a frame element. - pub fn push_frame(&mut self, pos: Point, subframe: Rc<Self>) { - self.elements.push((pos, Element::Frame(subframe))) + /// Add a group element. + pub fn push_frame(&mut self, pos: Point, frame: Rc<Self>) { + self.elements + .push((pos, Element::Group(Group { frame, clips: false }))) } /// Add all elements of another frame, placing them relative to the given /// position. pub fn merge_frame(&mut self, pos: Point, subframe: Self) { - if subframe.clips { - self.push_frame(pos, Rc::new(subframe)); - } else if pos == Point::zero() && self.elements.is_empty() { + if pos == Point::zero() && self.elements.is_empty() { self.elements = subframe.elements; } else { for (subpos, child) in subframe.elements { @@ -90,7 +82,6 @@ impl Debug for Frame { f.debug_struct("Frame") .field("size", &self.size) .field("baseline", &self.baseline) - .field("clips", &self.clips) .field("children", &Children(&self.elements)) .finish() } @@ -107,9 +98,9 @@ impl<'a> Iterator for Elements<'a> { fn next(&mut self) -> Option<Self::Item> { let (cursor, offset, frame) = self.stack.last_mut()?; if let Some((pos, e)) = frame.elements.get(*cursor) { - if let Element::Frame(f) = e { + if let Element::Group(g) = e { let new_offset = *offset + *pos; - self.stack.push((0, new_offset, f.as_ref())); + self.stack.push((0, new_offset, g.frame.as_ref())); self.next() } else { *cursor += 1; @@ -128,6 +119,8 @@ impl<'a> Iterator for Elements<'a> { /// The building block frames are composed of. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum Element { + /// A group of elements. + Group(Group), /// A run of shaped text. Text(Text), /// A geometric shape with optional fill and stroke. @@ -136,8 +129,15 @@ pub enum Element { Image(ImageId, Size), /// A link to an external resource and its trigger region. Link(String, Size), - /// A subframe, which can be a clipping boundary. - Frame(Rc<Frame>), +} + +/// A group of elements with optional clipping. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct Group { + /// The group's frame. + pub frame: Rc<Frame>, + /// Whether the frame should be a clipping boundary. + pub clips: bool, } /// A run of shaped text. diff --git a/src/library/image.rs b/src/library/image.rs index 8b85a53f..b0d66a63 100644 --- a/src/library/image.rs +++ b/src/library/image.rs @@ -75,12 +75,22 @@ impl Layout for ImageNode { // The position of the image so that it is centered in the canvas. let mut frame = Frame::new(canvas, canvas.h); - frame.clips = self.fit == ImageFit::Cover; frame.push( (canvas - size).to_point() / 2.0, Element::Image(self.id, size), ); + // Create a clipping group if the image mode is `cover`. + if self.fit == ImageFit::Cover { + let group = Group { + frame: Rc::new(frame), + clips: self.fit == ImageFit::Cover, + }; + + frame = Frame::new(canvas, canvas.h); + frame.push(Point::zero(), Element::Group(group)); + } + let mut cts = Constraints::new(regions.expand); cts.exact = regions.current.to_spec().map(Some); vec![frame.constrain(cts)] |
