@@ -183,6 +183,11 @@ public LineInfo(LineInfo info) {
183183 }
184184 }
185185 }
186+
187+ private record LineDrawInfo (int index , TextLayout layout , String text , int offset , int height ) {
188+
189+ }
190+
186191 static int cap (TextLayout layout , int offset ) {
187192 if (layout == null ) return offset ;
188193 return Math .min (layout .getText ().length () -1 , Math .max (0 , offset ));
@@ -452,32 +457,63 @@ void drawBullet(Bullet bullet, GC gc, int paintX, int paintY, int index, int lin
452457 layout .draw (gc , x , paintY );
453458 layout .dispose ();
454459}
455- int drawLine (int lineIndex , int paintX , int paintY , GC gc , Color widgetBackground , Color widgetForeground ) {
460+
461+ /**
462+ * Caches draw-related info that may be expensive to calculate twice when
463+ * drawing first background and then foreground.
464+ */
465+ private LineDrawInfo makeLineDrawInfo (int lineIndex ) {
456466 TextLayout layout = getTextLayout (lineIndex );
457- String line = content .getLine (lineIndex );
458- int lineOffset = content .getOffsetAtLine (lineIndex );
459- int lineLength = line .length ();
467+ String text = content .getLine (lineIndex );
468+ int offset = content .getOffsetAtLine (lineIndex );
469+ int height = layout .getBounds ().height ;
470+ return new LineDrawInfo (lineIndex , layout , text , offset , height );
471+ }
472+
473+ int drawLines (int startLine , int endLine , int begX , int begY , int endY , GC gc , Color widgetBackground , Color widgetForeground ) {
474+ final boolean drawBackBeforeFore = false ;
475+
476+ if (drawBackBeforeFore ) {
477+ return 0 ;
478+ }
479+
480+ int y = begY ;
481+ for (int iLine = startLine ; y < endY && iLine < endLine ; iLine ++) {
482+ LineDrawInfo lineInfo = makeLineDrawInfo (iLine );
483+ drawLineBackground (lineInfo , y , gc , widgetBackground );
484+ drawLineForeground (lineInfo , begX , y , gc , widgetForeground );
485+ disposeTextLayout (lineInfo .layout );
486+ y += lineInfo .height ;
487+ }
488+ return y - begY ;
489+ }
490+
491+ private void drawLineBackground (LineDrawInfo lineInfo , int paintY , GC gc , Color widgetBackground ) {
460492 Rectangle client = styledText .getClientArea ();
461- Color lineBackground = getLineBackground (lineIndex , null );
462- StyledTextEvent event = styledText .getLineBackgroundData (lineOffset , line );
493+ Color lineBackground = getLineBackground (lineInfo . index , null );
494+ StyledTextEvent event = styledText .getLineBackgroundData (lineInfo . offset , lineInfo . text );
463495 if (event != null && event .lineBackground != null ) lineBackground = event .lineBackground ;
464- int height = layout .getBounds (). height ;
465- int verticalIndent = layout . getVerticalIndent ();
496+ int verticalIndent = lineInfo . layout .getVerticalIndent () ;
497+
466498 if (lineBackground != null ) {
467499 if (verticalIndent > 0 ) {
468500 gc .setBackground (widgetBackground );
469501 gc .fillRectangle (client .x , paintY , client .width , verticalIndent );
470502 }
471503 gc .setBackground (lineBackground );
472- gc .fillRectangle (client .x , paintY + verticalIndent , client .width , height - verticalIndent );
504+ gc .fillRectangle (client .x , paintY + verticalIndent , client .width , lineInfo . height - verticalIndent );
473505 } else {
474506 gc .setBackground (widgetBackground );
475- styledText .drawBackground (gc , client .x , paintY , client .width , height );
507+ styledText .drawBackground (gc , client .x , paintY , client .width , lineInfo . height );
476508 }
509+ }
510+
511+ private void drawLineForeground (LineDrawInfo lineInfo , int paintX , int paintY , GC gc , Color widgetForeground ) {
512+ int lineLength = lineInfo .text .length ();
477513 gc .setForeground (widgetForeground );
478- Point [] selection = intersectingRelativeNonEmptySelections (lineOffset , lineOffset + lineLength );
514+ Point [] selection = intersectingRelativeNonEmptySelections (lineInfo . offset , lineInfo . offset + lineLength );
479515 if (styledText .getBlockSelection () || selection .length == 0 ) {
480- layout .draw (gc , paintX , paintY );
516+ lineInfo . layout .draw (gc , paintX , paintY );
481517 } else {
482518 Color selectionFg = styledText .getSelectionForeground ();
483519 Color selectionBg = styledText .getSelectionBackground ();
@@ -490,7 +526,7 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun
490526 flags |= SWT .LAST_LINE_SELECTION ;
491527 }
492528 // TODO calling draw multiple times here prints line multiple times, overriding some colors
493- layout .draw (gc , paintX , paintY , start , end - 1 , selectionFg , selectionBg , flags );
529+ lineInfo . layout .draw (gc , paintX , paintY , start , end - 1 , selectionFg , selectionBg , flags );
494530 }
495531 }
496532
@@ -499,48 +535,47 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun
499535 int bulletIndex = -1 ;
500536 if (bullets != null ) {
501537 if (bulletsIndices != null ) {
502- int index = lineIndex - topIndex ;
538+ int index = lineInfo . index - topIndex ;
503539 if (0 <= index && index < CACHE_SIZE ) {
504540 bullet = bullets [index ];
505541 bulletIndex = bulletsIndices [index ];
506542 }
507543 } else {
508544 for (Bullet b : bullets ) {
509545 bullet = b ;
510- bulletIndex = bullet .indexOf (lineIndex );
546+ bulletIndex = bullet .indexOf (lineInfo . index );
511547 if (bulletIndex != -1 ) break ;
512548 }
513549 }
514550 }
515551 if (bulletIndex != -1 && bullet != null ) {
516- FontMetrics metrics = layout .getLineMetrics (0 );
552+ FontMetrics metrics = lineInfo . layout .getLineMetrics (0 );
517553 int lineAscent = metrics .getAscent () + metrics .getLeading ();
518554 if (bullet .type == ST .BULLET_CUSTOM ) {
519- bullet .style .start = lineOffset ;
555+ bullet .style .start = lineInfo . offset ;
520556 styledText .paintObject (gc , paintX , paintY , lineAscent , metrics .getDescent (), bullet .style , bullet , bulletIndex );
521557 } else {
522558 drawBullet (bullet , gc , paintX , paintY , bulletIndex , lineAscent , metrics .getDescent ());
523559 }
524560 }
525- TextStyle [] styles = layout .getStyles ();
561+ TextStyle [] styles = lineInfo . layout .getStyles ();
526562 int [] ranges = null ;
527563 for (int i = 0 ; i < styles .length ; i ++) {
528564 if (styles [i ].metrics != null ) {
529- if (ranges == null ) ranges = layout .getRanges ();
565+ if (ranges == null ) ranges = lineInfo . layout .getRanges ();
530566 int start = ranges [i << 1 ];
531567 int length = ranges [(i << 1 ) + 1 ] - start + 1 ;
532- Point point = layout .getLocation (start , false );
533- FontMetrics metrics = layout .getLineMetrics (layout .getLineIndex (start ));
568+ Point point = lineInfo . layout .getLocation (start , false );
569+ FontMetrics metrics = lineInfo . layout .getLineMetrics (lineInfo . layout .getLineIndex (start ));
534570 StyleRange style = (StyleRange )((StyleRange )styles [i ]).clone ();
535- style .start = start + lineOffset ;
571+ style .start = start + lineInfo . offset ;
536572 style .length = length ;
537573 int lineAscent = metrics .getAscent () + metrics .getLeading ();
538574 styledText .paintObject (gc , point .x + paintX , point .y + paintY , lineAscent , metrics .getDescent (), style , null , 0 );
539575 }
540576 }
541- disposeTextLayout (layout );
542- return height ;
543577}
578+
544579private Point [] intersectingRelativeNonEmptySelections (int fromOffset , int toOffset ) {
545580 int [] selectionRanges = styledText .getSelectionRanges ();
546581 int lineLength = toOffset - fromOffset ;
0 commit comments