@@ -510,8 +510,143 @@ export class DomObjectRenderingEngine extends RenderingEngine<DomObject> {
510510 renderingUnits . push ( this . _createUnit ( cache , node , rendered ) ) ;
511511 }
512512 }
513+ if ( cache . optimizeModifiersRendering ) {
514+ this . _optimizeModifiersRendering ( cache , renderingUnits ) ;
515+ }
516+
513517 return renderingUnits ;
514518 }
519+ /**
520+ * The modifiers will be sorted to be rendererd with the minimum of tag and keep the hight
521+ * modifier level.
522+ *
523+ * Eg: change this (without space of course):
524+ * <b>
525+ * <i>
526+ * _
527+ * <a href="#">__</a>
528+ * </i>
529+ * <a href="#">_</a>
530+ * <i>
531+ * <a href="#">__</a>
532+ * </i>
533+ * </b>
534+ * Into this to keep the link:
535+ * <b>
536+ * <i>_</i>
537+ * <a href="#">
538+ * <i>__</i>
539+ * _
540+ * <i>__</i>
541+ * </a>
542+ * </b>
543+ *
544+ * @param cache
545+ * @param renderingUnits
546+ */
547+ private _optimizeModifiersRendering (
548+ cache : RenderingEngineCache < DomObject > ,
549+ renderingUnits : RenderingBatchUnit [ ] ,
550+ ) : void {
551+ // Clone to use pop after and create the intervales.
552+ const unitToModifiers = new Map < RenderingBatchUnit , Modifier [ ] > ( ) ;
553+ for ( const renderingUnit of renderingUnits ) {
554+ if ( renderingUnit ) {
555+ unitToModifiers . set ( renderingUnit , [ ...renderingUnit [ 1 ] ] ) ;
556+ }
557+ }
558+
559+ // Group by same modifier, then order the modifiers and take care of the level.
560+ // Create modifiers interval (Modifier, level, index begin, index end).
561+ const intervals : [ Modifier [ ] , number , number , number ] [ ] = [ ] ;
562+ for ( let i = 0 ; i < renderingUnits . length ; i ++ ) {
563+ const renderingUnit = renderingUnits [ i ] ;
564+ const unitModifiers = unitToModifiers . get ( renderingUnit ) ;
565+ if ( unitModifiers ) {
566+ while ( unitModifiers . length ) {
567+ // Take the first modifier and group.
568+ const modifierToSort = unitModifiers . pop ( ) ;
569+ const level = modifierToSort . level ;
570+ if ( ! level ) {
571+ continue ;
572+ }
573+ const modifiers : Modifier [ ] = [ modifierToSort ] ;
574+ const groupIndexes : number [ ] = [ 0 ] ;
575+
576+ let next : RenderingBatchUnit ;
577+ let nextIndex = i + 1 ;
578+ while ( ( next = renderingUnits [ nextIndex ] ) && unitToModifiers . get ( next ) ) {
579+ const modifierIndex = unitToModifiers
580+ . get ( next )
581+ . findIndex ( modifier =>
582+ this . _modifierIsSameAs ( cache , modifierToSort , modifier ) ,
583+ ) ;
584+ if ( modifierIndex === - 1 ) {
585+ break ;
586+ } else {
587+ const modifier = unitToModifiers . get ( next ) [ modifierIndex ] ;
588+ groupIndexes . push ( next [ 1 ] . indexOf ( modifier ) ) ;
589+ modifiers . push ( modifier ) ;
590+ unitToModifiers . get ( next ) . splice ( modifierIndex , 1 ) ;
591+ nextIndex ++ ;
592+ }
593+ }
594+ intervals . push ( [ modifiers , level , i , nextIndex - 1 ] ) ;
595+ }
596+ }
597+ }
598+
599+ // Split interval if break an interval with greatest level.
600+ for ( let i = 0 ; i < intervals . length ; i ++ ) {
601+ const self = intervals [ i ] ;
602+ // Use the same length because the newest are already splitted for this loop.
603+ const len = intervals . length ;
604+ for ( let u = 0 ; u < len ; u ++ ) {
605+ if ( u === i ) {
606+ continue ;
607+ }
608+ const other = intervals [ u ] ;
609+ if (
610+ self [ 1 ] > other [ 1 ] ||
611+ ( self [ 1 ] === other [ 1 ] && self [ 3 ] - self [ 2 ] > other [ 3 ] - other [ 2 ] )
612+ ) {
613+ // If greatest level or greatest number of VNodes split other modifiers.
614+ if ( self [ 2 ] > other [ 2 ] && self [ 2 ] <= other [ 3 ] && self [ 3 ] > other [ 3 ] ) {
615+ intervals . push ( [
616+ other [ 0 ] . splice ( 0 , other [ 3 ] - self [ 2 ] + 1 ) ,
617+ other [ 1 ] ,
618+ self [ 2 ] ,
619+ other [ 3 ] ,
620+ ] ) ;
621+ other [ 3 ] = self [ 2 ] - 1 ;
622+ } else if ( self [ 3 ] >= other [ 2 ] && self [ 3 ] < other [ 3 ] && self [ 2 ] < other [ 2 ] ) {
623+ intervals . push ( [
624+ other [ 0 ] . splice ( 0 , self [ 3 ] - other [ 2 ] + 1 ) ,
625+ other [ 1 ] ,
626+ other [ 2 ] ,
627+ self [ 3 ] ,
628+ ] ) ;
629+ other [ 2 ] = self [ 3 ] + 1 ;
630+ }
631+ }
632+ }
633+ }
634+
635+ // Sort by largest interval.
636+ intervals . sort ( ( a , b ) => a [ 3 ] - a [ 2 ] - b [ 3 ] + b [ 2 ] ) ;
637+
638+ // Sort the modifiers in unit from the interval order.
639+ for ( const interval of intervals ) {
640+ const nodes = [ ] ;
641+ for ( let i = interval [ 2 ] ; i <= interval [ 3 ] ; i ++ ) {
642+ const modifer = interval [ 0 ] [ i - interval [ 2 ] ] ;
643+ const modifiers = renderingUnits [ i ] [ 1 ] ;
644+ modifiers . splice ( modifiers . indexOf ( modifer ) , 1 ) ;
645+ modifiers . unshift ( modifer ) ;
646+ nodes . push ( renderingUnits [ i ] [ 0 ] ) ;
647+ }
648+ }
649+ }
515650 private _createUnit (
516651 cache : RenderingEngineCache < DomObject > ,
517652 node : VNode ,
0 commit comments