本文整理汇总了C#中ITextPointer.CreatePointer方法的典型用法代码示例。如果您正苦于以下问题:C# ITextPointer.CreatePointer方法的具体用法?C# ITextPointer.CreatePointer怎么用?C# ITextPointer.CreatePointer使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类ITextPointer
的用法示例。
在下文中一共展示了ITextPointer.CreatePointer方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: GetNextCaretUnitPosition
/// <summary>
/// Finds the next position at the edge of a caret unit in
/// specified direction.
/// </summary>
/// <param name="position">
/// Initial text position of an object/character.
/// </param>
/// <param name="direction">
/// If Forward, this method returns the "caret unit" position following
/// the initial position.
/// If Backward, this method returns the caret unit" position preceding
/// the initial position.
/// </param>
/// <returns>
/// The next caret unit break position in specified direction.
/// </returns>
/// <exception cref="System.InvalidOperationException">
/// Throws InvalidOperationException if IsValid is false.
/// If IsValid returns false, Validate method must be called before
/// calling this method.
/// </exception>
/// <remarks>
/// In the context of this method, "caret unit" refers to a group of one
/// or more Unicode code points that map to a single rendered glyph.
///
/// If position is located between two caret units, this method returns
/// a new position located at the opposite edge of the caret unit in
/// the indicated direction.
/// If position is located within a group of Unicode code points that map
/// to a single caret unit, this method returns a new position at
/// the indicated edge of the containing caret unit.
/// If position is located at the beginning of end of content -- there is
/// no content in the indicated direction -- then this method returns
/// a position located at the same location as initial position.
/// </remarks>
internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction)
{
FixedTextPointer ftp = Container.VerifyPosition(position);
FixedPosition fixedp;
if (_GetFixedPosition(ftp, out fixedp))
{
DependencyObject element = this.FixedPage.GetElement(fixedp.Node);
if (element is Glyphs)
{
Glyphs g = (Glyphs)element;
GlyphRun run = g.ToGlyphRun();
int characterCount = (run.Characters == null) ? 0 : run.Characters.Count;
CharacterHit start = (fixedp.Offset == characterCount) ?
new CharacterHit(fixedp.Offset - 1, 1) :
new CharacterHit(fixedp.Offset, 0);
CharacterHit next = (direction == LogicalDirection.Forward) ?
run.GetNextCaretCharacterHit(start) :
run.GetPreviousCaretCharacterHit(start);
if (!start.Equals(next))
{
LogicalDirection edge = LogicalDirection.Forward;
if (next.TrailingLength > 0)
{
edge = LogicalDirection.Backward;
}
int index = next.FirstCharacterIndex + next.TrailingLength;
return _CreateTextPointer(new FixedPosition(fixedp.Node, index), edge);
}
}
}
//default behavior is to simply move textpointer
ITextPointer pointer = position.CreatePointer();
pointer.MoveToNextInsertionPosition(direction);
return pointer;
}
示例2: WriteXamlTextSegment
// -------------------------------------------------------------
//
// Private Methods
//
// -------------------------------------------------------------
#region Private Methods
// .............................................................
//
// Serialization
//
// .............................................................
/// <summary>
/// This function serializes text segment formed by rangeStart and rangeEnd to valid xml using xmlWriter.
/// </summary>
/// <SecurityNote>
/// To mask the security exception from XamlWriter.Save in partial trust case,
/// this function checks if the current call stack has the all clipboard permission.
/// </SecurityNote>
private static void WriteXamlTextSegment(XmlWriter xmlWriter, ITextPointer rangeStart, ITextPointer rangeEnd, XamlTypeMapper xamlTypeMapper, ref int elementLevel, WpfPayload wpfPayload, bool ignoreWriteHyperlinkEnd, List<int> ignoreList, bool preserveTextElements)
{
// Special case for pure text selection - we need a Run wrapper for it.
if (elementLevel == EmptyDocumentDepth && typeof(Run).IsAssignableFrom(rangeStart.ParentType))
{
elementLevel++;
xmlWriter.WriteStartElement(typeof(Run).Name);
}
// Create text navigator for reading the range's content
ITextPointer textReader = rangeStart.CreatePointer();
// Exclude last opening tag from serialization - we don't need to create extra element
// is cases when we have whole paragraphs/cells selected.
// NOTE: We do this slightly differently than in TextRangeEdit.AdjustRangeEnd, where we use normalization for adjusted position.
// In this case normalized position does not work, because we need to keep information about crossed paragraph boundary.
while (rangeEnd.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart)
{
rangeEnd = rangeEnd.GetNextContextPosition(LogicalDirection.Backward);
}
// Write the range internal contents
while (textReader.CompareTo(rangeEnd) < 0)
{
TextPointerContext runType = textReader.GetPointerContext(LogicalDirection.Forward);
switch (runType)
{
case TextPointerContext.ElementStart:
TextElement nextElement = (TextElement)textReader.GetAdjacentElement(LogicalDirection.Forward);
if (nextElement is Hyperlink)
{
// Don't write Hyperlink start element if Hyperlink is invalid
// in case of having a UiElement except Image or stated the range end
// position before the end position of the Hyperlink.
if (IsHyperlinkInvalid(textReader, rangeEnd))
{
ignoreWriteHyperlinkEnd = true;
textReader.MoveToNextContextPosition(LogicalDirection.Forward);
continue;
}
}
else if (nextElement != null)
{
//
TextElementEditingBehaviorAttribute att = (TextElementEditingBehaviorAttribute)Attribute.GetCustomAttribute(nextElement.GetType(), typeof(TextElementEditingBehaviorAttribute));
if (att != null && !att.IsTypographicOnly)
{
if (IsPartialNonTypographic(textReader, rangeEnd))
{
// Add pointer to ignore list
ITextPointer ptr = textReader.CreatePointer();
ptr.MoveToElementEdge(ElementEdge.BeforeEnd);
ignoreList.Add(ptr.Offset);
textReader.MoveToNextContextPosition(LogicalDirection.Forward);
continue;
}
}
}
elementLevel++;
textReader.MoveToNextContextPosition(LogicalDirection.Forward);
WriteStartXamlElement(/*range:*/null, textReader, xmlWriter, xamlTypeMapper, /*reduceElement:*/wpfPayload == null, preserveTextElements);
break;
case TextPointerContext.ElementEnd:
// Don't write Hyperlink end element if Hyperlink include the invalid
// in case of having a UiElement except Image or stated the range end
// before the end position of the Hyperlink or Hyperlink opening tag is
// skipped from WriteOpeningTags by selecting of the partial of Hyperlink.
if (ignoreWriteHyperlinkEnd && (textReader.GetAdjacentElement(LogicalDirection.Forward) is Hyperlink))
{
// Reset the flag to keep walk up the next Hyperlink tag
//.........这里部分代码省略.........
示例3: WriteInheritableProperties
// Writes a collection of attributes representing inheritable properties
// whose values has been affected by this element.
// Parameter onlyAffected=true means that we serialize only properties affected by
// the current element; otherwise we output all known inheritable properties.
private static void WriteInheritableProperties(Type elementTypeStandardized, ITextPointer context, XmlWriter xmlWriter, bool onlyAffected, DependencyObject complexProperties)
{
// Create a pointer positioned immediately outside the element
ITextPointer outerContext = null;
if (onlyAffected)
{
outerContext = context.CreatePointer();
outerContext.MoveToElementEdge(ElementEdge.BeforeStart);
}
DependencyProperty[] inheritableProperties = TextSchema.GetInheritableProperties(elementTypeStandardized);
for (int i = 0; i < inheritableProperties.Length; i++)
{
DependencyProperty property = inheritableProperties[i];
object innerValue = context.GetValue(property);
if (innerValue == null)
{
// Some properties like Foreground may have null as default value.
// Skip them.
continue;
}
object outerValue = null;
if (onlyAffected)
{
outerValue = outerContext.GetValue(property);
}
// The property must appear in markup if the element
if (!onlyAffected || // all properties requested for saving context on root
!TextSchema.ValuesAreEqual(innerValue, outerValue)) // or the element really affects the property
{
string stringValue = DPTypeDescriptorContext.GetStringValue(property, innerValue);
if (stringValue != null)
{
stringValue = FilterNaNStringValueForDoublePropertyType(stringValue, property.PropertyType);
string propertyName;
if (property == FrameworkContentElement.LanguageProperty)
{
// Special case for CultureInfo property that must be represented in xaml as xml:lang attribute
propertyName = "xml:lang";
}
else
{
// Regular case: serialize a property with its own name
propertyName = GetPropertyNameForElement(property, elementTypeStandardized, /*forceComplexName:*/false);
}
xmlWriter.WriteAttributeString(propertyName, stringValue);
}
else
{
complexProperties.SetValue(property, innerValue);
}
}
}
}
示例4: AddMultipleCompositionLines
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
private void AddMultipleCompositionLines(ITextPointer start, ITextPointer end)
{
// Initalize the start/end line pointer
ITextPointer startLinePointer = start;
ITextPointer endLinePointer = startLinePointer;
// Get all composition lines that includes the start/end pointer
while (endLinePointer.CompareTo(end) < 0)
{
TextSegment textSegment = _textView.GetLineRange(endLinePointer);
if (textSegment.IsNull)
{
// endLinePointer is not within the TextView's definition of a line.
// Skip ahead to text on the next iteration.
startLinePointer = endLinePointer;
}
else
{
Debug.Assert(start.CompareTo(startLinePointer) <= 0, "The start pointer is positioned after the composition start line pointer!");
if (startLinePointer.CompareTo(textSegment.Start) < 0)
{
// Update the start line pointer
startLinePointer = textSegment.Start;
}
if (endLinePointer.CompareTo(textSegment.End) < 0)
{
if (end.CompareTo(textSegment.End) < 0)
{
// Update the end line pointer
endLinePointer = end.CreatePointer();
}
else
{
// Update the end line pointer
endLinePointer = textSegment.End.CreatePointer(LogicalDirection.Backward);
}
}
else
{
Debug.Assert(endLinePointer.CompareTo(textSegment.End) == 0, "The end line pointer is positioned after the composition text range end pointer!");
}
// Get the rectangle for start/end position
Rect startRect = _textView.GetRectangleFromTextPosition(startLinePointer);
Rect endRect = _textView.GetRectangleFromTextPosition(endLinePointer);
// Add the composition line to be rendered
_compositionLines.Add(new CompositionLine(startRect, endRect, _textServicesDisplayAttribute.GetLineColor(startLinePointer)));
startLinePointer = textSegment.End.CreatePointer(LogicalDirection.Forward);
}
// Move the start pointer to the next text line. startLinePointer must be a pointer to start
// text.
while ((startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None) &&
(startLinePointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text))
{
startLinePointer.MoveToNextContextPosition(LogicalDirection.Forward);
}
endLinePointer = startLinePointer;
}
}
示例5: IsPartialNonTypographic
/// <summary>
/// Return true if rangeEnd is not at the end of an element.
///
/// textReader must already be at the start of the element.
/// </summary>
private static bool IsPartialNonTypographic(ITextPointer textReader, ITextPointer rangeEnd)
{
bool isPartial = false;
Invariant.Assert(textReader.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart);
ITextPointer elementNavigation = textReader.CreatePointer();
ITextPointer elementEnd = textReader.CreatePointer();
elementEnd.MoveToNextContextPosition(LogicalDirection.Forward);
// Find the end position
elementEnd.MoveToElementEdge(ElementEdge.AfterEnd);
if (elementEnd.CompareTo(rangeEnd) > 0)
{
isPartial = true;
}
return isPartial;
}
示例6: IdentifyWordsOnSelectionEnds
// Extends the selection to the mouse cursor position.
void ITextSelection.ExtendSelectionByMouse(ITextPointer cursorPosition, bool forceWordSelection, bool forceParagraphSelection)
{
ITextSelection thisSelection = (ITextSelection)this;
// Check whether the cursor has been actually moved - compare with the previous position
if (forceParagraphSelection || _previousCursorPosition != null && cursorPosition.CompareTo(_previousCursorPosition) == 0)
{
// Mouse was not actually moved. Ignore the event.
return;
}
thisSelection.BeginChange();
try
{
if (!BeginMouseSelectionProcess(cursorPosition))
{
return;
}
// Get anchor position
ITextPointer anchorPosition = ((ITextSelection)this).AnchorPosition;
// Identify words on selection ends
TextSegment anchorWordRange;
TextSegment cursorWordRange;
IdentifyWordsOnSelectionEnds(anchorPosition, cursorPosition, forceWordSelection, out anchorWordRange, out cursorWordRange);
// Calculate selection boundary positions
ITextPointer startPosition;
ITextPointer movingPosition;
if (anchorWordRange.Start.CompareTo(cursorWordRange.Start) <= 0)
{
startPosition = anchorWordRange.Start.GetFrozenPointer(LogicalDirection.Forward);
movingPosition = cursorWordRange.End.GetFrozenPointer(LogicalDirection.Backward); ;
}
else
{
startPosition = anchorWordRange.End.GetFrozenPointer(LogicalDirection.Backward);
movingPosition = cursorWordRange.Start.GetFrozenPointer(LogicalDirection.Forward); ;
}
// Note that we use includeCellAtMovingPosition=true because we want that hit-tested table cell
// be included into selection no matter whether it's empty or not.
TextRangeBase.Select(this, startPosition, movingPosition, /*includeCellAtMovingPosition:*/true);
SetActivePositions(anchorPosition, movingPosition);
// Store previous cursor position - for the next extension event
_previousCursorPosition = cursorPosition.CreatePointer();
Invariant.Assert(thisSelection.Contains(thisSelection.AnchorPosition));
}
finally
{
thisSelection.EndChange();
}
}
示例7: IsInAncestorScope
// Walks parents from this position until it hits limiting ancestor type.
private static bool IsInAncestorScope(ITextPointer position, Type allowedParentType, Type limitingType)
{
ITextPointer navigator = position.CreatePointer();
Type parentType = navigator.ParentType;
while (parentType != null && allowedParentType.IsAssignableFrom(parentType))
{
if (limitingType.IsAssignableFrom(parentType))
{
return true;
}
navigator.MoveToElementEdge(ElementEdge.BeforeStart);
parentType = navigator.ParentType;
}
return false;
}
示例8: GetFollowingNonMergeableInlineContentStart
// If position is before the start boundary of a non-mergeable inline (Hyperlink),
// this method returns a position immediately preceding its content (which is not an insertion position).
// This method will skip past leading InlineUIContainers and BlockUIContainers. Otherwise returns null.
internal static ITextPointer GetFollowingNonMergeableInlineContentStart(ITextPointer position)
{
ITextPointer navigator = position.CreatePointer();
bool moved = false;
Type elementType;
while (true)
{
BorderingElementCategory category = GetBorderingElementCategory(navigator, LogicalDirection.Forward);
// If position is before formatting closing scope, skip to outside the formatting scope.
if (category == BorderingElementCategory.MergeableScopingInline)
{
do
{
navigator.MoveToNextContextPosition(LogicalDirection.Forward);
}
while (GetBorderingElementCategory(navigator, LogicalDirection.Forward) == BorderingElementCategory.MergeableScopingInline);
moved = true;
}
// Skip all InlineUIContainers and BlockUIContainers.
elementType = navigator.GetElementType(LogicalDirection.Forward);
if (elementType == typeof(InlineUIContainer) || elementType == typeof(BlockUIContainer))
{
// We are next to an InlineUIContainer/BlockUIContainer. Skip the following element.
navigator.MoveToNextContextPosition(LogicalDirection.Forward);
navigator.MoveToElementEdge(ElementEdge.AfterEnd);
}
else if (navigator.ParentType == typeof(InlineUIContainer) || navigator.ParentType == typeof(BlockUIContainer))
{
// We are inside an InlineUIContainer/BlockUIContainer. Skip this element.
navigator.MoveToElementEdge(ElementEdge.AfterEnd);
}
else
{
break;
}
// Move to next insertion position if we are done skipping a string of sequential UICs to get a
// valid selection start pointer. We need to make sure we land at a position that would be given
// to this function had the UICs not been there. This ensures that we end up inside Runs that
// follow instead of before them, e.g. </Span><Run>|abc</Run> instead of |</Span><Run>abc</Run>.
elementType = navigator.GetElementType(LogicalDirection.Forward);
if (!(elementType == typeof(InlineUIContainer)) && !(elementType == typeof(BlockUIContainer)))
{
navigator.MoveToNextInsertionPosition(LogicalDirection.Forward);
}
moved = true;
}
if (typeof(Inline).IsAssignableFrom(elementType) && !TextSchema.IsMergeableInline(elementType))
{
// We are adjacent to a nonmergeable inline. Find its content.
// Just skip over all opening contexts.
do
{
navigator.MoveToNextContextPosition(LogicalDirection.Forward);
}
while (navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementStart);
moved = true;
}
return moved ? navigator : null;
}
示例9: GetWordBreakerText
// Initializes an array with the minimum necessary text to support a call to
// SelectionWordBreaker.IsAtWordBoundary.
//
// position on exit holds the offset into the text array corresponding to
// pointer's location in the document.
//
// Called by IsAtWordBoundary.
private static void GetWordBreakerText(ITextPointer pointer, out char[] text, out int position)
{
char[] preceedingText = new char[SelectionWordBreaker.MinContextLength];
char[] followingText = new char[SelectionWordBreaker.MinContextLength];
int preceedingCount = 0;
int followingCount = 0;
int runLength;
ITextPointer navigator;
navigator = pointer.CreatePointer();
// Try to back up SelectionWordBreaker.MinContextLength chars, ignoring formatting.
do
{
runLength = Math.Min(navigator.GetTextRunLength(LogicalDirection.Backward), SelectionWordBreaker.MinContextLength - preceedingCount);
preceedingCount += runLength;
navigator.MoveByOffset(-runLength);
navigator.GetTextInRun(LogicalDirection.Forward, preceedingText, SelectionWordBreaker.MinContextLength - preceedingCount, runLength);
if (preceedingCount == SelectionWordBreaker.MinContextLength)
break;
// Skip over any formatting.
navigator.MoveToInsertionPosition(LogicalDirection.Backward);
}
while (navigator.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text);
navigator.MoveToPosition(pointer);
// Try to advance SelectionWordBreaker.MinContextLength chars, ignoring formatting.
do
{
runLength = Math.Min(navigator.GetTextRunLength(LogicalDirection.Forward), SelectionWordBreaker.MinContextLength - followingCount);
navigator.GetTextInRun(LogicalDirection.Forward, followingText, followingCount, runLength);
followingCount += runLength;
if (followingCount == SelectionWordBreaker.MinContextLength)
break;
navigator.MoveByOffset(runLength);
// Skip over any formatting.
navigator.MoveToInsertionPosition(LogicalDirection.Forward);
}
while (navigator.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text);
// Combine the preceeding and following text into a single array.
text = new char[preceedingCount + followingCount];
Array.Copy(preceedingText, SelectionWordBreaker.MinContextLength - preceedingCount, text, 0, preceedingCount);
Array.Copy(followingText, 0, text, preceedingCount, followingCount);
position = preceedingCount;
}
示例10: IsAtNonMergeableInlineEdge
// Worker for IsAtNonMergeableInlineStart/IsAtNonMergeableInlineEnd.
private static bool IsAtNonMergeableInlineEdge(ITextPointer position, LogicalDirection direction)
{
BorderingElementCategory elementType = GetBorderingElementCategory(position, direction);
if (elementType == BorderingElementCategory.MergeableScopingInline)
{
ITextPointer navigator = position.CreatePointer();
do
{
navigator.MoveToNextContextPosition(direction);
}
while ((elementType = GetBorderingElementCategory(navigator, direction)) == BorderingElementCategory.MergeableScopingInline);
}
return (elementType == BorderingElementCategory.NonMergeableScopingInline);
}
示例11: GetFrozenPointer
// <see cref="System.Windows.Documents.TextPointer.GetFrozenPointer"/>
internal static ITextPointer GetFrozenPointer(ITextPointer thisPointer, LogicalDirection logicalDirection)
{
ITextPointer frozenPointer;
if (thisPointer.IsFrozen && thisPointer.LogicalDirection == logicalDirection)
{
frozenPointer = thisPointer;
}
else
{
frozenPointer = thisPointer.CreatePointer(logicalDirection);
frozenPointer.Freeze();
}
return frozenPointer;
}
示例12: MoveToNextWordBoundary
/// <summary>
/// Moves the navigator in the given direction to a position of the next
/// word boundary.
/// </summary>
/// <param name="thisNavigator">ITextPointer to advance.</param>
/// <param name="movingDirection">
/// Direction to move.
/// </param>
/// <returns></returns>
//
internal static bool MoveToNextWordBoundary(ITextPointer thisNavigator, LogicalDirection movingDirection)
{
int moveCounter = 0;
Invariant.Assert(!thisNavigator.IsFrozen, "Can't reposition a frozen pointer!");
ITextPointer startPosition = thisNavigator.CreatePointer();
while (thisNavigator.MoveToNextInsertionPosition(movingDirection))
{
moveCounter++;
// Need to break the loop for weird case when there is no word break in text content.
// When the word looks too long, consider end of textRun as a word break.
//
if (moveCounter > 64) // 64 was taken as a random number. Probably not big enough though...
{
thisNavigator.MoveToPosition(startPosition);
thisNavigator.MoveToNextContextPosition(movingDirection);
break;
}
if (IsAtWordBoundary(thisNavigator, /*insideWordDirection:*/LogicalDirection.Forward))
{
// Note that we always use Forward direction for word orientation.
break;
}
}
return moveCounter > 0;
}
示例13: GetParagraph
/// <summary>
/// Determine paragraph type at the current TextPointer and
/// create it. Only ListItem elements are considered. Any other
/// content is skipped.
/// </summary>
/// <param name="textPointer">
/// TextPointer at which paragraph is to be created
/// </param>
/// <param name="fEmptyOk">
/// True if empty paragraph is acceptable
/// </param>
/// <returns>
/// BaseParagraph that was created
/// </returns>
protected override BaseParagraph GetParagraph(ITextPointer textPointer, bool fEmptyOk)
{
Invariant.Assert(textPointer is TextPointer);
BaseParagraph paragraph = null;
while (paragraph == null)
{
TextPointerContext runType = textPointer.GetPointerContext(LogicalDirection.Forward);
if (runType == TextPointerContext.ElementStart)
{
TextElement element = ((TextPointer)textPointer).GetAdjacentElementFromOuterPosition(LogicalDirection.Forward);
if (element is ListItem)
{
//
paragraph = new ListItemParagraph(element, StructuralCache);
break;
}
else if (element is List)
{
//
paragraph = new ListParagraph(element, StructuralCache);
break;
}
// Skip all elements, which are not valid list item children
if (((TextPointer)textPointer).IsFrozen)
{
// Need to clone TextPointer before moving it.
textPointer = textPointer.CreatePointer();
}
textPointer.MoveToPosition(element.ElementEnd);
}
else if (runType == TextPointerContext.ElementEnd)
{
// End of list, if the same as Owner of associated element
// Skip content otherwise
if (Element == ((TextPointer)textPointer).Parent)
{
break;
}
if (((TextPointer)textPointer).IsFrozen)
{
// Need to clone TextPointer before moving it.
textPointer = textPointer.CreatePointer();
}
textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
}
else
{
// Skip content
if (((TextPointer)textPointer).IsFrozen)
{
// Need to clone TextPointer before moving it.
textPointer = textPointer.CreatePointer();
}
textPointer.MoveToNextContextPosition(LogicalDirection.Forward);
}
}
if (paragraph != null)
{
StructuralCache.CurrentFormatContext.DependentMax = (TextPointer)textPointer;
}
return paragraph;
}
示例14: GetBoundingRectangles
//-------------------------------------------------------------------
//
// Internal Methods
//
//-------------------------------------------------------------------
#region Internal Methods
/// <summary>
/// Retrieves the bounding rectangles for the text lines of a given range.
/// </summary>
/// <param name="start">Start of range to measure</param>
/// <param name="end">End of range to measure</param>
/// <param name="clipToView">Specifies whether the caller wants the full bounds (false) or the bounds of visible portions
/// of the viewable line only ('true')</param>
/// <param name="transformToScreen">Requests the results in screen coordinates</param>
/// <returns>An array of bounding rectangles for each line or portion of a line within the client area of the text provider.
/// No bounding rectangles will be returned for lines that are empty or scrolled out of view. Note that even though a
/// bounding rectangle is returned the corresponding text may not be visible due to overlapping windows.
/// This will not return null, but may return an empty array.</returns>
internal Rect[] GetBoundingRectangles(ITextPointer start, ITextPointer end, bool clipToView, bool transformToScreen)
{
ITextView textView = GetUpdatedTextView();
if (textView == null)
{
return new Rect[0];
}
// If start/end positions are not in the visible range, move them to the first/last visible positions.
ReadOnlyCollection<TextSegment> textSegments = textView.TextSegments;
if (textSegments.Count > 0)
{
if (!textView.Contains(start) && start.CompareTo(textSegments[0].Start) < 0)
{
start = textSegments[0].Start.CreatePointer(); ;
}
if (!textView.Contains(end) && end.CompareTo(textSegments[textSegments.Count-1].End) > 0)
{
end = textSegments[textSegments.Count - 1].End.CreatePointer();
}
}
if (!textView.Contains(start) || !textView.Contains(end))
{
return new Rect[0];
}
TextRangeAdaptor.MoveToInsertionPosition(start, LogicalDirection.Forward);
TextRangeAdaptor.MoveToInsertionPosition(end, LogicalDirection.Backward);
Rect visibleRect = Rect.Empty;
if (clipToView)
{
visibleRect = GetVisibleRectangle(textView);
// If clipping into view and visible rect is empty, return.
if (visibleRect.IsEmpty)
{
return new Rect[0];
}
}
List<Rect> rectangles = new List<Rect>();
ITextPointer position = start.CreatePointer();
while (position.CompareTo(end) < 0)
{
TextSegment lineRange = textView.GetLineRange(position);
if (!lineRange.IsNull)
{
// Since range is limited to just one line, GetTightBoundingGeometry will return tight bounding
// rectangle for given range. It will also work correctly with bidi text.
ITextPointer first = (lineRange.Start.CompareTo(start) <= 0) ? start : lineRange.Start;
ITextPointer last = (lineRange.End.CompareTo(end) >= 0) ? end : lineRange.End;
Rect lineRect = Rect.Empty;
Geometry geometry = textView.GetTightBoundingGeometryFromTextPositions(first, last);
if (geometry != null)
{
lineRect = geometry.Bounds;
if (clipToView)
{
lineRect.Intersect(visibleRect);
}
if (!lineRect.IsEmpty)
{
if (transformToScreen)
{
lineRect = new Rect(ClientToScreen(lineRect.TopLeft, textView.RenderScope), ClientToScreen(lineRect.BottomRight, textView.RenderScope));
}
rectangles.Add(lineRect);
}
}
}
if (position.MoveToLineBoundary(1) == 0)
{
position = end;
}
}
return rectangles.ToArray();
}
示例15: IsAtNormalizedPosition
internal static bool IsAtNormalizedPosition(ITextPointer position, LogicalDirection direction, bool respectCaretUnitBoundaries)
{
if (!IsAtNormalizedPosition(position, respectCaretUnitBoundaries))
{
return false;
}
//
if (position.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart &&
position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
{
return true;
}
// Check if there is no any formatting tags in the given direction
if (TextSchema.IsFormattingType(position.GetElementType(direction)))
{
position = position.CreatePointer();
while (TextSchema.IsFormattingType(position.GetElementType(direction)))
{
position.MoveToNextContextPosition(direction);
}
if (IsAtNormalizedPosition(position, respectCaretUnitBoundaries))
{
// So there is a possibility to move over formatting tags only
// and reach some insertion position. This means
// that our position was not normalized in the given direction.
return false;
}
}
return true;
}