@@ -10,6 +10,7 @@ use core_graphics::path::CGPath;
1010use core_text:: font:: { self , CTFont } ;
1111
1212use piet:: kurbo:: { Point , Size } ;
13+ use piet:: util;
1314use piet:: {
1415 Error , Font , FontBuilder , HitTestMetrics , HitTestPoint , HitTestTextPosition , LineMetric , Text ,
1516 TextLayout , TextLayoutBuilder ,
@@ -193,7 +194,7 @@ impl TextLayout for CoreGraphicsTextLayout {
193194 let utf8_range = self . line_range ( line_num) . unwrap ( ) ;
194195 let line_txt = self . line_text ( line_num) . unwrap ( ) ;
195196 let rel_offset = ( n - utf16_range. location ) as usize ;
196- utf8_range. 0 + utf8_offset_for_utf16_offset ( line_txt, rel_offset)
197+ utf8_range. 0 + util :: count_until_utf16 ( line_txt, rel_offset) . unwrap_or_else ( || line_txt . len ( ) )
197198 }
198199 // some other value; should never happen
199200 _ => panic ! ( "gross violation of api contract" ) ,
@@ -220,7 +221,7 @@ impl TextLayout for CoreGraphicsTextLayout {
220221 let text = self . line_text ( line_num) ?;
221222
222223 let offset_remainder = offset - self . line_offsets . get ( line_num) ?;
223- let off16: usize = text[ ..offset_remainder] . chars ( ) . map ( char :: len_utf16 ) . sum ( ) ;
224+ let off16: usize = util :: count_utf16 ( & text[ ..offset_remainder] ) ;
224225 let line_range = line. get_string_range ( ) ;
225226 let char_idx = line_range. location + off16 as isize ;
226227 let ( x_pos, _) = line. get_offset_for_string_index ( char_idx) ;
@@ -311,19 +312,6 @@ impl CoreGraphicsTextLayout {
311312 }
312313}
313314
314- fn utf8_offset_for_utf16_offset ( text : & str , utf16_offset : usize ) -> usize {
315- let mut off16 = 0 ;
316- let mut off8 = 0 ;
317- for c in text. chars ( ) {
318- if utf16_offset == off16 {
319- break ;
320- }
321- off16 += c. len_utf16 ( ) ;
322- off8 += c. len_utf8 ( ) ;
323- }
324- off8
325- }
326-
327315#[ cfg( test) ]
328316#[ allow( clippy:: float_cmp) ]
329317mod tests {
@@ -428,4 +416,18 @@ mod tests {
428416 // just the general idea that this is the second character
429417 assert ! ( p1. point. x > 5.0 && p1. point. x < 15.0 ) ;
430418 }
419+
420+ #[ test]
421+ fn hit_test_text_position_astral_plane ( ) {
422+ let text = "👾🤠\n 🤖🎃👾" ;
423+ let a_font = font:: new_from_name ( "Helvetica" , 16.0 ) . unwrap ( ) ;
424+ let layout = CoreGraphicsTextLayout :: new ( & CoreGraphicsFont ( a_font) , text, f64:: INFINITY ) ;
425+ let p0 = layout. hit_test_text_position ( 4 ) . unwrap ( ) ;
426+ let p1 = layout. hit_test_text_position ( 8 ) . unwrap ( ) ;
427+ let p2 = layout. hit_test_text_position ( 13 ) . unwrap ( ) ;
428+
429+ assert ! ( p1. point. x > p0. point. x) ;
430+ assert ! ( p1. point. y == p0. point. y) ;
431+ assert ! ( p2. point. y > p1. point. y) ;
432+ }
431433}
0 commit comments