@@ -4,6 +4,7 @@ import type {Style} from './style.ts';
44import type { Run } from './layout-text.ts' ;
55import type {
66 InlineLevel ,
7+ BlockLevel ,
78 Break ,
89 Inline ,
910 BlockContainer ,
@@ -106,21 +107,31 @@ export abstract class RenderItem {
106107
107108 log . text ( '\n' ) ;
108109
109- if (
110- this . isBlockContainerOfInlines ( ) ||
111- this . isBlockContainerOfBlocks ( ) ||
112- this . isInline ( )
113- ) {
114- const children = this . isBlockContainerOfInlines ( ) ? [ this . root ] : this . children ;
110+ if ( this . isBlockContainerOfBlocks ( ) ) {
115111 log . pushIndent ( ) ;
116-
117- for ( let i = 0 ; i < children . length ; i ++ ) {
118- children [ i ] . log ( options , log ) ;
112+ for ( let i = 0 ; i < this . children . length ; i ++ ) {
113+ this . children [ i ] . log ( options , log ) ;
119114 }
120-
121115 log . popIndent ( ) ;
122116 }
123117
118+ if ( this . isBlockContainerOfInlines ( ) ) {
119+ const parents : Inline [ ] = [ ] ;
120+ for ( let i = 0 ; i < this . tree . length ; i ++ ) {
121+ const child = this . tree [ i ] ;
122+ log . pushIndent ( ) ;
123+ if ( child . isInline ( ) ) {
124+ parents . push ( child ) ;
125+ }
126+ child . log ( options , log ) ;
127+ if ( ! child . isInline ( ) ) log . popIndent ( ) ;
128+ while ( parents . at ( - 1 ) ?. lastDescendant === i ) {
129+ log . popIndent ( ) ;
130+ parents . pop ( ) ;
131+ }
132+ }
133+ }
134+
124135 if ( flush ) log . flush ( ) ;
125136 }
126137
@@ -761,11 +772,59 @@ export class BoxArea {
761772 }
762773}
763774
775+ export class InlineStack {
776+ tree : InlineLevel [ ] ;
777+ parents : Box [ ] ;
778+ parentsStart : number ;
779+ index : number ;
780+ inlineStack : true ;
781+
782+ constructor ( ifc : BlockContainerOfInlines , parents : Box [ ] , index = 0 ) {
783+ this . tree = ifc . tree ;
784+ this . parents = parents ;
785+ this . parentsStart = parents . length ;
786+ this . index = index ;
787+ this . inlineStack = true ;
788+ }
789+
790+ getValue ( ) {
791+ if ( this . parentsStart < this . parents . length ) {
792+ const parent = this . parents [ this . parents . length - 1 ] as Inline ;
793+ if ( parent . lastDescendant === this . index - 1 ) return { sentinel : true as const } ;
794+ }
795+
796+ return this . index < this . tree . length ? this . tree [ this . index ] : undefined ;
797+ }
798+
799+ lastChild ( ) {
800+ const value = this . index < this . tree . length ? this . tree [ this . index ] : undefined ;
801+ if ( value ?. isInline ( ) ) this . index = value . lastDescendant ;
802+ }
803+
804+ next ( ) {
805+ const item = this . getValue ( ) ;
806+ if ( item && ! ( 'sentinel' in item ) ) this . index ++ ;
807+ return item ;
808+ }
809+ }
810+
764811const EmptyContainingBlock = new BoxArea ( null ! ) ;
765812
813+ export function nextStack ( stack : ( BlockLevel | InlineStack | { sentinel : true } ) [ ] ) {
814+ const value = stack [ stack . length - 1 ] ;
815+ if ( 'inlineStack' in value ) {
816+ const ret = value . next ( ) ;
817+ if ( ret === undefined ) stack . pop ( ) ;
818+ return ret ;
819+ } else {
820+ stack . pop ( ) ;
821+ return value ;
822+ }
823+ }
824+
766825export function prelayout ( root : BlockContainer ) {
767- const stack : ( InlineLevel | { sentinel : true } ) [ ] = [ root ] ;
768- const parents : Box [ ] = [ ] ;
826+ const stack : ( BlockLevel | InlineStack | { sentinel : true } ) [ ] = [ root ] ;
827+ const parents : ( FormattingBox | Inline ) [ ] = [ ] ;
769828 const ifcs : BlockContainerOfInlines [ ] = [ ] ;
770829 const pstack = [ root . containingBlock ] ;
771830 const bstack = [ root . containingBlock ] ;
@@ -775,10 +834,13 @@ export function prelayout(root: BlockContainer) {
775834 } ;
776835
777836 while ( stack . length ) {
778- const box = stack . pop ( ) ! ;
837+ const item = nextStack ( stack ) ;
838+
839+ if ( item === undefined ) continue ; // end of inlines
779840
780- if ( 'sentinel' in box ) {
841+ if ( 'sentinel' in item ) {
781842 const box = parents . pop ( ) ! ;
843+
782844 if ( box . isBlockContainerOfInlines ( ) ) ifcs . pop ( ) ;
783845
784846 if ( box . isBlockContainer ( ) ) {
@@ -791,61 +853,66 @@ export function prelayout(root: BlockContainer) {
791853 const parent = parents . at ( - 1 ) ;
792854 if ( parent ) box . propagate ( parent ) ;
793855 box . prelayoutPostorder ( ctx ) ;
794- } else if ( box . isBox ( ) ) {
795- parents . push ( box ) ;
856+ } else if ( item . isBox ( ) ) {
857+ const box = item ;
796858 if ( box . isBlockContainerOfInlines ( ) ) ifcs . push ( box ) ;
797859
798860 ctx . lastPositionedArea = pstack . at ( - 1 ) ! ;
799861 ctx . lastBlockContainerArea = bstack . at ( - 1 ) ! ;
800862
801- stack . push ( { sentinel : true } ) ;
802863 box . prelayoutPreorder ( ctx ) ;
803864 if ( box . isBlockContainer ( ) ) {
804865 bstack . push ( box . getContentArea ( ) ) ;
805866 if ( box . style . position !== 'static' ) pstack . push ( box . getPaddingArea ( ) ) ;
806867 }
807868
808- if ( box . isBlockContainerOfBlocks ( ) || box . isInline ( ) ) {
869+ if ( box . isBlockContainerOfBlocks ( ) ) {
870+ parents . push ( box ) ;
871+ stack . push ( { sentinel : true } ) ;
809872 for ( let i = box . children . length - 1 ; i >= 0 ; i -- ) {
810873 stack . push ( box . children [ i ] ) ;
811874 }
812875 } else if ( box . isBlockContainerOfInlines ( ) ) {
813- stack . push ( box . root ) ;
876+ parents . push ( box ) ;
877+ stack . push ( { sentinel : true } , new InlineStack ( box , parents ) ) ;
878+ } else if ( box . isInline ( ) ) {
879+ parents . push ( box ) ;
880+ } else {
881+ item . propagate ( parents . at ( - 1 ) ! ) ;
814882 }
815- } else if ( box . isRun ( ) ) {
816- box . propagate ( parents . at ( - 1 ) ! , ifcs . at ( - 1 ) ! . text ) ;
883+ } else if ( item . isRun ( ) ) {
884+ item . propagate ( parents . at ( - 1 ) ! , ifcs . at ( - 1 ) ! . text ) ;
817885 } else {
818- box . propagate ( parents . at ( - 1 ) ! ) ;
886+ item . propagate ( parents . at ( - 1 ) ! ) ;
819887 }
820888 }
821889}
822890
823891export function postlayout ( root : BlockContainer ) {
824- const stack : ( BlockContainer | Inline | { sentinel : true } ) [ ] = [ root ] ;
892+ const stack : ( BlockLevel | InlineStack | { sentinel : true } ) [ ] = [ root ] ;
825893 const parents : Box [ ] = [ ] ;
826894
827895 while ( stack . length ) {
828- const box = stack . pop ( ) ! ;
896+ const item = nextStack ( stack ) ;
897+ if ( item === undefined ) continue ; // end inlines
829898
830- if ( 'sentinel' in box ) {
899+ if ( 'sentinel' in item ) {
831900 const parent = parents . pop ( ) ! ;
832901 parent . postlayoutPostorder ( ) ;
833902 } else {
834- box . postlayoutPreorder ( ) ;
835- stack . push ( { sentinel : true } ) ;
836- parents . push ( box ) ;
837- if ( box . isBlockContainerOfBlocks ( ) || box . isInline ( ) ) {
838- for ( let i = box . children . length - 1 ; i >= 0 ; i -- ) {
839- const child = box . children [ i ] ;
840- if ( child . isBlockContainer ( ) || child . isInline ( ) ) {
841- stack . push ( child ) ;
842- } else {
843- child . postlayoutPreorder ( )
844- child . postlayoutPostorder ( ) ;
845- }
903+ item . postlayoutPreorder ( ) ;
904+ if ( ! item . isBox ( ) ) item . postlayoutPostorder ( ) ;
905+ if ( item . isBlockContainerOfBlocks ( ) ) {
906+ parents . push ( item ) ;
907+ stack . push ( { sentinel : true } ) ;
908+ for ( let i = item . children . length - 1 ; i >= 0 ; i -- ) {
909+ stack . push ( item . children [ i ] ) ;
846910 }
847- } else if ( box . isBlockContainerOfInlines ( ) ) {
848- stack . push ( box . root ) ;
911+ } else if ( item . isBlockContainerOfInlines ( ) ) {
912+ parents . push ( item ) ;
913+ stack . push ( { sentinel : true } , new InlineStack ( item , parents ) ) ;
914+ } else if ( item . isInline ( ) ) {
915+ parents . push ( item ) ;
849916 }
850917 }
851918 }
0 commit comments