private ITextPointer NextCaretUnitPositionFromDcpCompositeLines( int dcp, ITextPointer position, LogicalDirection direction, ref PTS.FSTEXTDETAILSFULL textDetails) { ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap); // Get list of lines PTS.FSLINEDESCRIPTIONCOMPOSITE [] arrayLineDesc; PtsHelper.LineListCompositeFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); // Declare next position and set it to initial position ITextPointer nextCaretPosition = position; // First iterate through lines for (int 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); for (int elIndex = 0; elIndex < arrayLineElement.Length; elIndex++) { PTS.FSLINEELEMENT element = arrayLineElement[elIndex]; // 'dcp' needs to be within line range. If position points to dcpLim, // it means that the next line starts from such position, hence go to the next line. if ( ((element.dcpFirst <= dcp) && (element.dcpLim > dcp)) || ((element.dcpLim == dcp) && (elIndex == arrayLineElement.Length - 1) && (index == arrayLineDesc.Length - 1))) { if (dcp == element.dcpFirst && direction == LogicalDirection.Backward) { // Beginning of element. if (dcp == 0) { // Assert that this is first elment on first line Debug.Assert(index == 0); Debug.Assert(elIndex == 0); return position; } else { if (elIndex > 0) { // Beginning of element, but not of line --elIndex; element = arrayLineElement[elIndex]; } else { // There must be at least one line above this Debug.Assert(index > 0); // Go to previous line --index; lineDesc = arrayLineDesc[index]; if (lineDesc.cElements == 0) { // Stay in same position return position; } else { // Get list of line elements. PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); element = arrayLineElement[arrayLineElement.Length - 1]; } } } } else if (dcp >= element.dcpLim - 1 && direction == LogicalDirection.Forward) { if (dcp == element.dcpLim) { // End of paragraph Debug.Assert(elIndex == arrayLineElement.Length - 1); Debug.Assert(index == arrayLineDesc.Length - 1); return position; } else if (dcp == element.dcpLim - 1 && elIndex == arrayLineElement.Length - 1 && index == arrayLineDesc.Length - 1) { // Special end character does not belong to line return position; } } // Create and format line 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 [....]"); // Create CharacterHit from dcp, and get next CharacterHit charHit = new CharacterHit(dcp, 0); CharacterHit nextCharacterHit; if (direction == LogicalDirection.Forward) { nextCharacterHit = line.GetNextCaretCharacterHit(charHit); } else { nextCharacterHit = line.GetPreviousCaretCharacterHit(charHit); } LogicalDirection logicalDirection; if ((nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == element.dcpLim) && direction == LogicalDirection.Forward) { // Going forward brought us to the end of a line, context must be forward for next line if (index == arrayLineDesc.Length - 1) { // last line so context must stay backward logicalDirection = LogicalDirection.Backward; } else { // It is a new element, on the same line or a new one. Either way it;s forward context logicalDirection = LogicalDirection.Forward; } } else if ((nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == element.dcpFirst) && direction == LogicalDirection.Backward) { // Going forward brought us to the start of a line, context must be backward for previous line if (index == 0) { // First line, so we will stay forward logicalDirection = LogicalDirection.Forward; } else { // Either the previous element or last element on previous line, context is backward logicalDirection = LogicalDirection.Backward; } } else { logicalDirection = (nextCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward; } nextCaretPosition = GetTextPosition(nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength, logicalDirection); // Dispose the line line.Dispose(); return nextCaretPosition; } } } return nextCaretPosition; }
private ITextPointer NextCaretUnitPositionFromDcpSimpleLines( int dcp, ITextPointer position, LogicalDirection direction, ref PTS.FSTEXTDETAILSFULL textDetails) { ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap); // Get list of lines PTS.FSLINEDESCRIPTIONSINGLE[] arrayLineDesc; PtsHelper.LineListSimpleFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); // Declare next position and set it to initial position ITextPointer nextCaretPosition = position; // First iterate through lines for (int index = 0; index < arrayLineDesc.Length; index++) { PTS.FSLINEDESCRIPTIONSINGLE lineDesc = arrayLineDesc[index]; // 'dcp' needs to be within line range. If position points to dcpLim, // it means that the next line starts from such position, hence go to the next line. if (((lineDesc.dcpFirst <= dcp) && (lineDesc.dcpLim > dcp)) || ((lineDesc.dcpLim == dcp) && (index == arrayLineDesc.Length - 1))) { if (dcp == lineDesc.dcpFirst && direction == LogicalDirection.Backward) { // Go to previous line if (index == 0) { return position; } else { // Update dcp, lineDesc Debug.Assert(index > 0); --index; lineDesc = arrayLineDesc[index]; } } else if (dcp >= lineDesc.dcpLim - 1 && direction == LogicalDirection.Forward) { // If we are at the last line there will be a fake marker for this, so we return if (index == arrayLineDesc.Length - 1) { return position; } } // 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 [....]"); // Create CharacterHit CharacterHit charHit = new CharacterHit(dcp, 0); // Get previous caret position from the line // Determine logical direction for next caret index and create TextPointer from it CharacterHit nextCharacterHit; if (direction == LogicalDirection.Forward) { nextCharacterHit = line.GetNextCaretCharacterHit(charHit); } else { nextCharacterHit = line.GetPreviousCaretCharacterHit(charHit); } LogicalDirection logicalDirection; if ((nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == lineDesc.dcpLim) && direction == LogicalDirection.Forward) { // Going forward brought us to the end of a line, context must be forward for next line if (index == arrayLineDesc.Length - 1) { // last line so context must stay backward logicalDirection = LogicalDirection.Backward; } else { logicalDirection = LogicalDirection.Forward; } } else if ((nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == lineDesc.dcpFirst) && direction == LogicalDirection.Backward) { // Going forward brought us to the start of a line, context must be backward for previous line if (index == 0) { // First line, so we will stay forward logicalDirection = LogicalDirection.Forward; } else { logicalDirection = LogicalDirection.Backward; } } else { logicalDirection = (nextCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward; } nextCaretPosition = GetTextPosition(nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength, logicalDirection); // Dispose the line line.Dispose(); break; } } return nextCaretPosition; }