Make all fields of Frame private

This commit is contained in:
Laurenz 2022-06-12 17:16:14 +02:00
parent ed6550fdb0
commit 6e3b1a2c80
19 changed files with 164 additions and 107 deletions

View File

@ -611,19 +611,24 @@ impl<'a, 'b> PageExporter<'a, 'b> {
}
fn export(mut self, frame: &Frame) -> Page {
let size = frame.size();
// Make the coordinate system start at the top-left.
self.bottom = frame.size.y.to_f32();
self.bottom = size.y.to_f32();
self.transform(Transform {
sx: Ratio::one(),
ky: Ratio::zero(),
kx: Ratio::zero(),
sy: Ratio::new(-1.0),
tx: Length::zero(),
ty: frame.size.y,
ty: size.y,
});
// Encode the page into the content stream.
self.write_frame(frame);
Page {
size: frame.size,
size,
content: self.content,
id: self.page_ref,
links: self.links,
@ -648,7 +653,7 @@ impl<'a, 'b> PageExporter<'a, 'b> {
}
}
for &(pos, ref element) in &frame.elements {
for &(pos, ref element) in frame.elements() {
let x = pos.x.to_f32();
let y = pos.y.to_f32();
match *element {
@ -669,8 +674,9 @@ impl<'a, 'b> PageExporter<'a, 'b> {
self.transform(translation.pre_concat(group.transform));
if group.clips {
let w = group.frame.size.x.to_f32();
let h = group.frame.size.y.to_f32();
let size = group.frame.size();
let w = size.x.to_f32();
let h = size.y.to_f32();
self.content.move_to(0.0, 0.0);
self.content.line_to(w, 0.0);
self.content.line_to(w, h);

View File

@ -23,8 +23,9 @@ use crate::Context;
/// compilation so that fonts and images can be rendered and rendering artifacts
/// can be cached.
pub fn render(ctx: &Context, frame: &Frame, pixel_per_pt: f32) -> sk::Pixmap {
let pxw = (pixel_per_pt * frame.size.x.to_f32()).round().max(1.0) as u32;
let pxh = (pixel_per_pt * frame.size.y.to_f32()).round().max(1.0) as u32;
let size = frame.size();
let pxw = (pixel_per_pt * size.x.to_f32()).round().max(1.0) as u32;
let pxh = (pixel_per_pt * size.y.to_f32()).round().max(1.0) as u32;
let mut canvas = sk::Pixmap::new(pxw, pxh).unwrap();
canvas.fill(sk::Color::WHITE);
@ -43,7 +44,7 @@ fn render_frame(
ctx: &Context,
frame: &Frame,
) {
for (pos, element) in &frame.elements {
for (pos, element) in frame.elements() {
let x = pos.x.to_f32();
let y = pos.y.to_f32();
let ts = ts.pre_translate(x, y);
@ -80,8 +81,9 @@ fn render_group(
let mut mask = mask;
let mut storage;
if group.clips {
let w = group.frame.size.x.to_f32();
let h = group.frame.size.y.to_f32();
let size = group.frame.size();
let w = size.x.to_f32();
let h = size.y.to_f32();
if let Some(path) = sk::Rect::from_xywh(0.0, 0.0, w, h)
.map(sk::PathBuilder::from_rect)
.and_then(|path| path.transform(ts))

View File

@ -17,38 +17,65 @@ use crate::util::{EcoString, MaybeShared};
#[derive(Default, Clone, Eq, PartialEq)]
pub struct Frame {
/// The size of the frame.
pub size: Size,
size: Size,
/// The baseline of the frame measured from the top. If this is `None`, the
/// frame's implicit baseline is at the bottom.
pub baseline: Option<Length>,
/// The elements composing this layout.
pub elements: Vec<(Point, Element)>,
baseline: Option<Length>,
/// The semantic role of the frame.
role: Option<Role>,
/// The elements composing this layout.
elements: Vec<(Point, Element)>,
}
/// Accessors and setters.
impl Frame {
/// Create a new, empty frame.
///
/// Panics the size is not finite.
#[track_caller]
pub fn new(size: Size) -> Self {
assert!(size.is_finite());
Self {
size,
baseline: None,
elements: vec![],
role: None,
elements: vec![],
}
}
/// The size of the frame.
pub fn size(&self) -> Size {
self.size
}
/// The size of the frame, mutably.
pub fn size_mut(&mut self) -> &mut Size {
&mut self.size
}
/// Set the size of the frame.
pub fn set_size(&mut self, size: Size) {
self.size = size;
}
/// The width of the frame.
pub fn width(&self) -> Length {
self.size.x
}
/// The height of the frame.
pub fn height(&self) -> Length {
self.size.y
}
/// The baseline of the frame.
pub fn baseline(&self) -> Length {
self.baseline.unwrap_or(self.size.y)
}
/// The layer the next item will be added on. This corresponds to the number
/// of elements in the frame.
pub fn layer(&self) -> usize {
self.elements.len()
/// Set the frame's baseline from the top.
pub fn set_baseline(&mut self, baseline: Length) {
self.baseline = Some(baseline);
}
/// The role of the frame.
@ -56,9 +83,36 @@ impl Frame {
self.role
}
/// Whether the frame has comparatively few elements.
pub fn is_light(&self) -> bool {
self.elements.len() <= 5
/// An iterator over the elements inside this frame alongside their
/// positions relative to the top-left of the frame.
pub fn elements(&self) -> std::slice::Iter<'_, (Point, Element)> {
self.elements.iter()
}
/// Recover the text inside of the frame and its children.
pub fn text(&self) -> EcoString {
let mut text = EcoString::new();
for (_, element) in &self.elements {
match element {
Element::Text(content) => {
for glyph in &content.glyphs {
text.push(glyph.c);
}
}
Element::Group(group) => text.push_str(&group.frame.text()),
_ => {}
}
}
text
}
}
/// Inserting elements and subframes.
impl Frame {
/// The layer the next item will be added on. This corresponds to the number
/// of elements in the frame.
pub fn layer(&self) -> usize {
self.elements.len()
}
/// Add an element at a position in the foreground.
@ -66,6 +120,14 @@ impl Frame {
self.elements.push((pos, element));
}
/// Insert an element at the given layer in the frame.
///
/// This panics if the layer is greater than the number of layers present.
#[track_caller]
pub fn insert(&mut self, layer: usize, pos: Point, element: Element) {
self.elements.insert(layer, (pos, element));
}
/// Add a frame.
///
/// Automatically decides whether to inline the frame or to include it as a
@ -105,11 +167,17 @@ impl Frame {
}
}
/// Insert an element at the given layer in the frame.
///
/// This panics if the layer is greater than the number of layers present.
pub fn insert(&mut self, layer: usize, pos: Point, element: Element) {
self.elements.insert(layer, (pos, element));
/// Whether the frame has comparatively few elements.
fn is_light(&self) -> bool {
self.elements.len() <= 5
}
}
/// Modify the frame.
impl Frame {
/// Remove all elements from the frame.
pub fn clear(&mut self) {
self.elements.clear();
}
/// Resize the frame to a new size, distributing new space according to the
@ -137,11 +205,6 @@ impl Frame {
}
}
/// Arbitrarily transform the contents of the frame.
pub fn transform(&mut self, transform: Transform) {
self.group(|g| g.transform = transform);
}
/// Apply the given role to the frame if it doesn't already have one.
pub fn apply_role(&mut self, role: Role) {
if self.role.map_or(true, Role::is_weak) {
@ -149,13 +212,23 @@ impl Frame {
}
}
/// Link the whole frame to a resource.
pub fn link(&mut self, dest: Destination) {
self.push(Point::zero(), Element::Link(dest, self.size));
}
/// Arbitrarily transform the contents of the frame.
pub fn transform(&mut self, transform: Transform) {
self.group(|g| g.transform = transform);
}
/// Clip the contents of a frame to its size.
pub fn clip(&mut self) {
self.group(|g| g.clips = true);
}
/// Wrap the frame's contents in a group and modify that group with `f`.
pub fn group<F>(&mut self, f: F)
fn group<F>(&mut self, f: F)
where
F: FnOnce(&mut Group),
{
@ -165,28 +238,6 @@ impl Frame {
wrapper.push(Point::zero(), Element::Group(group));
*self = wrapper;
}
/// Link the whole frame to a resource.
pub fn link(&mut self, dest: Destination) {
self.push(Point::zero(), Element::Link(dest, self.size));
}
/// Recover the text inside of the frame and its children.
pub fn text(&self) -> EcoString {
let mut text = EcoString::new();
for (_, element) in &self.elements {
match element {
Element::Text(content) => {
for glyph in &content.glyphs {
text.push(glyph.c);
}
}
Element::Group(group) => text.push_str(&group.frame.text()),
_ => {}
}
}
text
}
}
impl Debug for Frame {

View File

@ -22,11 +22,7 @@ impl Layout for HideNode {
// Clear the frames.
for frame in &mut frames {
*frame = Arc::new({
let mut empty = Frame::new(frame.size);
empty.baseline = frame.baseline;
empty
});
Arc::make_mut(frame).clear();
}
Ok(frames)

View File

@ -104,7 +104,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
let target = regions.expand.select(regions.first, Size::zero());
target.x.max(target.y)
} else {
let size = frames[0].size;
let size = frames[0].size();
let desired = size.x.max(size.y);
desired.min(regions.first.x).min(regions.first.y)
};
@ -146,8 +146,8 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
}
};
let outset = styles.get(Self::OUTSET).relative_to(frame.size);
let size = frame.size + outset.sum_by_axis();
let outset = styles.get(Self::OUTSET).relative_to(frame.size());
let size = frame.size() + outset.sum_by_axis();
let radius = styles
.get(Self::RADIUS)

View File

@ -33,7 +33,7 @@ impl Layout for MoveNode {
let delta = self.delta.resolve(styles);
for frame in &mut frames {
let delta = delta.zip(frame.size).map(|(d, s)| d.relative_to(s));
let delta = delta.zip(frame.size()).map(|(d, s)| d.relative_to(s));
Arc::make_mut(frame).translate(delta.to_point());
}
@ -94,7 +94,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> {
let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames {
let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.position(s));
let Spec { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s));
let transform = Transform::translate(x, y)
.pre_concat(self.transform)
.pre_concat(Transform::translate(-x, -y));

View File

@ -47,7 +47,7 @@ impl Layout for AlignNode {
for (region, frame) in regions.iter().zip(&mut frames) {
// Align in the target size. The target size depends on whether we
// should expand.
let target = regions.expand.select(region, frame.size);
let target = regions.expand.select(region, frame.size());
let aligns = self
.aligns
.map(|align| align.resolve(styles))

View File

@ -80,10 +80,10 @@ impl Layout for ColumnsNode {
};
if !regions.expand.y {
output.size.y.set_max(frame.size.y);
output.size_mut().y.set_max(frame.height());
}
let width = frame.size.x;
let width = frame.width();
let x = if dir.is_positive() {
cursor
} else {

View File

@ -189,7 +189,7 @@ impl FlowLayouter {
}
// Grow our size, shrink the region and save the frame for later.
let size = frame.size;
let size = frame.size();
self.used.y += size.y;
self.used.x.set_max(size.x);
self.regions.first.y -= size.y;
@ -231,10 +231,10 @@ impl FlowLayouter {
}
FlowItem::Frame(frame, aligns) => {
ruler = ruler.max(aligns.y);
let x = aligns.x.position(size.x - frame.size.x);
let x = aligns.x.position(size.x - frame.width());
let y = offset + ruler.position(size.y - self.used.y);
let pos = Point::new(x, y);
offset += frame.size.y;
offset += frame.height();
output.push_frame(pos, frame);
}
FlowItem::Placed(frame) => {

View File

@ -304,7 +304,7 @@ impl<'a> GridLayouter<'a> {
}
let frame = node.layout(self.ctx, &pod, self.styles)?.remove(0);
resolved.set_max(frame.size.x);
resolved.set_max(frame.width());
}
}
@ -376,7 +376,7 @@ impl<'a> GridLayouter<'a> {
let mut sizes = node
.layout(self.ctx, &pod, self.styles)?
.into_iter()
.map(|frame| frame.size.y);
.map(|frame| frame.height());
self.ctx.pins.unfreeze();
// For each region, we want to know the maximum height any
@ -432,7 +432,7 @@ impl<'a> GridLayouter<'a> {
let frame = self.layout_single_row(resolved, y)?;
// Skip to fitting region.
let height = frame.size.y;
let height = frame.height();
while !self.regions.first.y.fits(height) && !self.regions.in_last() {
self.finish_region()?;
@ -533,8 +533,8 @@ impl<'a> GridLayouter<'a> {
/// Push a row frame into the current region.
fn push_row(&mut self, frame: Frame) {
self.regions.first.y -= frame.size.y;
self.used.y += frame.size.y;
self.regions.first.y -= frame.height();
self.used.y += frame.height();
self.lrows.push(Row::Frame(frame));
}
@ -562,7 +562,7 @@ impl<'a> GridLayouter<'a> {
}
};
let height = frame.size.y;
let height = frame.height();
output.push_frame(pos, frame);
pos.y += height;
}

View File

@ -40,13 +40,13 @@ impl Layout for PadNode {
for frame in &mut frames {
// Apply the padding inversely such that the grown size padded
// yields the frame's size.
let padded = grow(frame.size, padding);
let padded = grow(frame.size(), padding);
let padding = padding.relative_to(padded);
let offset = Point::new(padding.left, padding.top);
// Grow the frame and translate everything in the frame inwards.
let frame = Arc::make_mut(frame);
frame.size = padded;
frame.set_size(padded);
frame.translate(offset);
}

View File

@ -106,7 +106,7 @@ impl PageNode {
// Realize overlays.
for frame in &mut frames {
let size = frame.size;
let size = frame.size();
let pad = padding.resolve(styles).relative_to(size);
let pw = size.x - pad.left - pad.right;
let py = size.y - pad.bottom;

View File

@ -201,7 +201,7 @@ impl<'a> StackLayouter<'a> {
}
// Grow our size, shrink the region and save the frame for later.
let size = frame.size.to_gen(self.axis);
let size = frame.size().to_gen(self.axis);
self.used.main += size.main;
self.used.cross.set_max(size.cross);
*self.regions.first.get_mut(self.axis) -= size.main;
@ -248,7 +248,7 @@ impl<'a> StackLayouter<'a> {
// Align along the block axis.
let parent = size.get(self.axis);
let child = frame.size.get(self.axis);
let child = frame.size().get(self.axis);
let block = ruler.position(parent - self.used.main)
+ if self.dir.is_positive() {
cursor

View File

@ -66,8 +66,8 @@ impl Layout for RexNode {
let mut backend = FrameBackend {
frame: {
let mut frame = Frame::new(size);
frame.set_baseline(baseline);
frame.apply_role(Role::Formula);
frame.baseline = Some(baseline);
frame
},
baseline,

View File

@ -336,7 +336,7 @@ impl<'a> Item<'a> {
match self {
Self::Text(shaped) => shaped.width,
Self::Absolute(v) => *v,
Self::Frame(frame) => frame.size.x,
Self::Frame(frame) => frame.width(),
Self::Fractional(_) | Self::Repeat(_, _) | Self::Pin(_) => Length::zero(),
}
}
@ -1071,7 +1071,7 @@ fn stack(
// Stack the lines into one frame per region.
for line in lines {
let frame = commit(p, ctx, line, &regions, width)?;
let height = frame.size.y;
let height = frame.size().y;
while !regions.first.y.fits(height) && !regions.in_last() {
finished.push(Arc::new(output));
@ -1082,11 +1082,11 @@ fn stack(
}
if !first {
output.size.y += p.leading;
output.size_mut().y += p.leading;
}
let pos = Point::with_y(output.size.y);
output.size.y += height;
let pos = Point::with_y(output.height());
output.size_mut().y += height;
output.push_frame(pos, frame);
regions.first.y -= height + p.leading;
@ -1156,9 +1156,9 @@ fn commit(
let mut frames = vec![];
for item in reordered {
let mut push = |offset: &mut Length, frame: MaybeShared<Frame>| {
let width = frame.size.x;
let width = frame.width();
top.set_max(frame.baseline());
bottom.set_max(frame.size.y - frame.baseline());
bottom.set_max(frame.size().y - frame.baseline());
frames.push((*offset, frame));
*offset += width;
};
@ -1179,23 +1179,24 @@ fn commit(
}
Item::Repeat(node, styles) => {
let before = offset;
let width = Fraction::one().share(fr, remaining);
let size = Size::new(width, regions.base.y);
let fill = Fraction::one().share(fr, remaining);
let size = Size::new(fill, regions.base.y);
let pod = Regions::one(size, regions.base, Spec::new(false, false));
let frame = node.layout(ctx, &pod, *styles)?.remove(0);
let count = (width / frame.size.x).floor();
let remaining = width % frame.size.x;
let width = frame.width();
let count = (fill / width).floor();
let remaining = fill % width;
let apart = remaining / (count - 1.0);
if count == 1.0 {
offset += p.align.position(remaining);
}
if frame.size.x > Length::zero() {
if width > Length::zero() {
for _ in 0 .. (count as usize).min(1000) {
push(&mut offset, MaybeShared::Shared(frame.clone()));
offset += apart;
}
}
offset = before + width;
offset = before + fill;
}
Item::Pin(idx) => {
let mut frame = Frame::new(Size::zero());
@ -1212,7 +1213,7 @@ fn commit(
let size = Size::new(width, top + bottom);
let mut output = Frame::new(size);
output.baseline = Some(top);
output.set_baseline(top);
// Construct the line's frame.
for (offset, frame) in frames {

View File

@ -84,7 +84,7 @@ impl<'a> ShapedText<'a> {
let mut offset = Length::zero();
let mut frame = Frame::new(size);
frame.baseline = Some(top);
frame.set_baseline(top);
let shift = self.styles.get(TextNode::BASELINE);
let lang = self.styles.get(TextNode::LANG);
@ -103,7 +103,7 @@ impl<'a> ShapedText<'a> {
id: glyph.glyph_id,
x_advance: glyph.x_advance
+ if glyph.is_justifiable() {
frame.size.x += justification;
frame.size_mut().x += justification;
Em::from_length(justification, self.size)
} else {
Em::zero()
@ -120,6 +120,7 @@ impl<'a> ShapedText<'a> {
fill,
glyphs,
};
let text_layer = frame.layer();
let width = text.width();

View File

@ -366,7 +366,7 @@ impl Layout for SizedNode {
// Ensure frame size matches regions size if expansion is on.
let frame = &mut frames[0];
let target = regions.expand.select(regions.first, frame.size);
let target = regions.expand.select(regions.first, frame.size());
Arc::make_mut(frame).resize(target, Align::LEFT_TOP);
Ok(frames)
@ -391,7 +391,7 @@ impl Layout for FillNode {
) -> TypResult<Vec<Arc<Frame>>> {
let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames {
let shape = Geometry::Rect(frame.size).filled(self.fill);
let shape = Geometry::Rect(frame.size()).filled(self.fill);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
}
Ok(frames)
@ -416,7 +416,7 @@ impl Layout for StrokeNode {
) -> TypResult<Vec<Arc<Frame>>> {
let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames {
let shape = Geometry::Rect(frame.size).stroked(self.stroke);
let shape = Geometry::Rect(frame.size()).stroked(self.stroke);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
}
Ok(frames)

View File

@ -299,7 +299,7 @@ fn locate_in_frame(
frame: &Frame,
ts: Transform,
) {
for &(pos, ref element) in &frame.elements {
for &(pos, ref element) in frame.elements() {
match element {
Element::Group(group) => {
let ts = ts

View File

@ -538,8 +538,8 @@ fn render(ctx: &mut Context, frames: &[Arc<Frame>]) -> sk::Pixmap {
.iter()
.map(|frame| {
let limit = Length::cm(100.0);
if frame.size.x > limit || frame.size.y > limit {
panic!("overlarge frame: {:?}", frame.size);
if frame.width() > limit || frame.height() > limit {
panic!("overlarge frame: {:?}", frame.size());
}
typst::export::render(ctx, frame, pixel_per_pt)
})
@ -579,7 +579,7 @@ fn render_links(
ctx: &Context,
frame: &Frame,
) {
for (pos, element) in &frame.elements {
for (pos, element) in frame.elements() {
let ts = ts.pre_translate(pos.x.to_pt() as f32, pos.y.to_pt() as f32);
match *element {
Element::Group(ref group) => {