Skip to content

Commit e14c7ad

Browse files
committed
Lazily initialize content widths
1 parent 958ba51 commit e14c7ad

File tree

2 files changed

+31
-27
lines changed

2 files changed

+31
-27
lines changed

parley/src/layout/data.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::layout::{Alignment, Glyph, LineMetrics, RunMetrics, Style};
66
use crate::style::Brush;
77
use crate::util::nearly_zero;
88
use crate::Font;
9+
use core::cell::OnceCell;
910
use core::ops::Range;
1011
use swash::shape::Shaper;
1112
use swash::text::cluster::{Boundary, ClusterInfo};
@@ -195,12 +196,13 @@ pub(crate) struct LayoutData<B: Brush> {
195196
pub(crate) text_len: usize,
196197
pub(crate) width: f32,
197198
pub(crate) full_width: f32,
198-
pub(crate) min_content_width: f32,
199-
pub(crate) max_content_width: f32,
200199
pub(crate) height: f32,
201200
pub(crate) fonts: Vec<Font>,
202201
pub(crate) coords: Vec<i16>,
203202

203+
// Lazily calculated values
204+
content_widths: OnceCell<(f32, f32)>,
205+
204206
// Input (/ output of style resolution)
205207
pub(crate) styles: Vec<Style<B>>,
206208
pub(crate) inline_boxes: Vec<InlineBox>,
@@ -225,8 +227,7 @@ impl<B: Brush> Default for LayoutData<B> {
225227
text_len: 0,
226228
width: 0.,
227229
full_width: 0.,
228-
min_content_width: 0.,
229-
max_content_width: 0.,
230+
content_widths: OnceCell::new(),
230231
height: 0.,
231232
fonts: Vec::new(),
232233
coords: Vec::new(),
@@ -250,8 +251,7 @@ impl<B: Brush> LayoutData<B> {
250251
self.text_len = 0;
251252
self.width = 0.;
252253
self.full_width = 0.;
253-
self.min_content_width = 0.;
254-
self.max_content_width = 0.;
254+
self.content_widths.take();
255255
self.height = 0.;
256256
self.fonts.clear();
257257
self.coords.clear();
@@ -450,11 +450,6 @@ impl<B: Brush> LayoutData<B> {
450450
}
451451

452452
pub(crate) fn finish(&mut self) {
453-
self.apply_spacing();
454-
self.calculate_content_widths();
455-
}
456-
457-
fn apply_spacing(&mut self) {
458453
for run in &self.runs {
459454
let word = run.word_spacing;
460455
let letter = run.letter_spacing;
@@ -482,48 +477,57 @@ impl<B: Brush> LayoutData<B> {
482477
}
483478
}
484479

485-
fn calculate_content_widths(&mut self) {
480+
pub(crate) fn content_widths(&self) -> (f32, f32) {
481+
*self
482+
.content_widths
483+
.get_or_init(|| self.calculate_content_widths())
484+
}
485+
486+
fn calculate_content_widths(&self) -> (f32, f32) {
486487
fn whitespace_advance(cluster: Option<&ClusterData>) -> f32 {
487488
cluster
488489
.filter(|cluster| cluster.info.whitespace().is_space_or_nbsp())
489490
.map_or(0.0, |cluster| cluster.advance)
490491
}
491492

492-
let mut max_width = 0.0;
493+
let mut min_width = 0.0_f32;
494+
let mut max_width = 0.0_f32;
495+
496+
let mut running_max_width = 0.0;
493497
let mut prev_cluster: Option<&ClusterData> = None;
494498
for item in &self.items {
495499
match item.kind {
496500
LayoutItemKind::TextRun => {
497501
let run = &self.runs[item.index];
498-
let mut min_width = 0.0;
502+
let mut running_min_width = 0.0;
499503
for cluster in &self.clusters[run.cluster_range.clone()] {
500504
let boundary = cluster.info.boundary();
501505
if matches!(boundary, Boundary::Line | Boundary::Mandatory) {
502506
let trailing_whitespace = whitespace_advance(prev_cluster);
503-
self.min_content_width =
504-
self.min_content_width.max(min_width - trailing_whitespace);
505-
min_width = 0.0;
507+
min_width = min_width.max(running_min_width - trailing_whitespace);
508+
running_min_width = 0.0;
506509
if boundary == Boundary::Mandatory {
507-
max_width = 0.0;
510+
running_max_width = 0.0;
508511
}
509512
}
510-
min_width += cluster.advance;
513+
running_min_width += cluster.advance;
511514
prev_cluster = Some(cluster);
512515
}
513516
let trailing_whitespace = whitespace_advance(prev_cluster);
514-
self.min_content_width =
515-
self.min_content_width.max(min_width - trailing_whitespace);
516-
max_width += run.advance;
517+
min_width = min_width.max(running_min_width - trailing_whitespace);
518+
running_max_width += run.advance;
517519
}
518520
LayoutItemKind::InlineBox => {
519521
let ibox = &self.inline_boxes[item.index];
520-
self.min_content_width = self.min_content_width.max(ibox.width);
521-
max_width += ibox.width;
522+
min_width = min_width.max(ibox.width);
523+
running_max_width += ibox.width;
522524
prev_cluster = None;
523525
}
524526
}
525527
let trailing_whitespace = whitespace_advance(prev_cluster);
526-
self.max_content_width = self.max_content_width.max(max_width - trailing_whitespace);
528+
max_width = max_width.max(running_max_width - trailing_whitespace);
527529
}
530+
531+
(min_width, max_width)
528532
}
529533
}

parley/src/layout/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ impl<B: Brush> Layout<B> {
8484
/// Returns the minimum content width of the layout. This is the width of the layout if _all_
8585
/// soft line-breaking opportunities are taken.
8686
pub fn min_content_width(&self) -> f32 {
87-
self.data.min_content_width
87+
self.data.content_widths().0
8888
}
8989

9090
/// Returns the maximum content width of the layout. This is the width of the layout if _no_
9191
/// soft line-breaking opportunities are taken.
9292
pub fn max_content_width(&self) -> f32 {
93-
self.data.max_content_width
93+
self.data.content_widths().1
9494
}
9595

9696
/// Returns the height of the layout.

0 commit comments

Comments
 (0)