summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-11-22 15:26:56 +0100
committerLaurenz <laurmaedje@gmail.com>2021-11-22 15:26:56 +0100
commit0a974d86ba921af781a6c9d75961b92351a5f28e (patch)
tree618b0dd4ea554a888c9b93c769eaebe33ac2a9ec /src
parented50661378f356e02c6ec943bc4840091d33cfbd (diff)
Welcome to Tigerland
Diffstat (limited to 'src')
-rw-r--r--src/export/pdf.rs34
-rw-r--r--src/frame.rs38
-rw-r--r--src/library/image.rs12
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)]