ferroui_pretext_layout/
prepared_text_metrics.rs1use ferroui_pretext::{LayoutCursor, PreparedTextWithSegments, PretextLayout};
2
3use crate::{LayoutError, WrapMetrics};
4
5pub struct PreparedTextMetrics;
7
8impl PreparedTextMetrics {
9 pub fn measure_max_line_width(prepared: &PreparedTextWithSegments) -> f64 {
10 PretextLayout::measure_natural_width(prepared)
11 }
12
13 pub fn collect_wrap_metrics(
14 prepared: &PreparedTextWithSegments,
15 max_width: f64,
16 line_height: f64,
17 ) -> WrapMetrics {
18 let stats = PretextLayout::measure_line_stats(prepared, max_width);
19 WrapMetrics {
20 line_count: stats.line_count,
21 height: stats.line_count as f64 * line_height,
22 max_line_width: stats.max_line_width,
23 }
24 }
25
26 pub fn find_tight_wrap_metrics(
30 prepared: &PreparedTextWithSegments,
31 max_width: f64,
32 line_height: f64,
33 ) -> Result<WrapMetrics, LayoutError> {
34 if !max_width.is_finite() || max_width <= 0.0 || max_width > (1u64 << 53) as f64 {
35 return Err(LayoutError::InvalidMaximumWidth);
36 }
37 if !line_height.is_finite() || line_height <= 0.0 {
38 return Err(LayoutError::InvalidLineHeight);
39 }
40 let initial = Self::collect_wrap_metrics(prepared, max_width, line_height);
41 let mut lo = 1.0;
42 let mut hi = max_width.ceil().max(1.0);
43 while lo < hi {
44 let mid = lo + ((hi - lo) * 0.5).floor();
45 let result = PretextLayout::layout(prepared, mid, line_height);
46 if result.line_count <= initial.line_count {
47 hi = mid;
48 } else {
49 lo = mid + 1.0;
50 }
51 }
52 Ok(Self::collect_wrap_metrics(prepared, lo, line_height))
53 }
54
55 pub fn is_end(prepared: &PreparedTextWithSegments, cursor: LayoutCursor) -> bool {
56 cursor.segment_index >= prepared.segments().len()
57 }
58}