@@ -11,6 +11,7 @@ use crate::fonts::{self, FontLibrary};
1111use crate :: shaper:: { GlyphRun , PartMetrics } ;
1212use crate :: { Align , Range , Vec2 } ;
1313use smallvec:: SmallVec ;
14+ use std:: num:: NonZeroUsize ;
1415use tinyvec:: TinyVec ;
1516use unicode_bidi:: { LTR_LEVEL , Level } ;
1617
@@ -22,12 +23,33 @@ pub struct RunPart {
2223 pub offset : Vec2 ,
2324}
2425
26+ /// Per-line data (post wrapping)
2527#[ derive( Clone , Debug , Default ) ]
2628pub struct Line {
27- pub text_range : Range , // range in text
28- pub run_range : Range , // range in wrapped_runs
29- pub top : f32 ,
30- pub bottom : f32 ,
29+ text_range : Range , // range in text
30+ pub ( crate ) run_range : Range , // range in wrapped_runs
31+ pub ( crate ) top : f32 ,
32+ pub ( crate ) bottom : f32 ,
33+ }
34+
35+ impl Line {
36+ /// Get the text range of line contents
37+ #[ inline]
38+ pub fn text_range ( & self ) -> std:: ops:: Range < usize > {
39+ self . text_range . to_std ( )
40+ }
41+
42+ /// Get the upper bound of the line
43+ #[ inline]
44+ pub fn top ( & self ) -> f32 {
45+ self . top
46+ }
47+
48+ /// Get the lower bound of the line
49+ #[ inline]
50+ pub fn bottom ( & self ) -> f32 {
51+ self . bottom
52+ }
3153}
3254
3355impl TextDisplay {
@@ -70,16 +92,15 @@ impl TextDisplay {
7092
7193 /// Measure required vertical height, wrapping as configured
7294 ///
95+ /// Stops after `max_lines`, if provided.
96+ ///
7397 /// [Requires status][Self#status-of-preparation]: level runs have been
7498 /// prepared.
75- ///
76- /// This method performs most required preparation steps of the
77- /// [`TextDisplay`]. Remaining prepartion should be fast.
78- pub fn measure_height ( & self , wrap_width : f32 ) -> f32 {
99+ pub fn measure_height ( & self , wrap_width : f32 , max_lines : Option < NonZeroUsize > ) -> f32 {
79100 #[ derive( Default ) ]
80101 struct MeasureAdder {
81102 parts : Vec < usize > , // run index for each part
82- has_any_lines : bool ,
103+ lines : usize ,
83104 line_gap : f32 ,
84105 vcaret : f32 ,
85106 }
@@ -89,6 +110,10 @@ impl TextDisplay {
89110 self . parts . len ( )
90111 }
91112
113+ fn num_lines ( & self ) -> usize {
114+ self . lines
115+ }
116+
92117 fn add_part (
93118 & mut self ,
94119 _: & [ GlyphRun ] ,
@@ -134,7 +159,7 @@ impl TextDisplay {
134159 line_gap = line_gap. max ( scale_font. line_gap ( ) ) ;
135160 }
136161
137- if self . has_any_lines {
162+ if self . lines > 0 {
138163 self . vcaret += line_gap. max ( self . line_gap ) ;
139164 }
140165 self . vcaret += ascent - descent;
@@ -143,13 +168,14 @@ impl TextDisplay {
143168 // Vertically align lines to the nearest pixel (improves rendering):
144169 self . vcaret = self . vcaret . round ( ) ;
145170
146- self . has_any_lines = true ;
171+ self . lines += 1 ;
147172 self . parts . clear ( ) ;
148173 }
149174 }
150175
151176 let mut adder = MeasureAdder :: default ( ) ;
152- self . wrap_lines ( & mut adder, wrap_width) ;
177+ let max_lines = max_lines. map ( |n| n. get ( ) ) . unwrap_or ( 0 ) ;
178+ self . wrap_lines ( & mut adder, wrap_width, max_lines) ;
153179 adder. vcaret
154180 }
155181
@@ -188,7 +214,7 @@ impl TextDisplay {
188214 debug_assert ! ( width_bound. is_finite( ) ) ;
189215 let mut adder = LineAdder :: new ( width_bound, h_align) ;
190216
191- self . wrap_lines ( & mut adder, wrap_width) ;
217+ self . wrap_lines ( & mut adder, wrap_width, 0 ) ;
192218
193219 self . wrapped_runs = adder. wrapped_runs ;
194220 self . lines = adder. lines ;
@@ -201,7 +227,12 @@ impl TextDisplay {
201227 adder. vcaret
202228 }
203229
204- fn wrap_lines ( & self , accumulator : & mut impl PartAccumulator , wrap_width : f32 ) {
230+ fn wrap_lines (
231+ & self ,
232+ accumulator : & mut impl PartAccumulator ,
233+ wrap_width : f32 ,
234+ max_lines : usize ,
235+ ) {
205236 let fonts = fonts:: library ( ) ;
206237
207238 // Tuples: (index, part_index, num_parts)
@@ -244,6 +275,10 @@ impl TextDisplay {
244275 // Add up to last valid break point then wrap and reset
245276 accumulator. add_line ( fonts, & self . runs , end. 2 , true ) ;
246277
278+ if accumulator. num_lines ( ) == max_lines {
279+ return ;
280+ }
281+
247282 end. 2 = 0 ;
248283 start = end;
249284 caret = 0.0 ;
@@ -276,6 +311,10 @@ impl TextDisplay {
276311 debug_assert_eq ! ( num_parts, end. 2 ) ;
277312
278313 accumulator. add_line ( fonts, & self . runs , num_parts, false ) ;
314+
315+ if accumulator. num_lines ( ) == max_lines {
316+ return ;
317+ }
279318 }
280319
281320 start = ( run_index, 0 , 0 ) ;
@@ -332,6 +371,7 @@ impl TextDisplay {
332371
333372trait PartAccumulator {
334373 fn num_parts ( & self ) -> usize ;
374+ fn num_lines ( & self ) -> usize ;
335375
336376 fn add_part (
337377 & mut self ,
@@ -386,6 +426,10 @@ impl PartAccumulator for LineAdder {
386426 self . parts . len ( )
387427 }
388428
429+ fn num_lines ( & self ) -> usize {
430+ self . lines . len ( )
431+ }
432+
389433 fn add_part (
390434 & mut self ,
391435 runs : & [ GlyphRun ] ,
0 commit comments