// ------------------------------------------------------------------ // Returns ArrayList of rectangles (at msot one) for the given ContentElement // e if it spans all or part of the specified line // ----------------------------------------------------------------- private List<Rect> GetRectanglesInSingleLine( PTS.FSLINEDESCRIPTIONSINGLE lineDesc, ContentElement e, int start, int length) { // Calculate end of element relative to TextParagraph by adding length to start position int end = start + length; List<Rect> rectangles = new List<Rect>(); // If the element does not lie in the line at all, return empty list if (start >= lineDesc.dcpLim) { // Element starts after line ends return rectangles; } if (end <= lineDesc.dcpFirst) { // Element ends before line starts return rectangles; } // Establish start and end points of element span within the line so that // we can get rectangle between them int localStart = (start < lineDesc.dcpFirst) ? lineDesc.dcpFirst : start; int localEnd = (end < lineDesc.dcpLim) ? end : lineDesc.dcpLim; Debug.Assert(localEnd > localStart); // Create and format line Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(lineDesc.fClearOnLeft), PTS.ToBoolean(lineDesc.fClearOnRight), TextParagraph.TextRunCache); if(IsOptimalParagraph) { ctx.LineFormatLengthTarget = lineDesc.dcpLim - lineDesc.dcpFirst; } TextParagraph.FormatLineCore(line, lineDesc.pfsbreakreclineclient, ctx, lineDesc.dcpFirst, lineDesc.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), lineDesc.dcpFirst); // Assert that number of characters in Text line is the same as our expected length Invariant.Assert(line.SafeLength == lineDesc.dcpLim - lineDesc.dcpFirst, "Line length is out of [....]"); // Get rectangles from start and end positions of range rectangles = line.GetRangeBounds(localStart, localEnd - localStart, TextDpi.FromTextDpi(lineDesc.urStart), TextDpi.FromTextDpi(lineDesc.vrStart)); // Rectangles must have at least one element Invariant.Assert(rectangles.Count > 0); // Dispose the line line.Dispose(); return rectangles; }
private List<Rect> GetRectanglesInCompositeLine( PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc, ContentElement e, int start, int length) { List<Rect> rectangles = new List<Rect>(); int end = start + length; // If the element does not lie in the line at all, return empty list //if (start > lineDesc.dcpLim) //{ // // Element starts after line ends // return rectangles; //} //if (end < lineDesc.dcpFirst) //{ // Element ends before line starts // return rectangles; //} // Get list of line elements. PTS.FSLINEELEMENT[] arrayLineElement; PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); for (int elIndex = 0; elIndex < arrayLineElement.Length; elIndex++) { PTS.FSLINEELEMENT element = arrayLineElement[elIndex]; // Check if element we are looking for does not span the current element at all if (start >= element.dcpLim) { // Element starts after other element ends continue; } if (end <= element.dcpFirst) { // Element ends before line starts continue; } // Establish start and end points of element span within the line so that // we can get rectangle between them int localStart = (start < element.dcpFirst) ? element.dcpFirst : start; int localEnd = (end < element.dcpLim) ? end : element.dcpLim; Debug.Assert(localEnd > localStart); Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(element.fClearOnLeft), PTS.ToBoolean(element.fClearOnRight), TextParagraph.TextRunCache); if(IsOptimalParagraph) { ctx.LineFormatLengthTarget = element.dcpLim - element.dcpFirst; } TextParagraph.FormatLineCore(line, element.pfsbreakreclineclient, ctx, element.dcpFirst, element.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), element.dcpFirst); // Assert that number of characters in Text line is the same as our expected length Invariant.Assert(line.SafeLength == element.dcpLim - element.dcpFirst, "Line length is out of [....]"); // Get rectangles from start and end positions of range for this element List<Rect> elementRectangles = line.GetRangeBounds(localStart, localEnd - localStart, TextDpi.FromTextDpi(element.urStart), TextDpi.FromTextDpi(lineDesc.vrStart)); // Rectangles must have at least one element Invariant.Assert(elementRectangles.Count > 0); // Add rectangles from this element to rectangles from whole line rectangles.AddRange(elementRectangles); // Dispose the line line.Dispose(); } return rectangles; }
// ------------------------------------------------------------------ // Returns rectangles for a single composite line correcsponding to the // given dcp range. Includes trailing whitespaces. // Params: // dcpRangeStart - range's cp start position. Adjusted for // line's cp range. // cchRange - nuber of cps in the range. // lineTopSpace - the value that line's height should // be extended to at the top. // lineRightSpace - the value that line's width should // be extended to at the right. // lineDesc - line description. // lineIndex - line index. // elemDesc - element description. // visibleRect - visibility rectangle. It is Ok to return // null if the line is not visible. // hasAttachedObjects- Attached objects are present // Returns: // null - if line is not visible // rectangles - otherwise. // ----------------------------------------------------------------- private List<Rect> RectanglesFromDcpRangeOfCompositeLineElement( int dcpRangeStart, int cchRange, double lineTopSpace, double lineRightSpace, ref PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc, int lineIndex, ref PTS.FSLINEELEMENT elemDesc, int elemIndex, Rect visibleRect) { List<Rect> rectangles = null; Rect elementRect = new PTS.FSRECT(elemDesc.urBBox, lineDesc.vrStart, elemDesc.durBBox, lineDesc.dvrAscent + lineDesc.dvrDescent).FromTextDpi(); // width has to be adjusted to include trailing whitespaces... LineVisual lineVisual = FetchLineVisualComposite(lineIndex, elemIndex); if (lineVisual != null) { elementRect.Width = Math.Max(lineVisual.WidthIncludingTrailingWhitespace, 0); } elementRect.Y = elementRect.Y - lineTopSpace; elementRect.Height = elementRect.Height + lineTopSpace; elementRect.Width = elementRect.Width + lineRightSpace; // Ignore horizontal offset because TextBox page width != extent width. // It's ok to include content that doesn't strictly intersect -- this // is a perf optimization and the edge cases won't significantly hurt us. Rect testRect = elementRect; testRect.X = visibleRect.X; if (testRect.IntersectsWith(visibleRect)) { // Check whether the line is fully selected - we don't need to reformat it in this case if (dcpRangeStart == elemDesc.dcpFirst && elemDesc.dcpLim <= (dcpRangeStart + cchRange)) { rectangles = new List<Rect>(1); rectangles.Add(elementRect); } else { // Create and format line Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(elemDesc.fClearOnLeft), PTS.ToBoolean(elemDesc.fClearOnRight), TextParagraph.TextRunCache); if (IsOptimalParagraph) { ctx.LineFormatLengthTarget = elemDesc.dcpLim - elemDesc.dcpFirst; } TextParagraph.FormatLineCore(line, elemDesc.pfsbreakreclineclient, ctx, elemDesc.dcpFirst, elemDesc.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), elemDesc.dcpFirst); Invariant.Assert(line.SafeLength == elemDesc.dcpLim - elemDesc.dcpFirst, "Line length is out of [....]"); double duOffset = TextDpi.FromTextDpi(elemDesc.urStart); double dvOffset = TextDpi.FromTextDpi(lineDesc.vrStart); rectangles = line.GetRangeBounds(dcpRangeStart, cchRange, duOffset, dvOffset); if (!DoubleUtil.IsZero(lineTopSpace)) { for (int i = 0, count = rectangles.Count; i < count; ++i) { Rect r = rectangles[i]; r.Y = r.Y - lineTopSpace; r.Height = r.Height + lineTopSpace; rectangles[i] = r; } } if (!DoubleUtil.IsZero(lineRightSpace)) { // add the rect representing end-of-line / end-of-para rectangles.Add( new Rect( duOffset + TextDpi.FromTextDpi(line.Start + line.Width), dvOffset - lineTopSpace, lineRightSpace, TextDpi.FromTextDpi(line.Height) + lineTopSpace ) ); } // dispose of the line line.Dispose(); } } return (rectangles); }