internal void GetLineDetails(int dcpLine, out int cchContent, out int cchEllipses) { // Query paragraph details PTS.FSTEXTDETAILS textDetails; PTS.Validate(PTS.FsQueryTextDetails(PtsContext.Context, _paraHandle.Value, out textDetails)); int lineWidth = 0; bool firstLine = (dcpLine == 0); int dcpLim = 0; IntPtr breakRecLine = IntPtr.Zero; // There are 3 different types of text paragraphs: // (a) full with simple lines // (b) full with composite lines - when figures/floaters are present // (c) cached - when using ParaChache if (textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdFull) { if (textDetails.u.full.cLines > 0) { if (!PTS.ToBoolean(textDetails.u.full.fLinesComposite)) { // (a) full with simple lines PTS.FSLINEDESCRIPTIONSINGLE[] arrayLineDesc; PtsHelper.LineListSimpleFromTextPara(PtsContext, _paraHandle.Value, ref textDetails.u.full, out arrayLineDesc); // Get lines information int index; for (index = 0; index < arrayLineDesc.Length; index++) { PTS.FSLINEDESCRIPTIONSINGLE lineDesc = arrayLineDesc[index]; if (dcpLine == lineDesc.dcpFirst) { lineWidth = lineDesc.dur; // Store dcpLim to check that line lengths are in [....] dcpLim = lineDesc.dcpLim; breakRecLine = lineDesc.pfsbreakreclineclient; break; } } } else { // (b) full with composite lines - when figures/floaters are present PTS.FSLINEDESCRIPTIONCOMPOSITE[] arrayLineDesc; PtsHelper.LineListCompositeFromTextPara(PtsContext, _paraHandle.Value, ref textDetails.u.full, out arrayLineDesc); // Get lines information int index; for (index = 0; index < arrayLineDesc.Length; index++) { PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc = arrayLineDesc[index]; if (lineDesc.cElements == 0) continue; // Get list of line elements. PTS.FSLINEELEMENT[] arrayLineElement; PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); int elIndex; for (elIndex = 0; elIndex < arrayLineElement.Length; elIndex++) { PTS.FSLINEELEMENT element = arrayLineElement[elIndex]; if (element.dcpFirst == dcpLine) { lineWidth = element.dur; // Store dcpLim to check that line lengths are in [....] dcpLim = element.dcpLim; breakRecLine = element.pfsbreakreclineclient; break; } } if (elIndex < arrayLineElement.Length) { firstLine = (index == 0); break; } } } } } else { // (c) cached - when using ParaChache Invariant.Assert(textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdCached); Invariant.Assert(false, "Should not get here. ParaCache is not currently used."); } // Recreate text line Line.FormattingContext ctx = new Line.FormattingContext(false, true, true, TextParagraph.TextRunCache); Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); if(IsOptimalParagraph) { ctx.LineFormatLengthTarget = dcpLim - dcpLine; } TextParagraph.FormatLineCore(line, breakRecLine, ctx, dcpLine, lineWidth, firstLine, dcpLine); // Assert that number of characters in Text line is the same as our expected length Invariant.Assert(line.SafeLength == dcpLim - dcpLine, "Line length is out of [....]"); cchContent = line.ContentLength; cchEllipses = line.GetEllipsesLength(); line.Dispose(); }