@@ -43,6 +43,7 @@ type TestLayoutCursor = {
4343
4444type TestPreparedTextWithSegments = {
4545 segments : string [ ]
46+ segLevels ?: Int8Array | null
4647}
4748
4849type TestLayoutLine = {
@@ -213,6 +214,20 @@ function terminalCursor(prepared: TestPreparedTextWithSegments): TestLayoutCurso
213214 return { segmentIndex : prepared . segments . length , graphemeIndex : 0 }
214215}
215216
217+ function getNonSpaceSegmentLevels (
218+ prepared : TestPreparedTextWithSegments ,
219+ ) : Array < { level : number , text : string } > {
220+ if ( prepared . segLevels === null || prepared . segLevels === undefined ) return [ ]
221+
222+ const levels : Array < { level : number , text : string } > = [ ]
223+ for ( let i = 0 ; i < prepared . segments . length ; i ++ ) {
224+ const text = prepared . segments [ i ] !
225+ if ( text . trim ( ) . length === 0 ) continue
226+ levels . push ( { level : prepared . segLevels [ i ] ! , text } )
227+ }
228+ return levels
229+ }
230+
216231class TestCanvasRenderingContext2D {
217232 font = ''
218233
@@ -543,6 +558,30 @@ describe('prepare invariants', () => {
543558 const latin = prepare ( 'hello world' , FONT )
544559 expect ( layout ( latin , 200 , LINE_HEIGHT ) ) . toEqual ( { lineCount : 1 , height : LINE_HEIGHT } )
545560 } )
561+
562+ test ( 'pure LTR text skips rich bidi metadata' , ( ) => {
563+ expect ( prepareWithSegments ( 'hello world' , FONT ) . segLevels ) . toBeNull ( )
564+ } )
565+
566+ test ( 'rich bidi metadata uses the first strong character for paragraph direction' , ( ) => {
567+ const ltrFirst = prepareWithSegments ( 'one اثنان three' , FONT )
568+ expect ( ltrFirst . segLevels ) . not . toBeNull ( )
569+ expect ( ltrFirst . segLevels ) . toHaveLength ( ltrFirst . segments . length )
570+ expect ( getNonSpaceSegmentLevels ( ltrFirst ) ) . toEqual ( [
571+ { text : 'one' , level : 0 } ,
572+ { text : 'اثنان' , level : 1 } ,
573+ { text : 'three' , level : 0 } ,
574+ ] )
575+
576+ const rtlFirst = prepareWithSegments ( '123 واحد three' , FONT )
577+ expect ( rtlFirst . segLevels ) . not . toBeNull ( )
578+ expect ( rtlFirst . segLevels ) . toHaveLength ( rtlFirst . segments . length )
579+ expect ( getNonSpaceSegmentLevels ( rtlFirst ) ) . toEqual ( [
580+ { text : '123' , level : 2 } ,
581+ { text : 'واحد' , level : 1 } ,
582+ { text : 'three' , level : 2 } ,
583+ ] )
584+ } )
546585} )
547586
548587describe ( 'inline-flow invariants' , ( ) => {
0 commit comments