// Token: 0x06007CED RID: 31981 RVA: 0x0023255C File Offset: 0x0023075C private static FlowDirection GetTextFlowDirection(ITextPointer pointer) { Invariant.Assert(pointer != null, "Null pointer passed."); Invariant.Assert(pointer.IsAtInsertionPosition, "Pointer is not an insertion position"); int num = 0; LogicalDirection logicalDirection = pointer.LogicalDirection; TextPointerContext pointerContext = pointer.GetPointerContext(logicalDirection); FlowDirection result; if ((pointerContext == TextPointerContext.ElementEnd || pointerContext == TextPointerContext.ElementStart) && !TextSchema.IsFormattingType(pointer.ParentType)) { result = (FlowDirection)pointer.GetValue(FrameworkElement.FlowDirectionProperty); } else { Rect anchorRectangle = TextSelectionHelper.GetAnchorRectangle(pointer); ITextPointer textPointer = pointer.GetNextInsertionPosition(logicalDirection); if (textPointer != null) { textPointer = textPointer.CreatePointer((logicalDirection == LogicalDirection.Backward) ? LogicalDirection.Forward : LogicalDirection.Backward); if (logicalDirection == LogicalDirection.Forward) { if (pointerContext == TextPointerContext.ElementEnd && textPointer.GetPointerContext(textPointer.LogicalDirection) == TextPointerContext.ElementStart) { return((FlowDirection)pointer.GetValue(FrameworkElement.FlowDirectionProperty)); } } else if (pointerContext == TextPointerContext.ElementStart && textPointer.GetPointerContext(textPointer.LogicalDirection) == TextPointerContext.ElementEnd) { return((FlowDirection)pointer.GetValue(FrameworkElement.FlowDirectionProperty)); } Rect anchorRectangle2 = TextSelectionHelper.GetAnchorRectangle(textPointer); if (anchorRectangle2 != Rect.Empty && anchorRectangle != Rect.Empty) { num = Math.Sign(anchorRectangle2.Left - anchorRectangle.Left); if (logicalDirection == LogicalDirection.Backward) { num = -num; } } } if (num == 0) { result = (FlowDirection)pointer.GetValue(FrameworkElement.FlowDirectionProperty); } else { result = ((num > 0) ? FlowDirection.LeftToRight : FlowDirection.RightToLeft); } } return(result); }
// Token: 0x06003C71 RID: 15473 RVA: 0x00117698 File Offset: 0x00115898 internal static Color GetColor(UnsafeNativeMethods.TF_DA_COLOR dacolor, ITextPointer position) { if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_SYSCOLOR) { return(TextServicesDisplayAttribute.GetSystemColor(dacolor.indexOrColorRef)); } if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_COLORREF) { int indexOrColorRef = dacolor.indexOrColorRef; uint num = (uint)TextServicesDisplayAttribute.FromWin32Value(indexOrColorRef); return(Color.FromArgb((byte)((num & 4278190080U) >> 24), (byte)((num & 16711680U) >> 16), (byte)((num & 65280U) >> 8), (byte)(num & 255U))); } Invariant.Assert(position != null, "position can't be null"); return(((SolidColorBrush)position.GetValue(TextElement.ForegroundProperty)).Color); }
/// <summary> /// Convert TF_DA_COLOR to Color. /// </summary> internal static Color GetColor(UnsafeNativeMethods.TF_DA_COLOR dacolor, ITextPointer position) { if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_SYSCOLOR) { return(GetSystemColor(dacolor.indexOrColorRef)); } else if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_COLORREF) { int color = dacolor.indexOrColorRef; uint argb = (uint)FromWin32Value(color); return(Color.FromArgb((byte)((argb & 0xff000000) >> 24), (byte)((argb & 0x00ff0000) >> 16), (byte)((argb & 0x0000ff00) >> 8), (byte)(argb & 0x000000ff))); } Invariant.Assert(position != null, "position can't be null"); return(((SolidColorBrush)position.GetValue(TextElement.ForegroundProperty)).Color); }
// Writes a collection of attributes representing non-inheritable properties // whose values are set inline on the given element instance. // When we read properties fromContext we want all values including defaults; from text elements we only want only affected private static void WriteNoninheritableProperties(Type elementTypeStandardized, ITextPointer context, XmlWriter xmlWriter, bool onlyAffected, DependencyObject complexProperties) { DependencyProperty[] elementProperties = TextSchema.GetNoninheritableProperties(elementTypeStandardized); // We'll need a pointer to walk the tree up when onlyAffected=false ITextPointer parentContext = onlyAffected ? null : context.CreatePointer(); for (int i = 0; i < elementProperties.Length; i++) { DependencyProperty property = elementProperties[i]; Type propertyOwnerType = context.ParentType; object propertyValue; if (onlyAffected) { // propertyValue = context.GetValue(property); } else { // This is request for contextual properties - use "manual" inheritance to collect values Invariant.Assert(elementTypeStandardized == typeof(Span), "Request for contextual properties is expected for Span wrapper only"); // Get property value from this element or from one of its ancestors (the latter in case of !onlyAffeted) propertyValue = context.GetValue(property); // Get property value from its ancestors if the property is not set. // TextDecorationCollection is special-cased as its default is empty collection, // and its value source cannot be distinguished from ITextPointer. if (propertyValue == null || TextDecorationCollection.Empty.ValueEquals(propertyValue as TextDecorationCollection)) { if (property == Inline.BaselineAlignmentProperty || property == TextElement.TextEffectsProperty) { // These properties do not make sense as contextual; do not include them into context. continue; } parentContext.MoveToPosition(context); while ((propertyValue == null || TextDecorationCollection.Empty.ValueEquals(propertyValue as TextDecorationCollection)) && typeof(Inline).IsAssignableFrom(parentContext.ParentType)) { parentContext.MoveToElementEdge(ElementEdge.BeforeStart); propertyValue = parentContext.GetValue(property); propertyOwnerType = parentContext.ParentType; } } } // if ((property == Block.MarginProperty && (typeof(Paragraph).IsAssignableFrom(propertyOwnerType) || typeof(List).IsAssignableFrom(propertyOwnerType))) || (property == Block.PaddingProperty) && typeof(List).IsAssignableFrom(propertyOwnerType)) { Thickness thickness = (Thickness)propertyValue; if (Paragraph.IsMarginAuto(thickness)) { continue; } } // Write the property as attribute string or add it to a list of complex properties. WriteNoninheritableProperty(xmlWriter, property, propertyValue, propertyOwnerType, onlyAffected, complexProperties, context.ReadLocalValue(property)); } }
// 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); } } } }
// Verify that a pointer is an acceptable ancestor. Some types can't be ancestors at all, while // non-typographic-only elements are unacceptable if the range being serialized does not include the // element's start and end (because we don't want to serialize properties on such an element). private static bool IsAcceptableAncestor(ITextPointer commonAncestor, ITextRange range) { if (typeof(TableRow).IsAssignableFrom(commonAncestor.ParentType) || typeof(TableRowGroup).IsAssignableFrom(commonAncestor.ParentType) || typeof(Table).IsAssignableFrom(commonAncestor.ParentType) || typeof(BlockUIContainer).IsAssignableFrom(commonAncestor.ParentType) || typeof(List).IsAssignableFrom(commonAncestor.ParentType) || typeof(Inline).IsAssignableFrom(commonAncestor.ParentType) && TextSchema.HasTextDecorations(commonAncestor.GetValue(Inline.TextDecorationsProperty))) { return false; } // We don't want to use any formatting from within a non-typographic-only element unless the entire // element is selected (in which case, the ancestor candidate will already be outside that element. // If there is such an element ANYWHERE in the ancestry, the only acceptable // ancestor is outside the outermost such element. ITextPointer navigator = commonAncestor.CreatePointer(); while (typeof(TextElement).IsAssignableFrom(navigator.ParentType)) { TextElementEditingBehaviorAttribute behaviorAttribute = (TextElementEditingBehaviorAttribute)Attribute.GetCustomAttribute(navigator.ParentType, typeof(TextElementEditingBehaviorAttribute)); if (behaviorAttribute != null && !behaviorAttribute.IsTypographicOnly) { return false; } navigator.MoveToElementEdge(ElementEdge.BeforeStart); } return true; }
/// A handler for an event reporting that the drag over during drag-and-drop operation. internal void TargetOnDragOver(DragEventArgs e) { if (!AllowDragDrop(e)) { return; } // Ok, there's data to move or copy here. if ((e.AllowedEffects & DragDropEffects.Move) != 0) { e.Effects = DragDropEffects.Move; } bool ctrlKeyDown = ((int)(e.KeyStates & DragDropKeyStates.ControlKey) != 0); if (ctrlKeyDown) { e.Effects |= DragDropEffects.Copy; } // Show the caret on the drag over target position. if (_caretDragDrop != null) { // Update the layout to get the corrected text position. Otherwise, we can get the // incorrected text position. if (!_textEditor.TextView.Validate(e.GetPosition(_textEditor.TextView.RenderScope))) { return; } // Find the scroller from the render scope FrameworkElement scroller = _textEditor._Scroller; // Automatically scroll the dropable content(line or page up/down) if scroller is available if (scroller != null) { // Get the ScrollInfo to scroll a line or page up/down IScrollInfo scrollInfo = scroller as IScrollInfo; if (scrollInfo == null && scroller is ScrollViewer) { scrollInfo = ((ScrollViewer)scroller).ScrollInfo; } Invariant.Assert(scrollInfo != null); // Takes care of scrolling mechanism when vertical scrollbar is available, it creates a virtual // block within the viewport where if you position your mouse during drag leads to scrolling,here // it is of 16pixels and within first 8pixels it does scrolling by line and for next it scrolls by page. Point pointScroller = e.GetPosition((IInputElement)scroller); double pageHeight = (double)_textEditor.UiScope.GetValue(TextEditor.PageHeightProperty); double slowAreaHeight = ScrollViewer._scrollLineDelta; if (pointScroller.Y < slowAreaHeight) { // Drag position is on the scroll area that we need to scroll up if (pointScroller.Y > slowAreaHeight / 2) { // scroll a line up scrollInfo.LineUp(); } else { // scroll a page up scrollInfo.PageUp(); } } else if (pointScroller.Y > (pageHeight - slowAreaHeight)) { // Drag position is on the scroll area that we need to scroll down if (pointScroller.Y < (pageHeight - slowAreaHeight / 2)) { // scroll a line down scrollInfo.LineDown(); } else { // scroll a page down scrollInfo.PageDown(); } } } // Get the current text position from the dropable mouse point. _textEditor.TextView.RenderScope.UpdateLayout(); // REVIEW:benwest:6/27/2006: This should use TextView.Validate, and check the return value instead of using IsValid below. if (_textEditor.TextView.IsValid) { ITextPointer dragPosition = GetDropPosition(_textEditor.TextView.RenderScope as Visual, e.GetPosition(_textEditor.TextView.RenderScope)); if (dragPosition != null) { // Get the caret position to show the dropable point. Rect caretRectangle = this.TextView.GetRectangleFromTextPosition(dragPosition); // NOTE: We DO NOT use GetCurrentValue because springload formatting should NOT be involved for drop caret. object fontStylePropertyValue = dragPosition.GetValue(TextElement.FontStyleProperty); bool italic = (_textEditor.AcceptsRichContent && fontStylePropertyValue != DependencyProperty.UnsetValue && (FontStyle)fontStylePropertyValue == FontStyles.Italic); Brush caretBrush = TextSelection.GetCaretBrush(_textEditor); // Show the caret on the dropable position. _caretDragDrop.Update(/*visible:*/ true, caretRectangle, caretBrush, 0.5, italic, CaretScrollMethod.None, /*wordWrappingPosition*/ double.NaN); } } } }
// Token: 0x060085BC RID: 34236 RVA: 0x0024A7EC File Offset: 0x002489EC internal void TargetOnDragOver(DragEventArgs e) { if (!this.AllowDragDrop(e)) { return; } if ((e.AllowedEffects & DragDropEffects.Move) != DragDropEffects.None) { e.Effects = DragDropEffects.Move; } bool flag = (e.KeyStates & DragDropKeyStates.ControlKey) > DragDropKeyStates.None; if (flag) { e.Effects |= DragDropEffects.Copy; } if (this._caretDragDrop != null) { if (!this._textEditor.TextView.Validate(e.GetPosition(this._textEditor.TextView.RenderScope))) { return; } FrameworkElement scroller = this._textEditor._Scroller; if (scroller != null) { IScrollInfo scrollInfo = scroller as IScrollInfo; if (scrollInfo == null && scroller is ScrollViewer) { scrollInfo = ((ScrollViewer)scroller).ScrollInfo; } Invariant.Assert(scrollInfo != null); Point position = e.GetPosition(scroller); double num = (double)this._textEditor.UiScope.GetValue(TextEditor.PageHeightProperty); double num2 = 16.0; if (position.Y < num2) { if (position.Y > num2 / 2.0) { scrollInfo.LineUp(); } else { scrollInfo.PageUp(); } } else if (position.Y > num - num2) { if (position.Y < num - num2 / 2.0) { scrollInfo.LineDown(); } else { scrollInfo.PageDown(); } } } this._textEditor.TextView.RenderScope.UpdateLayout(); if (this._textEditor.TextView.IsValid) { ITextPointer dropPosition = this.GetDropPosition(this._textEditor.TextView.RenderScope, e.GetPosition(this._textEditor.TextView.RenderScope)); if (dropPosition != null) { Rect rectangleFromTextPosition = this.TextView.GetRectangleFromTextPosition(dropPosition); object value = dropPosition.GetValue(TextElement.FontStyleProperty); bool italic = this._textEditor.AcceptsRichContent && value != DependencyProperty.UnsetValue && (FontStyle)value == FontStyles.Italic; Brush caretBrush = TextSelection.GetCaretBrush(this._textEditor); this._caretDragDrop.Update(true, rectangleFromTextPosition, caretBrush, 0.5, italic, CaretScrollMethod.None, double.NaN); } } } }
/// <summary> /// </summary> void ITextSelection.SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace) { // We need a pointer with appropriate direction, // becasue it will be used in textRangeBase.Select method for // pointer normalization. caretPosition = caretPosition.CreatePointer(direction); // Normalize the position in its logical direction - to get to text content over there. caretPosition.MoveToInsertionPosition(direction); // We need a pointer with the reverse direction to confirm // the line wrapping position. So we can ensure Bidi caret navigation. // Bidi can have the different caret position by setting the // logical direction, so we have to only set the logical direction // as the forward for the real line wrapping position. ITextPointer reversePosition = caretPosition.CreatePointer(direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward); // Check line wrapping condition if (!allowStopAtLineEnd && ((TextPointerBase.IsAtLineWrappingPosition(caretPosition, this.TextView) && TextPointerBase.IsAtLineWrappingPosition(reversePosition, this.TextView)) || TextPointerBase.IsNextToPlainLineBreak(caretPosition, LogicalDirection.Backward) || TextSchema.IsBreak(caretPosition.GetElementType(LogicalDirection.Backward)))) { // Caret is at wrapping position, and we are not allowed to stay at end of line, // so we choose forward direction to appear in the begiinning of a second line caretPosition.SetLogicalDirection(LogicalDirection.Forward); } else { if (caretPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.Text && caretPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text) { // This is statistically most typical case. No "smartness" needed // to choose standard Forward orientation for the caret. // NOTE: By using caretPosition's direction we solve BiDi caret orientation case: // The orietnation reflects a direction from where caret has been moved // or orientation where mouse clicked. So we will stick with appropriate // character. // Nothing to do. The caretPosition is good to go. } else if (!allowStopNearSpace) { // There are some tags around, and we are not allowed to choose a side near to space. // So we need to perform some content analysis. char[] charBuffer = new char[1]; if (caretPosition.GetPointerContext(direction) == TextPointerContext.Text && caretPosition.GetTextInRun(direction, charBuffer, 0, 1) == 1 && Char.IsWhiteSpace(charBuffer[0])) { LogicalDirection oppositeDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward; // Check formatting switch condition at this position FlowDirection initialFlowDirection = (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty); bool moved = caretPosition.MoveToInsertionPosition(oppositeDirection); if (moved && initialFlowDirection == (FlowDirection)caretPosition.GetValue(FrameworkElement.FlowDirectionProperty) && (caretPosition.GetPointerContext(oppositeDirection) != TextPointerContext.Text || caretPosition.GetTextInRun(oppositeDirection, charBuffer, 0, 1) != 1 || !Char.IsWhiteSpace(charBuffer[0]))) { // In the opposite direction we have a non-space // character. So we choose that direction direction = oppositeDirection; caretPosition.SetLogicalDirection(direction); } } } } // Now that orientation of a caretPosition is identified, // build an empty selection at this position TextRangeBase.BeginChange(this); try { TextRangeBase.Select(this, caretPosition, caretPosition); // Note how Select method works for the case of empty range: // It creates a single instance TextPointer normalized and oriented // in a direction taken from caretPosition: ITextSelection thisSelection = this; Invariant.Assert(thisSelection.Start.LogicalDirection == caretPosition.LogicalDirection); // orientation must be as passed Invariant.Assert(this.IsEmpty); //Invariant.Assert((object)thisSelection.Start == (object)thisSelection.End); // it must be the same instance of TextPointer //Invariant.Assert(TextPointerBase.IsAtInsertionPosition(thisSelection.Start, caretPosition.LogicalDirection)); // normalization must be done in the same diredction as orientation // Clear active positions when selection is empty SetActivePositions(null, null); } finally { TextRangeBase.EndChange(this); } }
// Helper for MoveSelectionByMouse private bool ShouldSelectEmbeddedObject(ITextPointer cursorPosition, Point cursorMousePoint, Rect objectEdgeRect) { // Although we now know that cursorPosition is facing an embedded object, // we still need an additional test to determine if the original mouse point // fell within the object or outside it's bouding box (which can happen when // a mouse click is snapped to the nearest content). // If the mouse point is outside the object, we don't want to select it. if (!objectEdgeRect.IsEmpty && cursorMousePoint.Y >= objectEdgeRect.Y && cursorMousePoint.Y < objectEdgeRect.Y + objectEdgeRect.Height) { // Compare X coordinates of mouse down point and object edge rect, // depending on the FlowDirection of the render scope and paragraph content. FlowDirection renderScopeFlowDirection = (FlowDirection)this.TextView.RenderScope.GetValue(Block.FlowDirectionProperty); FlowDirection paragraphFlowDirection = (FlowDirection)cursorPosition.GetValue(Block.FlowDirectionProperty); if (renderScopeFlowDirection == FlowDirection.LeftToRight) { if (paragraphFlowDirection == FlowDirection.LeftToRight && (cursorPosition.LogicalDirection == LogicalDirection.Forward && objectEdgeRect.X < cursorMousePoint.X || cursorPosition.LogicalDirection == LogicalDirection.Backward && cursorMousePoint.X < objectEdgeRect.X)) { return true; } else if (paragraphFlowDirection == FlowDirection.RightToLeft && (cursorPosition.LogicalDirection == LogicalDirection.Forward && objectEdgeRect.X > cursorMousePoint.X || cursorPosition.LogicalDirection == LogicalDirection.Backward && cursorMousePoint.X > objectEdgeRect.X)) { return true; } } else { if (paragraphFlowDirection == FlowDirection.LeftToRight && (cursorPosition.LogicalDirection == LogicalDirection.Forward && objectEdgeRect.X > cursorMousePoint.X || cursorPosition.LogicalDirection == LogicalDirection.Backward && cursorMousePoint.X > objectEdgeRect.X)) { return true; } else if (paragraphFlowDirection == FlowDirection.RightToLeft && (cursorPosition.LogicalDirection == LogicalDirection.Forward && objectEdgeRect.X < cursorMousePoint.X || cursorPosition.LogicalDirection == LogicalDirection.Backward && cursorMousePoint.X < objectEdgeRect.X)) { return true; } } } return false; }
// Returns the CultureInfo of the content at a position. // Returns null if there is no CultureInfo matching the current XmlLanguage. private CultureInfo GetCurrentCultureAndLanguage(ITextPointer position, out XmlLanguage language) { CultureInfo cultureInfo; bool hasModifiers; // TextBox takes the input language iff no local LanguageProperty is set. if (!_textEditor.AcceptsRichContent && _textEditor.UiScope.GetValueSource(FrameworkElement.LanguageProperty, null, out hasModifiers) == BaseValueSourceInternal.Default) { cultureInfo = _defaultCulture; language = XmlLanguage.GetLanguage(cultureInfo.IetfLanguageTag); } else { language = (XmlLanguage)position.GetValue(FrameworkElement.LanguageProperty); if (language == null) { cultureInfo = null; } else { try { cultureInfo = language.GetSpecificCulture(); } catch (InvalidOperationException) { // Someone set a bogus language on the run. cultureInfo = null; } } } return cultureInfo; }
// Gets a non-inherited property from a given position private static object GetCharacterValueFromPosition(ITextPointer pointer, DependencyProperty formattingProperty) { object value = null; if (formattingProperty != Inline.TextDecorationsProperty) { value = pointer.GetValue(formattingProperty); } else { if (pointer is TextPointer) // Implement only for concrete TextCotainer returning null otherwise - for optimization { DependencyObject element = ((TextPointer)pointer).Parent as TextElement; while (value == null && (element is Inline || element is Paragraph || element is TextBlock)) { value = element.GetValue(formattingProperty); element = element is TextElement ? ((TextElement)element).Parent : null; } } } return value; }
/// <summary> /// Retrieves FontFamily name. /// </summary> private static string GetFontFamilyName(FontFamily fontFamily, ITextPointer context) { if (fontFamily != null) { // Typical case: return the family name/URI used to construct the FontFamily. if (fontFamily.Source != null) return fontFamily.Source; // Use the target font specified by the first family map with a compatible language. if (fontFamily.FamilyMaps != null) { XmlLanguage textLanguage = (context != null) ? (XmlLanguage)context.GetValue(FrameworkElement.LanguageProperty) : null; foreach (FontFamilyMap familyMap in fontFamily.FamilyMaps) { // A language-neutral family map matches any text language. if (familyMap.Language == null) return familyMap.Target; // Does the language match the text culture or a parent culture? if (textLanguage != null && familyMap.Language.RangeIncludes(textLanguage)) return familyMap.Target; } } } // Worst case: we have to return something so just return a default family name. return _defaultFamilyName; }
//----------------------------------------------------- // // Static Methods // //------------------------------------------------------ #region Static Methods /// <summary> /// Determine the flow direction of the character referred to by the TextPointer. /// If the context of the pointer is not text, we use the FlowDirection of the /// containing element. /// </summary> /// <param name="pointer">pointer to get flow direction for</param> /// <returns>positive value means LeftToRight, negative value means RightToLeft</returns> private static FlowDirection GetTextFlowDirection(ITextPointer pointer) { Invariant.Assert(pointer != null, "Null pointer passed."); Invariant.Assert(pointer.IsAtInsertionPosition, "Pointer is not an insertion position"); int sign = 0; FlowDirection flowDirection; LogicalDirection direction = pointer.LogicalDirection; TextPointerContext currentContext = pointer.GetPointerContext(direction); if ((currentContext == TextPointerContext.ElementEnd || currentContext == TextPointerContext.ElementStart) && !TextSchema.IsFormattingType(pointer.ParentType)) { // If the current pointer (with its current direction) is at the start or end of a paragraph, // the next insertion position will be in a separate paragraph. We can't determine direction // based on the pointer rects in that case so we use the direction of the Paragraph. flowDirection = (FlowDirection)pointer.GetValue(FlowDirectionProperty); } else { // We get the rects before and after the character following the current // pointer and determine that character's flow direction based on the x-values // of the rects. Because we use direction when requesting a rect, we should // always get rects that are on the same line (except for the case above) // Forward gravity for leading edge Rect current = TextSelectionHelper.GetAnchorRectangle(pointer); // Get insertion position after the current pointer ITextPointer nextPointer = pointer.GetNextInsertionPosition(direction); // There may be no more insertion positions in this document if (nextPointer != null) { // Backward gravity for trailing edge nextPointer = nextPointer.CreatePointer(direction == LogicalDirection.Backward ? LogicalDirection.Forward : LogicalDirection.Backward); // Special case - for pointers at the end of a paragraph // Actually the pointer is the last insertion position in the paragraph and the next insertion position is the first // in the next paragraph. We handle this by detecting that the two pointers only have markup between them. If the // markup was only formatting, there would also be content (because insertion position would move past a character). if (direction == LogicalDirection.Forward) { if (currentContext == TextPointerContext.ElementEnd && nextPointer.GetPointerContext(nextPointer.LogicalDirection) == TextPointerContext.ElementStart) { return (FlowDirection)pointer.GetValue(FlowDirectionProperty); } } else { if (currentContext == TextPointerContext.ElementStart && nextPointer.GetPointerContext(nextPointer.LogicalDirection) == TextPointerContext.ElementEnd) { return (FlowDirection)pointer.GetValue(FlowDirectionProperty); } } Rect next = TextSelectionHelper.GetAnchorRectangle(nextPointer); // Calculate the difference in x-coordinate between the two rects if (next != Rect.Empty && current != Rect.Empty) { sign = Math.Sign(next.Left - current.Left); // If we are looking at the character before the current pointer, // we swap the difference since "next" was actually before "current" if (direction == LogicalDirection.Backward) { sign = -(sign); } } } // If the rects were at the same x-coordinate or we couldn't get rects // at all, we simply use the FlowDirection at that pointer. if (sign == 0) { flowDirection = (FlowDirection)pointer.GetValue(FlowDirectionProperty); } else { // Positive is left to right, negative is right to left flowDirection = (sign > 0 ? FlowDirection.LeftToRight : FlowDirection.RightToLeft); } } return flowDirection; }
/// <summary> /// Returns a moving position and the suggestedX value for it. /// </summary> /// <param name="This">TextEditor</param> /// <param name="innerMovingPosition">Inner moving position if it has valid layout, otherwise null.</param> /// <returns>Returns suggestedX when moving position has valid layout, Double.NaN otherwise.</returns> private static Double GetSuggestedX(TextEditor This, out ITextPointer innerMovingPosition) { // When getting moving position, we need to take care of end-of-line case // and adjust moving position according to its orientation. innerMovingPosition = TextEditorSelection.GetMovingPositionInner(This); // We need a non-dirty layout to walk pages. if (!innerMovingPosition.ValidateLayout()) { innerMovingPosition = null; return Double.NaN; // This value is not supposed to be used by a caller. } if (Double.IsNaN(This._suggestedX)) { This._suggestedX = GetAbsoluteXOffset(This.TextView, innerMovingPosition); // If the original moving position is on the other side of a line break, // add in the pixel width of the line break visualization. // Note this logic implicitly only modifies suggested x when the // selection is non-empty. if (This.Selection.MovingPosition.CompareTo(innerMovingPosition) > 0) { double breakWidth = (double)innerMovingPosition.GetValue(TextElement.FontSizeProperty) * CaretElement.c_endOfParaMagicMultiplier; FlowDirection paragraphFlowDirection = GetScopingParagraphFlowDirection(innerMovingPosition); FlowDirection controlFlowDirection = This.UiScope.FlowDirection; if (paragraphFlowDirection != controlFlowDirection) { // Adjust for X-axis flip on Paragraphs with non-default flow direction. breakWidth = -breakWidth; } This._suggestedX += breakWidth; } } return This._suggestedX; }
/// <summary> /// Convert TF_DA_COLOR to Color. /// </summary> internal static Color GetColor(UnsafeNativeMethods.TF_DA_COLOR dacolor, ITextPointer position) { if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_SYSCOLOR) { return GetSystemColor(dacolor.indexOrColorRef); } else if (dacolor.type == UnsafeNativeMethods.TF_DA_COLORTYPE.TF_CT_COLORREF) { int color = dacolor.indexOrColorRef; uint argb = (uint)FromWin32Value(color); return Color.FromArgb((byte)((argb & 0xff000000) >> 24), (byte)((argb & 0x00ff0000) >> 16), (byte)((argb & 0x0000ff00) >> 8), (byte)(argb & 0x000000ff)); } Invariant.Assert(position != null, "position can't be null"); return ((SolidColorBrush)position.GetValue(TextElement.ForegroundProperty)).Color; }