55
66//! Text prepared for display
77
8- #[ allow( unused) ]
9- use crate :: Text ;
108use crate :: conv:: to_usize;
11- use crate :: { Direction , Vec2 , shaper} ;
9+ #[ allow( unused) ]
10+ use crate :: { Direction , Status , Text } ;
11+ use crate :: { Vec2 , shaper} ;
1212use smallvec:: SmallVec ;
1313use tinyvec:: TinyVec ;
1414
@@ -37,33 +37,24 @@ pub struct NotReady;
3737///
3838/// ### Status of preparation
3939///
40- /// Stages of preparation are as follows:
41- ///
42- /// 1. Ensure all required [fonts](crate::fonts) are loaded.
43- /// 2. Call [`Self::prepare_runs`] to break text into level runs, then shape
44- /// these runs into glyph runs (unwrapped but with weak break points).
40+ /// This struct does not track the state-of-preparation internally. It is
41+ /// recommended to use [`Text`] or a custom wrapper to do this. The [`Status`]
42+ /// enum may be helpful here.
4543///
46- /// This method must be called again if the `text`, text `direction` or
47- /// `font_id` change. If only the text size (`dpem`) changes, it is
48- /// sufficient to instead call [`Self::resize_runs`].
49- /// 3. Optionally, [`Self::measure_width`] and [`Self::measure_height`] may be
50- /// used at this point to determine size requirements.
51- /// 4. Call [`Self::prepare_lines`] to wrap text and perform re-ordering (where
52- /// lines are bi-directional) and horizontal alignment.
44+ /// Methods note the expected status-of-preparation. Violating this expectation
45+ /// is memory-safe but may cause a panic or an unexpected result.
5346///
54- /// This must be called again if any of `wrap_width`, `width_bound` or
55- /// `h_align` change.
56- /// 5. Call [`Self::vertically_align`] to set or adjust vertical alignment.
57- /// (Not technically required if alignment is always top.)
47+ /// Steps of preparation are as follows:
5848///
59- /// All methods are idempotent (that is, they may be called multiple times
60- /// without affecting the result). Later stages of preparation do not affect
61- /// earlier stages, but if an earlier stage is repeated to account for adjusted
62- /// configuration then later stages must also be repeated.
63- ///
64- /// This struct does not track the state of preparation. It is recommended to
65- /// use [`Text`] or a custom wrapper for that purpose. Failure to observe the
66- /// correct sequence is memory-safe but may cause panic or an unexpected result.
49+ /// 1. Run-breaking: call [`Self::prepare_runs`] to break text into runs,
50+ /// resolve fonts and apply shaping. (This is the most expensive step,
51+ /// especially when shaping is enabled.)
52+ /// 2. (Optional) Measure size requirements using [`Self::measure_width`] and
53+ /// [`Self::measure_height`].
54+ /// 3. Line-wrapping: call [`Self::prepare_lines`] to perform line-wrapping at
55+ /// the given wrap-width. This also re-orders segments (where lines are
56+ /// bi-directional) and performs horizontal alignment.
57+ /// 4. (Optional) Tweak alignment (e.g. to vertically center text).
6758///
6859/// ### Text navigation
6960///
@@ -85,12 +76,8 @@ pub struct NotReady;
8576/// which provides a
8677/// [`GraphemeCursor`](https://unicode-rs.github.io/unicode-segmentation/unicode_segmentation/struct.GraphemeCursor.html)
8778/// to step back or forward one "grapheme", in logical text order.
88- /// Optionally, the direction may
89- /// be reversed for right-to-left lines [`TextDisplay::line_is_rtl`], but note
90- /// that the result may be confusing since not all text on the line follows the
91- /// line's base direction and adjacent lines may have different directions.
92- ///
93- /// Navigating glyphs left or right in display-order is not currently supported.
79+ /// The direction of navigation may be reversed for [right-to-left text](Self::text_is_rtl)
80+ /// (i.e. reversed logical-order navigation).
9481///
9582/// To navigate "up" and "down" lines, use [`TextDisplay::text_glyph_pos`] to
9683/// get the position of the cursor, [`TextDisplay::find_line`] to get the line
@@ -123,10 +110,10 @@ pub struct TextDisplay {
123110fn size_of_elts ( ) {
124111 use std:: mem:: size_of;
125112 assert_eq ! ( size_of:: <TinyVec <[ u8 ; 0 ] >>( ) , 24 ) ;
126- assert_eq ! ( size_of:: <shaper:: GlyphRun >( ) , 112 ) ;
113+ assert_eq ! ( size_of:: <shaper:: GlyphRun >( ) , 120 ) ;
127114 assert_eq ! ( size_of:: <RunPart >( ) , 24 ) ;
128115 assert_eq ! ( size_of:: <Line >( ) , 24 ) ;
129- assert_eq ! ( size_of:: <TextDisplay >( ) , 200 ) ;
116+ assert_eq ! ( size_of:: <TextDisplay >( ) , 208 ) ;
130117}
131118
132119impl Default for TextDisplay {
@@ -208,26 +195,18 @@ impl TextDisplay {
208195 first
209196 }
210197
211- /// Get the base directionality of the text
198+ /// Get the base directionality of the first paragraph
212199 ///
213- /// [Requires status][Self#status-of-preparation]: none.
214- pub fn text_is_rtl ( & self , text : & str , direction : Direction ) -> bool {
215- let ( is_auto, mut is_rtl) = match direction {
216- Direction :: Ltr => ( false , false ) ,
217- Direction :: Rtl => ( false , true ) ,
218- Direction :: Auto => ( true , false ) ,
219- Direction :: AutoRtl => ( true , true ) ,
220- } ;
221-
222- if is_auto {
223- match unicode_bidi:: get_base_direction ( text) {
224- unicode_bidi:: Direction :: Ltr => is_rtl = false ,
225- unicode_bidi:: Direction :: Rtl => is_rtl = true ,
226- unicode_bidi:: Direction :: Mixed => ( ) ,
227- }
228- }
229-
230- is_rtl
200+ /// [Requires status][Self#status-of-preparation]: run-breaking is complete.
201+ ///
202+ /// This returns the direction inferred from the `text` and [`Direction`]
203+ /// used during run-breaking. See also [`Direction::text_is_rtl`].
204+ #[ inline]
205+ pub fn text_is_rtl ( & self ) -> bool {
206+ self . runs
207+ . first ( )
208+ . map ( |r| r. base_level . is_rtl ( ) )
209+ . unwrap_or_default ( )
231210 }
232211
233212 /// Get the directionality of the current line
@@ -236,16 +215,16 @@ impl TextDisplay {
236215 ///
237216 /// Returns:
238217 ///
239- /// - `None` if text is empty
218+ /// - `None` if the line is not found
240219 /// - `Some(line_is_right_to_left)` otherwise
241220 ///
242221 /// Note: indeterminate lines (e.g. empty lines) have their direction
243- /// determined from the passed environment, by default left-to-right .
222+ /// determined from the passed [`Direction`] .
244223 pub fn line_is_rtl ( & self , line : usize ) -> Option < bool > {
245224 if let Some ( line) = self . lines . get ( line) {
246225 let first_run = line. run_range . start ( ) ;
247226 let glyph_run = to_usize ( self . wrapped_runs [ first_run] . glyph_run ) ;
248- Some ( self . runs [ glyph_run] . level . is_rtl ( ) )
227+ Some ( self . runs [ glyph_run] . base_level . is_rtl ( ) )
249228 } else {
250229 None
251230 }
0 commit comments