// this function gets the bounding rectangle for a range that does not wrap lines. private static Rect CalculateOneLineRangeRectangle(ITextRange lineRange, Rect clientRect) { int start = lineRange.Start; int end = lineRange.End; if (start < end) { // make a working copy of the range. shrink it by one character since // ITextRange.GetPoint returns the coordinates of the character *after* the end of the // range rather than the one immediately *before* the end of the range. ITextRange range = lineRange.GetDuplicate(); range.MoveEnd(TomUnit.tomCharacter, -1); end--; // The ITextRange::SetRange method sets this range’s Start = min(cp1, cp2) and End = max(cp1, cp2). // If the range is a nondegenerate selection, cp2 is the active end; if it’s a degenerate selection, // the ambiguous cp is displayed at the start of the line (rather than at the end of the previous line). // Set the end to the start and the start to the end to create an ambiguous cp. This was added to // resolve Windows OS Bug 1030882. range.SetRange(range.End, range.Start); Rect rect = new Rect(clientRect.Location, clientRect.Size); bool trimmed = TrimRectangleByRangeCorners(range, ref rect); if (!trimmed) { while (!trimmed && start < end) { // shrink the range range.MoveStart(TomUnit.tomCharacter, 1); // If the character just moved over was a '\r' the start will be out of sink with range.Start start++; if (start < end) { range.MoveEnd(TomUnit.tomCharacter, -1); // If the character just moved over was a '\r' the end will be out of sink with range.End end--; } //Debug.Assert(start == range.Start); //Debug.Assert(end == range.End); trimmed = TrimRectangleByRangeCorners(range, ref rect); } if (trimmed) { rect.X = clientRect.X; rect.Width = clientRect.Width; } } if (!trimmed) { rect = Rect.Empty; } return rect; } else { // degenerate range. return empty rectangle. // it might be nice to return a zero-width rectangle with the appropriate height and location. // however, when the degenerate range is at a line wrapping point then it is ambiguous as to // whether the rectangle should be at the end of one line or the beginning of the next. clients // can always extend a degenerate range by one character in either direction before getting a bounding // rectangle if they want. return Rect.Empty; } }
private static ITextRange LastUnit(ITextRange range) { // get a degenerate subrange positioned at the end of the range ITextRange subrange = range.GetDuplicate(); subrange.Collapse(TomStartEnd.tomEnd); return subrange; }