From 694c4b025a709e60f2904bdcd6c5406fc616e4a9 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sat, 7 Jun 2025 03:06:01 -0600 Subject: [PATCH] [buffer] Expose more glyph flags Fixes https://github.com/harfbuzz/rustybuzz/issues/163 --- src/hb/buffer.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/hb/buffer.rs b/src/hb/buffer.rs index 2ac1b16f..419fb1f3 100644 --- a/src/hb/buffer.rs +++ b/src/hb/buffer.rs @@ -193,6 +193,49 @@ impl hb_glyph_info_t { self.mask & glyph_flag::UNSAFE_TO_BREAK != 0 } + /// Indicates that if input text is changed on one side of the beginning of the cluster + /// this glyph is part of, then the shaping results for the other side might change. + /// Note that the absence of this flag will NOT by itself mean that it IS safe to concat + /// text. Only two pieces of text both of which clear of this flag can be concatenated + /// safely. + /// + /// This can be used to optimize paragraph layout, by avoiding re-shaping of each line after + /// line-breaking, by limiting the reshaping to a small piece around the breaking position + /// only, even if the breaking position carries the unsafe-to-break flag or when hyphenation + /// or other text transformation happens at line-break position, in the following way: + /// 1. Iterate back from the line-break position until the first cluster start position + /// that is NOT unsafe-to-concat. + /// 2. Shape the segment from there till the end of line. + /// 3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its + /// start-of-text position; if it is, just splice it into place and the line is shaped; + /// If not, move on to a position further back that is clear of unsafe-to-concat and retry + /// from there, and repeat. + /// + /// At the start of next line a similar algorithm can be implemented. That is: + /// 1. Iterate forward from the line-break position until the first cluster start position that is + /// NOT unsafe-to-concat. + /// 2. Shape the segment from beginning of the line to that position. + /// 3. Check whether the resulting glyph-run also is clear of the unsafe-to-concat at its end-of-text + /// position; if it is, just splice it into place and the beginning is shaped; If not, move on to a + /// position further forward that is clear of unsafe-to-concat and retry up to there, and repeat. A + /// slight complication will arise in the implementation of the algorithm above, because while our + /// buffer API has a way to return flags for position corresponding to start-of-text, there is currently + /// no position corresponding to end-of-text. This limitation can be alleviated by shaping more text + /// than needed and looking for unsafe-to-concat flag within text clusters. The unsafe-to-break flag will + /// always imply this flag. To use this flag, you must enable the buffer flag [`BufferFlags::PRODUCE_UNSAFE_TO_CONCAT`] + /// during shaping, otherwise the buffer flag will not be reliably produced. + pub fn unsafe_to_concat(&self) -> bool { + self.mask & glyph_flag::UNSAFE_TO_CONCAT != 0 + } + + /// In scripts that use elongation (Arabic, Mongolian, Syriac, etc.), this flag signifies that it is + /// safe to insert a U+0640 TATWEEL character before this cluster for elongation. This flag does not + /// determine the script-specific elongation places, but only when it is safe to do the elongation + /// without interrupting text shaping. + pub fn safe_to_insert_tatweel(&self) -> bool { + self.mask & glyph_flag::SAFE_TO_INSERT_TATWEEL != 0 + } + #[inline] pub(crate) fn as_char(&self) -> char { char::try_from(self.glyph_id).unwrap()