/// <summary> /// Fetch the next run at embedded object position. /// </summary> /// <param name="dcp"> /// Character offset of this run. /// </param> /// <param name="position"> /// Current position in the text array. /// </param> protected TextRun HandleEmbeddedObject(int dcp, StaticTextPointer position) { Invariant.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement, "TextPointer does not point to embedded object."); TextRun run = null; DependencyObject embeddedObject = position.GetAdjacentElement(LogicalDirection.Forward) as DependencyObject; if (embeddedObject is UIElement) { // Extract the aggregated properties into something that the textrun can use. TextRunProperties textProps = new TextProperties(embeddedObject, position, true /* inline objects */, true /* get background */); // Create inline object run. run = new InlineObjectRun(TextContainerHelper.EmbeddedObjectLength, (UIElement)embeddedObject, textProps, _paraClient.Paragraph as TextParagraph); } else { // If the embedded object is of an unknown type, treat it as hidden content. run = new TextHidden(TextContainerHelper.EmbeddedObjectLength); } return run; }
/// <summary> /// Fetch the next run at element end edge position. /// ElementEndEdge; we can have 2 possibilities: /// (1) Close edge of element associated with the text paragraph, /// create synthetic LineBreak run to end the current line. /// (2) End of inline element, hide CloseEdge character and continue /// </summary> /// <param name="position"></param> /// Position in current text array protected TextRun HandleElementEndEdge(StaticTextPointer position) { Invariant.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd, "TextPointer does not point to element end edge."); TextRun run; if (position.Parent == _paraClient.Paragraph.Element) { // (1) Close edge of element associated with the text paragraph, // create synthetic LineBreak run to end the current line. run = new ParagraphBreakRun(_syntheticCharacterLength, PTS.FSFLRES.fsflrEndOfParagraph); } else { TextElement element = (TextElement)position.GetAdjacentElement(LogicalDirection.Forward); Debug.Assert(element != null, "Element should be here."); Inline inline = (Inline) element; DependencyObject parent = inline.Parent; FlowDirection parentFlowDirection = inline.FlowDirection; if(parent != null) { parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty); } if (inline.FlowDirection != parentFlowDirection) { run = new TextEndOfSegment(_elementEdgeCharacterLength); } else { TextDecorationCollection textDecorations = DynamicPropertyReader.GetTextDecorations(inline); if (textDecorations == null || textDecorations.Count == 0) { // (2) End of inline element, hide CloseEdge character and continue run = new TextHidden(_elementEdgeCharacterLength); } else { run = new TextEndOfSegment(_elementEdgeCharacterLength); } } } return run; }
/// <summary> /// Return next TextRun at element edge start position /// </summary> /// <param name="position"> /// Current position in text array /// </param> protected TextRun HandleElementStartEdge(StaticTextPointer position) { Invariant.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart, "TextPointer does not point to element start edge."); // TextRun run = null; TextElement element = (TextElement)position.GetAdjacentElement(LogicalDirection.Forward); Debug.Assert(element != null, "Cannot use ITextContainer that does not provide TextElement instances."); Invariant.Assert(!(element is Block), "We do not expect any Blocks inside Paragraphs"); // Treat figure and floaters as special hidden runs. if (element is Figure || element is Floater) { // Get the length of the element int cch = TextContainerHelper.GetElementLength(_paraClient.Paragraph.StructuralCache.TextContainer, element); // Create special hidden run. run = new FloatingRun(cch, element is Figure); if (element is Figure) { _hasFigures = true; } else { _hasFloaters = true; } } else if (element is LineBreak) { int cch = TextContainerHelper.GetElementLength(_paraClient.Paragraph.StructuralCache.TextContainer, element); run = new LineBreakRun(cch, PTS.FSFLRES.fsflrSoftBreak); } else if (element.IsEmpty) { // Empty TextElement should affect line metrics. // TextFormatter does not support this feature right now, so as workaround // TextRun with ZERO WIDTH SPACE is used. TextProperties textProps = new TextProperties(element, position, false /* inline objects */, true /* get background */); char[] textBuffer = new char[_elementEdgeCharacterLength * 2]; // Assert that _elementEdgeCharacterLength is 1 before we use hard-coded indices Invariant.Assert(_elementEdgeCharacterLength == 1, "Expected value of _elementEdgeCharacterLength is 1"); textBuffer[0] = (char)0x200B; textBuffer[1] = (char)0x200B; run = new TextCharacters(textBuffer, 0, textBuffer.Length, textProps); } else { Inline inline = (Inline) element; DependencyObject parent = inline.Parent; FlowDirection inlineFlowDirection = inline.FlowDirection; FlowDirection parentFlowDirection = inlineFlowDirection; TextDecorationCollection inlineTextDecorations = DynamicPropertyReader.GetTextDecorations(inline); if(parent != null) { parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty); } if (inlineFlowDirection != parentFlowDirection) { // Inline's flow direction is different from its parent. Need to create new TextSpanModifier with flow direction if (inlineTextDecorations == null || inlineTextDecorations.Count == 0) { run = new TextSpanModifier( _elementEdgeCharacterLength, null, null, inlineFlowDirection ); } else { run = new TextSpanModifier( _elementEdgeCharacterLength, inlineTextDecorations, inline.Foreground, inlineFlowDirection ); } } else { if (inlineTextDecorations == null || inlineTextDecorations.Count == 0) { run = new TextHidden(_elementEdgeCharacterLength); } else { run = new TextSpanModifier( _elementEdgeCharacterLength, inlineTextDecorations, inline.Foreground ); } } } return run; }
// ----------------------------------------------------------------- // Fetch the next run at UIElment position. // // position - current position in the text array // dcp - current position in the text array // ----------------------------------------------------------------- private TextRun HandleInlineObject(StaticTextPointer position, int dcp) { Debug.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.EmbeddedElement, "TextPointer does not point to embedded object."); TextRun run = null; DependencyObject element = position.GetAdjacentElement(LogicalDirection.Forward) as DependencyObject; if (element is UIElement) { // TextRunProperties textProps = new TextProperties(element, position, true /* inline objects */, true /* get background */); // Create object run. run = new InlineObject(dcp, TextContainerHelper.EmbeddedObjectLength, (UIElement)element, textProps, _owner); } else { // If the embedded object is of an unknown type (not UIElement), // treat it as element edge. run = HandleElementEndEdge(position); } return run; }
// ----------------------------------------------------------------- // Fetch the next run at element close edge position. // // position - current position in the text array // ------------------------------------------------------------------ private TextRun HandleElementEndEdge(StaticTextPointer position) { Debug.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd, "TextPointer does not point to element end edge."); TextRun run = null; TextElement element = (TextElement)position.GetAdjacentElement(LogicalDirection.Forward); Debug.Assert(element != null, "Element should be here."); Inline inline = element as Inline; if (inline == null) { run = new TextHidden(_elementEdgeCharacterLength); } else { DependencyObject parent = inline.Parent; FlowDirection parentFlowDirection = inline.FlowDirection; if(parent != null) { parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty); } if (inline.FlowDirection != parentFlowDirection) { run = new TextEndOfSegment(_elementEdgeCharacterLength); } else { TextDecorationCollection textDecorations = DynamicPropertyReader.GetTextDecorations(inline); if (textDecorations == null || textDecorations.Count == 0) { // (2) End of inline element, hide CloseEdge character and continue run = new TextHidden(_elementEdgeCharacterLength); } else { run = new TextEndOfSegment(_elementEdgeCharacterLength); } } } return run; }
// ------------------------------------------------------------------ // Fetch the next run at element open edge position. // // position - current position in the text array // ------------------------------------------------------------------ private TextRun HandleElementStartEdge(StaticTextPointer position) { Debug.Assert(position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart, "TextPointer does not point to element start edge."); // TextRun run = null; TextElement element = (TextElement)position.GetAdjacentElement(LogicalDirection.Forward); Debug.Assert(element != null, "Cannot use ITextContainer that does not provide TextElement instances."); if (element is LineBreak) { run = new TextEndOfLine(_elementEdgeCharacterLength * 2); } else if (element.IsEmpty) { // Empty TextElement should affect line metrics. // TextFormatter does not support this feature right now, so as workaround // TextRun with ZERO WIDTH SPACE is used. TextRunProperties textProps = new TextProperties(element, position, false /* inline objects */, true /* get background */); char[] textBuffer = new char[_elementEdgeCharacterLength * 2]; textBuffer[0] = (char)0x200B; textBuffer[1] = (char)0x200B; run = new TextCharacters(textBuffer, 0, textBuffer.Length, textProps); } else { Inline inline = element as Inline; if (inline == null) { run = new TextHidden(_elementEdgeCharacterLength); } else { DependencyObject parent = inline.Parent; FlowDirection inlineFlowDirection = inline.FlowDirection; FlowDirection parentFlowDirection = inlineFlowDirection; if(parent != null) { parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty); } TextDecorationCollection inlineTextDecorations = DynamicPropertyReader.GetTextDecorations(inline); if (inlineFlowDirection != parentFlowDirection) { // Inline's flow direction is different from its parent. Need to create new TextSpanModifier with flow direction if (inlineTextDecorations == null || inlineTextDecorations.Count == 0) { run = new TextSpanModifier( _elementEdgeCharacterLength, null, null, inlineFlowDirection ); } else { run = new TextSpanModifier( _elementEdgeCharacterLength, inlineTextDecorations, inline.Foreground, inlineFlowDirection ); } } else { if (inlineTextDecorations == null || inlineTextDecorations.Count == 0) { run = new TextHidden(_elementEdgeCharacterLength); } else { run = new TextSpanModifier( _elementEdgeCharacterLength, inlineTextDecorations, inline.Foreground ); } } } } return run; }