/// <summary> /// Builds a highlight geometry object for a given character range. /// </summary> /// <param name="origin">The origin of the highlight region.</param> /// <param name="startIndex">The start index of initial character the bounds should be obtained for.</param> /// <param name="count">The number of characters the bounds should be obtained for.</param> /// <returns>Geometry that surrounds the specified character range.</returns> public Geometry BuildHighlightGeometry(Point origin, int startIndex, int count) { ValidateRange(startIndex, count); PathGeometry accumulatedBounds = null; using (LineEnumerator enumerator = GetEnumerator()) { Point lineOrigin = origin; while (enumerator.MoveNext()) { using (TextLine currentLine = enumerator.Current) { int x0 = Math.Max(enumerator.Position, startIndex); int x1 = Math.Min(enumerator.Position + enumerator.Length, startIndex + count); // check if this line is intersects with the specified character range if (x0 < x1) { IList<TextBounds> highlightBounds = currentLine.GetTextBounds( x0, x1 - x0 ); if (highlightBounds != null) { foreach (TextBounds bound in highlightBounds) { Rect rect = bound.Rectangle; if (FlowDirection == FlowDirection.RightToLeft) { // Convert logical units (which extend leftward from the right edge // of the paragraph) to physical units. // // Note that since rect is in logical units, rect.Right corresponds to // the visual *left* edge of the rectangle in the RTL case. Specifically, // is the distance leftward from the right edge of the formatting rectangle // whose width is the paragraph width passed to FormatLine. // rect.X = enumerator.CurrentParagraphWidth - rect.Right; } rect.X += lineOrigin.X; rect.Y += lineOrigin.Y; RectangleGeometry rectangleGeometry = new RectangleGeometry(rect); if (accumulatedBounds == null) accumulatedBounds = rectangleGeometry.GetAsPathGeometry(); else accumulatedBounds = Geometry.Combine(accumulatedBounds, rectangleGeometry, GeometryCombineMode.Union, null); } } } AdvanceLineOrigin(ref lineOrigin, currentLine); } } } if (accumulatedBounds == null || accumulatedBounds.IsEmpty()) return null; return accumulatedBounds; }