Skip to content

Commit 632bfca

Browse files
committed
Allow the caller to set x/y/max_advance for each line
Signed-off-by: Nico Burns <[email protected]>
1 parent 501216d commit 632bfca

File tree

3 files changed

+98
-32
lines changed

3 files changed

+98
-32
lines changed

parley/src/layout/line/greedy.rs

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,14 @@ pub struct LineBreakData {
6464
}
6565

6666
pub struct BoxBreakData {
67-
pub inline_box_id: usize,
67+
/// The user-supplied ID for the inline box
68+
pub inline_box_id: u64,
69+
// The index of the inline box within the inline_boxes `Vec`
70+
pub inline_box_index: usize,
6871
}
6972

7073
#[derive(Clone, Default)]
71-
struct BreakerState {
74+
pub struct BreakerState {
7275
/// The number of items that have been processed (used to revert state)
7376
items: usize,
7477
/// The number of lines that have been processed (used to revert state)
@@ -81,9 +84,16 @@ struct BreakerState {
8184
/// Iteration state: the current cluster (within the layout)
8285
cluster_idx: usize,
8386

84-
/// The y coordinate of the bottom of the last committed line (or else 0)
87+
/// The x coordinate of the left/start of the current line
88+
line_x: f32,
89+
/// The y coordinate of the top/start of the current line
8590
/// Use of f64 here is important. f32 causes test failures due to accumulated error
86-
committed_y: f64,
91+
line_y: f64,
92+
93+
/// The max advance of the entire layout.
94+
layout_max_advance: f32,
95+
/// The max advance (max width) of the current line. This must be <= the `layout_max_advance`.
96+
line_max_advance: f32,
8797

8898
line: LineState,
8999
prev_boundary: Option<PrevBoundaryState>,
@@ -92,7 +102,7 @@ struct BreakerState {
92102

93103
impl BreakerState {
94104
/// Add the cluster(s) currently being evaluated to the current line
95-
fn append_cluster_to_line(&mut self, next_x: f32) {
105+
pub fn append_cluster_to_line(&mut self, next_x: f32) {
96106
self.line.items.end = self.item_idx + 1;
97107
self.line.clusters.end = self.cluster_idx + 1;
98108
self.line.x = next_x;
@@ -101,7 +111,7 @@ impl BreakerState {
101111
}
102112

103113
/// Add inline box to line
104-
fn append_inline_box_to_line(&mut self, next_x: f32) {
114+
pub fn append_inline_box_to_line(&mut self, next_x: f32) {
105115
// self.item_idx += 1;
106116
self.line.items.end += 1;
107117
self.line.x = next_x;
@@ -111,7 +121,7 @@ impl BreakerState {
111121

112122
/// Store the current iteration state so that we can revert to it if we later want to take
113123
/// the line breaking opportunity at this point.
114-
fn mark_line_break_opportunity(&mut self) {
124+
pub fn mark_line_break_opportunity(&mut self) {
115125
self.prev_boundary = Some(PrevBoundaryState {
116126
item_idx: self.item_idx,
117127
run_idx: self.run_idx,
@@ -122,14 +132,36 @@ impl BreakerState {
122132

123133
/// Store the current iteration state so that we can revert to it if we later want to take
124134
/// an *emergency* line breaking opportunity at this point.
125-
fn mark_emergency_break_opportunity(&mut self) {
135+
pub fn mark_emergency_break_opportunity(&mut self) {
126136
self.emergency_boundary = Some(PrevBoundaryState {
127137
item_idx: self.item_idx,
128138
run_idx: self.run_idx,
129139
cluster_idx: self.cluster_idx,
130140
state: self.line.clone(),
131141
});
132142
}
143+
144+
pub fn set_layout_max_advance(&mut self, advance: f32) {
145+
self.layout_max_advance = advance;
146+
}
147+
148+
pub fn set_line_max_advance(&mut self, advance: f32) {
149+
self.line_max_advance = advance;
150+
}
151+
152+
pub fn line_x(&self) -> f32 {
153+
self.line_x
154+
}
155+
pub fn set_line_x(&mut self, x: f32) {
156+
self.line_x = x;
157+
}
158+
159+
pub fn line_y(&self) -> f64 {
160+
self.line_y
161+
}
162+
pub fn set_line_y(&mut self, y: f64) {
163+
self.line_y = y;
164+
}
133165
}
134166

135167
/// Line breaking support for a paragraph.
@@ -179,9 +211,35 @@ impl<'a, B: Brush> BreakLines<'a, B> {
179211
}
180212
}
181213

214+
pub fn state(&self) -> &BreakerState {
215+
&self.state
216+
}
217+
218+
pub fn state_mut(&mut self) -> &mut BreakerState {
219+
&mut self.state
220+
}
221+
222+
/// Reverts the to an externally saved state.
223+
pub fn revert_to(&mut self, state: BreakerState) {
224+
self.state = state;
225+
self.lines.lines.truncate(self.state.lines);
226+
self.lines.line_items.truncate(self.state.items);
227+
self.done = false;
228+
}
229+
230+
/// Reverts the last computed line, returning to the previous state.
231+
pub fn revert(&mut self) -> bool {
232+
if let Some(state) = self.prev_state.take() {
233+
self.revert_to(state);
234+
true
235+
} else {
236+
false
237+
}
238+
}
239+
182240
/// Returns the y-coordinate of the top of the current line
183241
pub fn committed_y(&self) -> f64 {
184-
self.state.committed_y
242+
self.state.line_y
185243
}
186244

187245
/// Returns true if all the text has been placed into lines.
@@ -191,13 +249,13 @@ impl<'a, B: Brush> BreakLines<'a, B> {
191249

192250
/// Computes the next line in the paragraph. Returns the advance and size
193251
/// (width and height for horizontal layouts) of the line.
194-
pub fn break_next(&mut self, max_advance: f32) -> Option<YieldData> {
195-
self.break_next_line_or_box(max_advance)
252+
pub fn break_next(&mut self) -> Option<YieldData> {
253+
self.break_next_line_or_box()
196254
}
197255

198256
/// Computes the next line in the paragraph. Returns the advance and size
199257
/// (width and height for horizontal layouts) of the line.
200-
fn break_next_line_or_box(&mut self, max_advance: f32) -> Option<YieldData> {
258+
fn break_next_line_or_box(&mut self) -> Option<YieldData> {
201259
// Maintain iterator state
202260
if self.done {
203261
return None;
@@ -210,7 +268,7 @@ impl<'a, B: Brush> BreakLines<'a, B> {
210268
if self.layout.data.text_len == 0 && self.layout.data.inline_boxes.is_empty() {
211269
f32::MAX
212270
} else {
213-
max_advance
271+
self.state.line_max_advance
214272
};
215273

216274
// This macro simply calls the `commit_line` with the provided arguments and some parts of self.
@@ -248,6 +306,15 @@ impl<'a, B: Brush> BreakLines<'a, B> {
248306
LayoutItemKind::InlineBox => {
249307
let inline_box = &self.layout.data.inline_boxes[item.index];
250308

309+
// If the box is marked as "break_on_box", then the assumption is that the caller will handle placement of the box.
310+
if inline_box.break_on_box {
311+
self.state.item_idx += 1;
312+
return Some(YieldData::InlineBoxBreak(BoxBreakData {
313+
inline_box_id: inline_box.id,
314+
inline_box_index: item.index,
315+
}));
316+
}
317+
251318
// Compute the x position of the content being currently processed
252319
let next_x = self.state.line.x + inline_box.width;
253320

@@ -424,19 +491,6 @@ impl<'a, B: Brush> BreakLines<'a, B> {
424491
None
425492
}
426493

427-
/// Reverts the last computed line, returning to the previous state.
428-
pub fn revert(&mut self) -> bool {
429-
if let Some(state) = self.prev_state.take() {
430-
self.state = state;
431-
self.lines.lines.truncate(self.state.lines);
432-
self.lines.line_items.truncate(self.state.items);
433-
self.done = false;
434-
true
435-
} else {
436-
false
437-
}
438-
}
439-
440494
/// Breaks all remaining lines with the specified maximum advance. This
441495
/// consumes the line breaker.
442496
pub fn break_remaining(mut self, max_advance: f32) {
@@ -452,8 +506,17 @@ impl<'a, B: Brush> BreakLines<'a, B> {
452506
// }
453507

454508
// println!("\nBREAK ALL");
455-
456-
while self.break_next(max_advance).is_some() {}
509+
self.state.layout_max_advance = max_advance;
510+
self.state.line_max_advance = max_advance;
511+
while let Some(data) = self.break_next() {
512+
match data {
513+
YieldData::LineBreak(line_break_data) => {
514+
self.state.line_y += line_break_data.line_height as f64;
515+
continue;
516+
}
517+
YieldData::InlineBoxBreak(_) => continue,
518+
}
519+
}
457520
self.finish();
458521
}
459522

@@ -476,7 +539,7 @@ impl<'a, B: Brush> BreakLines<'a, B> {
476539

477540
// Whether metrics should be quantized to pixel boundaries
478541
let quantize = self.layout.data.quantize;
479-
let y = self.state.committed_y;
542+
let y = self.state.line_y;
480543

481544
// Reset metrics for line
482545
line.metrics.ascent = 0.;
@@ -661,7 +724,8 @@ impl<'a, B: Brush> BreakLines<'a, B> {
661724
line.metrics.block_min_coord = line.metrics.baseline - ascent - leading_above.max(0.);
662725
line.metrics.block_max_coord = line.metrics.baseline + descent + leading_below.max(0.);
663726

664-
self.state.committed_y += line.metrics.line_height as f64;
727+
line.metrics.inline_min_coord = self.state.line_x;
728+
line.metrics.inline_max_coord = self.state.line_x + self.state.line_max_advance;
665729
}
666730
}
667731

parley/src/layout/line/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ impl<'a, B: Brush> Iterator for GlyphRunIter<'a, B> {
284284
style,
285285
glyph_start,
286286
glyph_count,
287-
offset: offset + self.line.data.metrics.offset,
287+
offset: offset
288+
// + self.line.data.metrics.inline_min_coord
289+
+ self.line.data.metrics.offset,
288290
baseline: self.line.data.metrics.baseline,
289291
advance,
290292
}));

parley/src/layout/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub use cluster::{Affinity, ClusterPath, ClusterSide};
3434
pub use cursor::{Cursor, Selection};
3535
pub use data::BreakReason;
3636
pub(crate) use line::LineItem;
37-
pub use line::greedy::{BoxBreakData, BreakLines, LineBreakData, YieldData};
37+
pub use line::greedy::{BoxBreakData, BreakLines, BreakerState, LineBreakData, YieldData};
3838
pub use line::{GlyphRun, LineMetrics, PositionedInlineBox, PositionedLayoutItem};
3939
pub use run::RunMetrics;
4040

0 commit comments

Comments
 (0)