// 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;
 }