Skip to content

Commit 5279a77

Browse files
committed
#66: Fix BackgroundGeometryBuilder in word-wrap mode.
1 parent 5d685bc commit 5279a77

1 file changed

Lines changed: 42 additions & 18 deletions

File tree

ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,9 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
222222
double y = visualLine.GetTextLineVisualYPosition(line, VisualYPosition.LineTop);
223223
int visualStartCol = visualLine.GetTextLineVisualStartColumn(line);
224224
int visualEndCol = visualStartCol + line.Length;
225-
if (line != lastTextLine)
225+
if (line == lastTextLine)
226+
visualEndCol -= 1; // 1 position for the TextEndOfParagraph
227+
else
226228
visualEndCol -= line.TrailingWhitespaceLength;
227229

228230
if (segmentEndVC < visualStartCol)
@@ -232,6 +234,7 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
232234
int segmentStartVCInLine = Math.Max(segmentStartVC, visualStartCol);
233235
int segmentEndVCInLine = Math.Min(segmentEndVC, visualEndCol);
234236
y -= scrollOffset.Y;
237+
Rect lastRect = Rect.Empty;
235238
if (segmentStartVCInLine == segmentEndVCInLine) {
236239
// GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit
237240
// We need to return a rectangle to ensure empty lines are still visible
@@ -244,9 +247,8 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
244247
continue;
245248
if (segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine.TextLines[i - 1].TrailingWhitespaceLength == 0)
246249
continue;
247-
yield return new Rect(pos, y, textView.EmptyLineSelectionWidth, line.Height);
250+
lastRect = new Rect(pos, y, textView.EmptyLineSelectionWidth, line.Height);
248251
} else {
249-
Rect lastRect = Rect.Empty;
250252
if (segmentStartVCInLine <= visualEndCol) {
251253
foreach (TextBounds b in line.GetTextBounds(segmentStartVCInLine, segmentEndVCInLine - segmentStartVCInLine)) {
252254
double left = b.Rectangle.Left - scrollOffset.X;
@@ -257,23 +259,45 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
257259
lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height);
258260
}
259261
}
260-
if (segmentEndVC >= visualLine.VisualLengthWithEndOfLineMarker) {
261-
double left = (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker ? visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC) : line.WidthIncludingTrailingWhitespace) - scrollOffset.X;
262-
double right = ((segmentEndVC == int.MaxValue || line != lastTextLine) ? Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth) : visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC)) - scrollOffset.X;
263-
Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height);
264-
if (!lastRect.IsEmpty) {
265-
if (extendSelection.IntersectsWith(lastRect)) {
266-
lastRect.Union(extendSelection);
267-
yield return lastRect;
268-
} else {
269-
yield return lastRect;
270-
yield return extendSelection;
271-
}
272-
} else
262+
}
263+
// If the segment ends in virtual space, extend the last rectangle with the rectangle the portion of the selection
264+
// after the line end.
265+
// Also, when word-wrap is enabled and the segment continues into the next line, extend lastRect up to the end of the line.
266+
if (segmentEndVC > visualEndCol) {
267+
double left, right;
268+
if (segmentStartVC > visualLine.VisualLengthWithEndOfLineMarker) {
269+
// segmentStartVC is in virtual space
270+
left = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentStartVC);
271+
} else {
272+
// Otherwise, we already processed the rects from segmentStartVC up to visualEndCol,
273+
// so we only need to do the remainder starting at visualEndCol.
274+
// For word-wrapped lines, visualEndCol doesn't include the whitespace hidden by the wrap,
275+
// so we'll need to include it here.
276+
// For the last line, visualEndCol already includes the whitespace.
277+
left = (line == lastTextLine ? line.WidthIncludingTrailingWhitespace : line.Width);
278+
}
279+
if (line != lastTextLine || segmentEndVC == int.MaxValue) {
280+
// If word-wrap is enabled and the segment continues into the next line,
281+
// or if the extendToFullWidthAtLineEnd option is used (segmentEndVC == int.MaxValue),
282+
// we select the full width of the viewport.
283+
right = Math.Max(((IScrollInfo)textView).ExtentWidth, ((IScrollInfo)textView).ViewportWidth);
284+
} else {
285+
right = visualLine.GetTextLineVisualXPosition(lastTextLine, segmentEndVC);
286+
}
287+
Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height);
288+
if (!lastRect.IsEmpty) {
289+
if (extendSelection.IntersectsWith(lastRect)) {
290+
lastRect.Union(extendSelection);
291+
yield return lastRect;
292+
} else {
293+
// If the end of the line is in an RTL segment, keep lastRect and extendSelection separate.
294+
yield return lastRect;
273295
yield return extendSelection;
296+
}
274297
} else
275-
yield return lastRect;
276-
}
298+
yield return extendSelection;
299+
} else
300+
yield return lastRect;
277301
}
278302
}
279303

0 commit comments

Comments
 (0)