@@ -6,6 +6,7 @@ use crate::layout::{Alignment, Glyph, LineMetrics, RunMetrics, Style};
6
6
use crate :: style:: Brush ;
7
7
use crate :: util:: nearly_zero;
8
8
use crate :: Font ;
9
+ use core:: cell:: OnceCell ;
9
10
use core:: ops:: Range ;
10
11
use swash:: shape:: Shaper ;
11
12
use swash:: text:: cluster:: { Boundary , ClusterInfo } ;
@@ -195,12 +196,13 @@ pub(crate) struct LayoutData<B: Brush> {
195
196
pub ( crate ) text_len : usize ,
196
197
pub ( crate ) width : f32 ,
197
198
pub ( crate ) full_width : f32 ,
198
- pub ( crate ) min_content_width : f32 ,
199
- pub ( crate ) max_content_width : f32 ,
200
199
pub ( crate ) height : f32 ,
201
200
pub ( crate ) fonts : Vec < Font > ,
202
201
pub ( crate ) coords : Vec < i16 > ,
203
202
203
+ // Lazily calculated values
204
+ content_widths : OnceCell < ( f32 , f32 ) > ,
205
+
204
206
// Input (/ output of style resolution)
205
207
pub ( crate ) styles : Vec < Style < B > > ,
206
208
pub ( crate ) inline_boxes : Vec < InlineBox > ,
@@ -225,8 +227,7 @@ impl<B: Brush> Default for LayoutData<B> {
225
227
text_len : 0 ,
226
228
width : 0. ,
227
229
full_width : 0. ,
228
- min_content_width : 0. ,
229
- max_content_width : 0. ,
230
+ content_widths : OnceCell :: new ( ) ,
230
231
height : 0. ,
231
232
fonts : Vec :: new ( ) ,
232
233
coords : Vec :: new ( ) ,
@@ -250,8 +251,7 @@ impl<B: Brush> LayoutData<B> {
250
251
self . text_len = 0 ;
251
252
self . width = 0. ;
252
253
self . full_width = 0. ;
253
- self . min_content_width = 0. ;
254
- self . max_content_width = 0. ;
254
+ self . content_widths . take ( ) ;
255
255
self . height = 0. ;
256
256
self . fonts . clear ( ) ;
257
257
self . coords . clear ( ) ;
@@ -450,11 +450,6 @@ impl<B: Brush> LayoutData<B> {
450
450
}
451
451
452
452
pub ( crate ) fn finish ( & mut self ) {
453
- self . apply_spacing ( ) ;
454
- self . calculate_content_widths ( ) ;
455
- }
456
-
457
- fn apply_spacing ( & mut self ) {
458
453
for run in & self . runs {
459
454
let word = run. word_spacing ;
460
455
let letter = run. letter_spacing ;
@@ -482,48 +477,57 @@ impl<B: Brush> LayoutData<B> {
482
477
}
483
478
}
484
479
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 ) {
486
487
fn whitespace_advance ( cluster : Option < & ClusterData > ) -> f32 {
487
488
cluster
488
489
. filter ( |cluster| cluster. info . whitespace ( ) . is_space_or_nbsp ( ) )
489
490
. map_or ( 0.0 , |cluster| cluster. advance )
490
491
}
491
492
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 ;
493
497
let mut prev_cluster: Option < & ClusterData > = None ;
494
498
for item in & self . items {
495
499
match item. kind {
496
500
LayoutItemKind :: TextRun => {
497
501
let run = & self . runs [ item. index ] ;
498
- let mut min_width = 0.0 ;
502
+ let mut running_min_width = 0.0 ;
499
503
for cluster in & self . clusters [ run. cluster_range . clone ( ) ] {
500
504
let boundary = cluster. info . boundary ( ) ;
501
505
if matches ! ( boundary, Boundary :: Line | Boundary :: Mandatory ) {
502
506
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 ;
506
509
if boundary == Boundary :: Mandatory {
507
- max_width = 0.0 ;
510
+ running_max_width = 0.0 ;
508
511
}
509
512
}
510
- min_width += cluster. advance ;
513
+ running_min_width += cluster. advance ;
511
514
prev_cluster = Some ( cluster) ;
512
515
}
513
516
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 ;
517
519
}
518
520
LayoutItemKind :: InlineBox => {
519
521
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 ;
522
524
prev_cluster = None ;
523
525
}
524
526
}
525
527
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) ;
527
529
}
530
+
531
+ ( min_width, max_width)
528
532
}
529
533
}
0 commit comments