Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Documents / TextElement.cs / 1 / TextElement.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: Base class for content in text based FrameworkElement. // // History: // 07/2003 : grzegorz - Created // 02/18/2004: benwest - new TOM method implementation for TextContainer rewrite. // 10/28/2004 : grzegorz - ContentElements refactoring. // //--------------------------------------------------------------------------- // Enable presharp pragma warning suppress directives. #pragma warning disable 1634, 1691 using System.Collections; using System.ComponentModel; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using MS.Internal; using MS.Internal.PresentationFramework; using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS restrictions using MS.Internal.Text; namespace System.Windows.Documents { ////// TextElement is an base class for content in text based FrameworkElement /// controls such as Text, FlowDocument, or RichTextBox. TextElements span /// other content, applying property values or providing structural information. /// ////// public abstract class TextElement : FrameworkContentElement, IAddChild { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors static TextElement() { // For attached properties metadata specific to the type needs to be set using OverrideMetadata // instead of passing it during property registration. Otherwise all types will get it. PropertyChangedCallback typographyChanged = new PropertyChangedCallback(OnTypographyChanged); // Registering typography properties metadata DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; for (int i = 0; i < typographyProperties.Length; i++) { typographyProperties[i].OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); } } ////// Internal constructor to prevent publicly derived classes. /// internal TextElement() : base() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Extracts this TextElement from its current position, if any, and /// inserts it at a specified location. /// /// /// New start position. /// /// /// New end position. /// ////// Throws an ArgumentException if start and end are not /// positioned within the same document, or if start is positioned /// after end, or if start == null but end != null. /// ////// This method extracts the TextElement from its current position, /// leaving behind any contained content, before inserting the TextElement /// at a new location. /// /// If start is null, end must also be null, and the TextElement will /// not be inserted into a new document. /// internal void Reposition(TextPointer start, TextPointer end) { TextContainer tree; if (start != null) { ValidationHelper.VerifyPositionPair(start, end); } else if (end != null) { throw new ArgumentException(SR.Get(SRID.TextElement_UnmatchedEndPointer)); } if (start != null) { // start/end must be equally scoped. But we want to discount // this TextElement when considering scoping -- it will be // extracted before the final insert. SplayTreeNode startNode = start.GetScopingNode(); // Suppress presharp 6506: Parameter 'end' to this public method must be validated. // We already validated it indirectly above, when calling ValidationHelper.VerifyPositionPair. #pragma warning suppress 6506 SplayTreeNode endNode = end.GetScopingNode(); if (startNode == _textElementNode) { startNode = _textElementNode.GetContainingNode(); } if (endNode == _textElementNode) { endNode = _textElementNode.GetContainingNode(); } if (startNode != endNode) { throw new ArgumentException(SR.Get(SRID.InDifferentScope, "start", "end")); } } if (this.IsInTree) { tree = EnsureTextContainer(); if (start == null) { // // Case 0: Extract this element from its tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); } finally { tree.EndChange(); } } else { // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 6506 if (tree == start.TextContainer) { // // Case 1: extract and insert this TextElement within the same tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); tree.InsertElementInternal(start, end, this); } finally { tree.EndChange(); } } else { // // Case 2: extract and insert this TextElement from one tree to another tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); } finally { tree.EndChange(); } // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 56506 start.TextContainer.BeginChange(); try { start.TextContainer.InsertElementInternal(start, end, this); } finally { start.TextContainer.EndChange(); } } } } else if (start != null) { // // Case 3: insert this TextElement to a new tree (this is no current tree). // start.TextContainer.BeginChange(); try { start.TextContainer.InsertElementInternal(start, end, this); } finally { start.TextContainer.EndChange(); } } } ////// Extracts this TextElement and its content from its current /// position, if any, and inserts it at a specified location. /// /// /// New position. /// ////// This method extracts the TextElement from its current position, /// including any contained content, before inserting the TextElement /// at a new location. /// /// If textPosition is null, the TextElement will not be inserted into /// a new document. /// internal void RepositionWithContent(TextPointer textPosition) { TextContainer tree; if (textPosition == null) { if (this.IsInTree) { tree = EnsureTextContainer(); // Presharp doesn't understand that by design EnsureTextContainer can never return null. #pragma warning suppress 6506 tree.BeginChange(); try { tree.DeleteContentInternal(this.ElementStart, this.ElementEnd); } finally { tree.EndChange(); } } } else { tree = textPosition.TextContainer; // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 56506 tree.BeginChange(); try { tree.InsertElementInternal(textPosition, textPosition, this); } finally { tree.EndChange(); } } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties internal static readonly UncommonFieldContainerTextElementField = new UncommonField (); /// /// A TextRange spanning the content of this element. /// internal TextRange TextRange { get { VerifyAccess(); TextContainer tree = EnsureTextContainer(); TextPointer contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward); contentStart.Freeze(); TextPointer contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward); contentEnd.Freeze(); return new TextRange(contentStart, contentEnd); } } ////// A TextPointer located just before the start edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Forward. /// public TextPointer ElementStart { get { TextContainer tree; TextPointer elementStart; tree = EnsureTextContainer(); elementStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward); elementStart.Freeze(); return elementStart; } } internal StaticTextPointer StaticElementStart { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, 0); } } ////// A TextPointer located just past the start edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Backward. /// public TextPointer ContentStart { get { TextContainer tree; TextPointer contentStart; tree = EnsureTextContainer(); contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward); contentStart.Freeze(); return contentStart; } } internal StaticTextPointer StaticContentStart { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, 1); } } ////// A TextPointer located just before the end edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Forward. /// public TextPointer ContentEnd { get { TextContainer tree; TextPointer contentEnd; tree = EnsureTextContainer(); contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward); contentEnd.Freeze(); return contentEnd; } } internal StaticTextPointer StaticContentEnd { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount - 1); } } // Returns true if a position belongs to inner part of this TextElement (ContentStart and ContentEnd including). internal bool Contains(TextPointer position) { TextContainer tree = EnsureTextContainer(); ValidationHelper.VerifyPosition(tree, position); return this.ContentStart.CompareTo(position) <= 0 && this.ContentEnd.CompareTo(position) >= 0; } ////// A TextPointer located just after the end edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Backward. /// public TextPointer ElementEnd { get { TextContainer tree; TextPointer elementEnd; tree = EnsureTextContainer(); elementEnd = new TextPointer(tree, _textElementNode, ElementEdge.AfterEnd, LogicalDirection.Backward); elementEnd.Freeze(); return elementEnd; } } internal StaticTextPointer StaticElementEnd { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount); } } #region DependencyProperties ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.RegisterAttached( "FontFamily", typeof(FontFamily), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontFamily, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), new ValidateValueCallback(IsValidFontFamily)); ///property. /// /// The FontFamily property specifies the name of font family. /// [Localizability( LocalizationCategory.Font, Modifiability = Modifiability.Unmodifiable )] public FontFamily FontFamily { get { return (FontFamily) GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontFamily(DependencyObject element, FontFamily value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontFamilyProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontFamily GetFontFamily(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontFamily)element.GetValue(FontFamilyProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontStyleProperty = DependencyProperty.RegisterAttached( "FontStyle", typeof(FontStyle), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontStyle, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontStyle property requests normal, italic, and oblique faces within a font family. /// public FontStyle FontStyle { get { return (FontStyle) GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontStyle(DependencyObject element, FontStyle value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontStyleProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontStyle GetFontStyle(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontStyle)element.GetValue(FontStyleProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontWeightProperty = DependencyProperty.RegisterAttached( "FontWeight", typeof(FontWeight), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontWeight, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontWeight property specifies the weight of the font. /// public FontWeight FontWeight { get { return (FontWeight) GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontWeight(DependencyObject element, FontWeight value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontWeightProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontWeight GetFontWeight(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontWeight)element.GetValue(FontWeightProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontStretchProperty = DependencyProperty.RegisterAttached( "FontStretch", typeof(FontStretch), typeof(TextElement), new FrameworkPropertyMetadata( FontStretches.Normal, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontStretch property selects a normal, condensed, or extended face from a font family. /// public FontStretch FontStretch { get { return (FontStretch) GetValue(FontStretchProperty); } set { SetValue(FontStretchProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontStretch(DependencyObject element, FontStretch value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontStretchProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontStretch GetFontStretch(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontStretch)element.GetValue(FontStretchProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached( "FontSize", typeof(double), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontSize, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), new ValidateValueCallback(IsValidFontSize)); ///property. /// /// The FontSize property specifies the size of the font. /// [TypeConverter(typeof(FontSizeConverter))] [Localizability(LocalizationCategory.None)] public double FontSize { get { return (double) GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontSize(DependencyObject element, double value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontSizeProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. [TypeConverter(typeof(FontSizeConverter))] public static double GetFontSize(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (double)element.GetValue(FontSizeProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached( "Foreground", typeof(Brush), typeof(TextElement), new FrameworkPropertyMetadata( Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The Foreground property specifies the foreground brush of an element's text content. /// public Brush Foreground { get { return (Brush) GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetForeground(DependencyObject element, Brush value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(ForegroundProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static Brush GetForeground(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (Brush)element.GetValue(ForegroundProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(TextElement), new FrameworkPropertyMetadata((Brush)null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The Background property defines the brush used to fill the content area. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextEffectsProperty = DependencyProperty.Register( "TextEffects", typeof(TextEffectCollection), typeof(TextElement), new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(TextEffectCollection.Empty), FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// It doesn't affect layout /// /// The TextEffects property specifies effects that are added to the text of an element. /// public TextEffectCollection TextEffects { get { return (TextEffectCollection) GetValue(TextEffectsProperty); } set { SetValue(TextEffectsProperty, value); } } ////// Class providing access to all text typography properties /// public Typography Typography { get { return new Typography(this); } } #endregion DependencyProperties #region IAddChild ////// Called to add the object as a child. /// /// /// A Block to add as a child. /// ////// o must derive from either UIElement or TextElement, or an /// ArgumentException will be thrown by this method. /// void IAddChild.AddChild(object value) { Type valueType = value.GetType(); TextElement te = value as TextElement; if (te != null) { TextSchema.ValidateChild(/*parent:*/this, /*child:*/te, true /* throwIfIllegalChild */, true /* throwIfIllegalHyperlinkDescendent */); Append(te); } else { UIElement uie = value as UIElement; if (uie != null) { InlineUIContainer inlineContainer = this as InlineUIContainer; if (inlineContainer != null) { if (inlineContainer.Child != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_ThisInlineUIContainerHasAChildUIElementAlready, this.GetType().Name, ((InlineUIContainer)this).Child.GetType().Name, value.GetType().Name)); } inlineContainer.Child = uie; } else { BlockUIContainer blockContainer = this as BlockUIContainer; if (blockContainer != null) { if (blockContainer.Child != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_ThisBlockUIContainerHasAChildUIElementAlready, this.GetType().Name, ((BlockUIContainer)this).Child.GetType().Name, value.GetType().Name)); } blockContainer.Child = uie; } else { if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(InlineUIContainer))) { // Create implicit InlineUIContainer wrapper for this UIElement InlineUIContainer implicitInlineUIContainer = Inline.CreateImplicitInlineUIContainer(this); Append(implicitInlineUIContainer); implicitInlineUIContainer.Child = uie; } else { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name)); } } } } else { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name)); } } } ////// Called when text appears under the tag in markup /// /// /// Text to Add to this TextElement /// ///void IAddChild.AddText(string text) { if (text == null) { throw new ArgumentNullException("text"); } // Check if text run is allowed in this element, // and create implicit Run if possible. if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(string))) { Append(text); } else { // Implicit Run creation if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(Run))) { // NOTE: Do not use new Run(text) constructor to avoid TextContainer creation // which would hit parser perf Run implicitRun = Inline.CreateImplicitRun(this); Append(implicitRun); implicitRun.Text = text; } else { // Otherwise text is not allowed. Throw if it is not a whitespace if (text.Trim().Length > 0) { throw new InvalidOperationException(SR.Get(SRID.TextSchema_TextIsNotAllowed, this.GetType().Name)); } // As to whitespace - it can be simply ignored } } } #endregion IAddChild #region LogicalTree /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { return this.IsEmpty ? new RangeContentEnumerator(null, null) : new RangeContentEnumerator(this.ContentStart, this.ContentEnd); } } #endregion LogicalTree #endregion Public Properties //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Notification that a specified property has been invalidated /// /// EventArgs that contains the property, metadata, old value, and new value for this change protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { // Always call base.OnPropertyChanged, otherwise Property Engine will not work. base.OnPropertyChanged(e); // Note whether or not this change due to a SetValue/ClearValue call. bool localValueChanged = e.NewValueSource == BaseValueSourceInternal.Local || e.OldValueSource == BaseValueSourceInternal.Local; if (localValueChanged || e.IsAValueChange || e.IsASubPropertyChange) { if (this.IsInTree) // No work to do if no one's listening. { // If the modified property affects layout we have some additional // bookkeeping to take care of. FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata; if (fmetadata != null) { bool affectsMeasureOrArrange = fmetadata.AffectsMeasure || fmetadata.AffectsArrange || fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange; bool affectsRender = (fmetadata.AffectsRender && (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender)); if (affectsMeasureOrArrange || affectsRender) { TextContainer textContainer = EnsureTextContainer(); textContainer.BeginChange(); try { if (localValueChanged) { TextTreeUndo.CreatePropertyUndoUnit(this, e); } if (e.IsAValueChange || e.IsASubPropertyChange) { NotifyTypographicPropertyChanged(affectsMeasureOrArrange, localValueChanged, e.Property); } } finally { textContainer.EndChange(); } } } } } } // Notify our TextContainer that a typographic property has changed // value on this TextElement. // This has the side effect of invalidating layout. internal void NotifyTypographicPropertyChanged(bool affectsMeasureOrArrange, bool localValueChanged, DependencyProperty property) { if (!this.IsInTree) // No work to do if no one's listening. { return; } TextContainer tree; TextPointer beforeStart; tree = EnsureTextContainer(); // Take note that something layout related has changed. tree.NextLayoutGeneration(); // Notify any external listeners. if (tree.HasListeners) { // Get the position before the start of this element. beforeStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward); beforeStart.Freeze(); // Raise ContentAffected event that spans entire TextElement (from BeforeStart to AfterEnd). tree.BeginChange(); try { tree.BeforeAddChange(); if (localValueChanged) { tree.AddLocalValueChange(); } tree.AddChange(beforeStart, _textElementNode.SymbolCount, _textElementNode.IMECharCount, PrecursorTextChangeType.PropertyModified, property, !affectsMeasureOrArrange); } finally { tree.EndChange(); } } } #endregion Protected Events //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods internal static TypographyProperties GetTypographyProperties(DependencyObject element) { TypographyProperties group = new TypographyProperties(); group.SetStandardLigatures((bool) element.GetValue(Typography.StandardLigaturesProperty)); group.SetContextualLigatures((bool) element.GetValue(Typography.ContextualLigaturesProperty)); group.SetDiscretionaryLigatures((bool) element.GetValue(Typography.DiscretionaryLigaturesProperty)); group.SetHistoricalLigatures((bool) element.GetValue(Typography.HistoricalLigaturesProperty)); group.SetAnnotationAlternates((int) element.GetValue(Typography.AnnotationAlternatesProperty)); group.SetContextualAlternates((bool) element.GetValue(Typography.ContextualAlternatesProperty)); group.SetHistoricalForms((bool) element.GetValue(Typography.HistoricalFormsProperty)); group.SetKerning((bool) element.GetValue(Typography.KerningProperty)); group.SetCapitalSpacing((bool) element.GetValue(Typography.CapitalSpacingProperty)); group.SetCaseSensitiveForms((bool) element.GetValue(Typography.CaseSensitiveFormsProperty)); group.SetStylisticSet1((bool) element.GetValue(Typography.StylisticSet1Property)); group.SetStylisticSet2((bool) element.GetValue(Typography.StylisticSet2Property)); group.SetStylisticSet3((bool) element.GetValue(Typography.StylisticSet3Property)); group.SetStylisticSet4((bool) element.GetValue(Typography.StylisticSet4Property)); group.SetStylisticSet5((bool) element.GetValue(Typography.StylisticSet5Property)); group.SetStylisticSet6((bool) element.GetValue(Typography.StylisticSet6Property)); group.SetStylisticSet7((bool) element.GetValue(Typography.StylisticSet7Property)); group.SetStylisticSet8((bool) element.GetValue(Typography.StylisticSet8Property)); group.SetStylisticSet9((bool) element.GetValue(Typography.StylisticSet9Property)); group.SetStylisticSet10((bool) element.GetValue(Typography.StylisticSet10Property)); group.SetStylisticSet11((bool) element.GetValue(Typography.StylisticSet11Property)); group.SetStylisticSet12((bool) element.GetValue(Typography.StylisticSet12Property)); group.SetStylisticSet13((bool) element.GetValue(Typography.StylisticSet13Property)); group.SetStylisticSet14((bool) element.GetValue(Typography.StylisticSet14Property)); group.SetStylisticSet15((bool) element.GetValue(Typography.StylisticSet15Property)); group.SetStylisticSet16((bool) element.GetValue(Typography.StylisticSet16Property)); group.SetStylisticSet17((bool) element.GetValue(Typography.StylisticSet17Property)); group.SetStylisticSet18((bool) element.GetValue(Typography.StylisticSet18Property)); group.SetStylisticSet19((bool) element.GetValue(Typography.StylisticSet19Property)); group.SetStylisticSet20((bool) element.GetValue(Typography.StylisticSet20Property)); group.SetFraction((FontFraction) element.GetValue(Typography.FractionProperty)); group.SetSlashedZero((bool) element.GetValue(Typography.SlashedZeroProperty)); group.SetMathematicalGreek((bool) element.GetValue(Typography.MathematicalGreekProperty)); group.SetEastAsianExpertForms((bool) element.GetValue(Typography.EastAsianExpertFormsProperty)); group.SetVariants((FontVariants) element.GetValue(Typography.VariantsProperty)); group.Set----s((FontCapitals) element.GetValue(Typography.CapitalsProperty)); group.SetNumeralStyle((FontNumeralStyle) element.GetValue(Typography.NumeralStyleProperty)); group.SetNumeralAlignment((FontNumeralAlignment) element.GetValue(Typography.NumeralAlignmentProperty)); group.SetEastAsianWidths((FontEastAsianWidths) element.GetValue(Typography.EastAsianWidthsProperty)); group.SetEastAsianLanguage((FontEastAsianLanguage) element.GetValue(Typography.EastAsianLanguageProperty)); group.SetStandardSwashes((int) element.GetValue(Typography.StandardSwashesProperty)); group.SetContextualSwashes((int) element.GetValue(Typography.ContextualSwashesProperty)); group.SetStylisticAlternates((int) element.GetValue(Typography.StylisticAlternatesProperty)); return group; } // ........................................................................ // // Helpers for Text Flow Initialization // // ........................................................................ // Recursively calls EndInit for this element and for all its descendants internal void DeepEndInit() { if (!this.IsInitialized) { if (!this.IsEmpty) { IEnumerator children = this.LogicalChildren; while (children.MoveNext()) { // child.Current could be FrameworkElement, FrameworkContentElement, // or anything else. Only recursively call self for FE & FCE. TextElement child = children.Current as TextElement; if (child != null) { child.DeepEndInit(); } } } // Mark the end of the initialization phase this.EndInit(); Invariant.Assert(this.IsInitialized); } } // Returns the common TextElement ancestor of two TextElements. internal static TextElement GetCommonAncestor(TextElement element1, TextElement element2) { if (element1 != element2) { int depth1 = 0; int depth2 = 0; TextElement element; // Calculate the depths of each TextElement within the tree. for (element = element1; element.Parent is TextElement; element = (TextElement)element.Parent) { depth1++; } for (element = element2; element.Parent is TextElement; element = (TextElement)element.Parent) { depth2++; } // Then walk up until we reach an equal depth. while (depth1 > depth2 && element1 != element2) { element1 = (TextElement)element1.Parent; depth1--; } while (depth2 > depth1 && element1 != element2) { element2 = (TextElement)element2.Parent; depth2--; } // Then, if necessary, keep going up to the root looking for a match. while (element1 != element2) { element1 = element1.Parent as TextElement; element2 = element2.Parent as TextElement; } } Invariant.Assert(element1 == element2); return element1; } #endregion Internal Methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties //----------------------------------------------------- // The TextContainer containing this TextElement. //------------------------------------------------------ internal TextContainer TextContainer { get { return EnsureTextContainer(); } } //------------------------------------------------------ // Emptiness of an element //----------------------------------------------------- internal bool IsEmpty { get { if (_textElementNode == null) return true; return (_textElementNode.ContainedNode == null); } } //------------------------------------------------------ // True if this TextElement is contained within a TextContainer. //----------------------------------------------------- internal bool IsInTree { get { return _textElementNode != null; } } //----------------------------------------------------- // Symbol offset of this.ElementStart. //----------------------------------------------------- internal int ElementStartOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) - 1; } } //------------------------------------------------------ // Symbol offset of this.ContentStart. //----------------------------------------------------- internal int ContentStartOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation); } } //------------------------------------------------------ // Symbol offset of this.ContentEnd. //------------------------------------------------------ internal int ContentEndOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 2; } } //----------------------------------------------------- // Symbol offset of this.ElementEnd. //------------------------------------------------------ internal int ElementEndOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 1; } } //----------------------------------------------------- // Symbol count of this TextElement, including start/end // edges. //----------------------------------------------------- internal int SymbolCount { get { return this.IsInTree ? _textElementNode.SymbolCount : 2; } } //----------------------------------------------------- // The node in a TextContainer representing this TextElement. //------------------------------------------------------ internal TextTreeTextElementNode TextElementNode { get { return _textElementNode; } set { _textElementNode = value; } } //------------------------------------------------------------------- // Typography properties group //-------------------------------------------------------------------- internal TypographyProperties TypographyPropertiesGroup { get { if (_typographyPropertiesGroup == null) { _typographyPropertiesGroup = GetTypographyProperties(this); } return _typographyPropertiesGroup; } } private static void OnTypographyChanged(DependencyObject element, DependencyPropertyChangedEventArgs e) { ((TextElement) element)._typographyPropertiesGroup = null; } //------------------------------------------------------ // Derived classes override this method if they want // their left edges to be visible to IMEs. This is the // case for structural elements like Paragraph but not // for formatting elements like Inline. //----------------------------------------------------- internal virtual bool IsIMEStructuralElement { get { return false; } } //------------------------------------------------------ // Plain text character count of this element's edges. // Used by the IME to convert Paragraph, TableCell, etc. // into unicode placeholders. //----------------------------------------------------- internal int IMELeftEdgeCharCount { get { int leftEdgeCharCount = 0; if (this.IsIMEStructuralElement) { if (!this.IsInTree) { // IMELeftEdgeCharCount depends on context, has no meaning outside a tree. leftEdgeCharCount = -1; } else { // The first sibling is always invisible to the IME. // This ensures we don't get into trouble creating implicit // content on IME SetText calls. leftEdgeCharCount = this.TextElementNode.IsFirstSibling ? 0 : 1; } } return leftEdgeCharCount; } } //----------------------------------------------------- // Returns true if this node is the leftmost sibling of its parent // and visible to the IMEs (ie, is a Block). // // This is interesting because when we do want to expose // element edges to the IMEs (Blocks, TableCell, etc.) we // have one exception: the first sibling. Edges of first // siblings must be hidden because the TextEditor will // implicitly create first siblings when the IMEs, for example, // insert raw text into a TableCell that lacks a Paragraph. // The IMEs can't handle the implicit edge creation, so we // hide those edges. //----------------------------------------------------- internal virtual bool IsFirstIMEVisibleSibling { get { bool isFirstIMEVisibleSibling = false; if (this.IsIMEStructuralElement) { isFirstIMEVisibleSibling = (this.TextElementNode == null) ? true : this.TextElementNode.IsFirstSibling; } return isFirstIMEVisibleSibling; } } //------------------------------------------------------ // Returns a TextElement immediately following this one // on the same level of siblings. //----------------------------------------------------- internal TextElement NextElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetNextNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //------------------------------------------------------ // Returns a TextElement immediately preceding this one // on the same level of siblings. //------------------------------------------------------ internal TextElement PreviousElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetPreviousNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //----------------------------------------------------- // Returns the first TextElement contained by this // TextElement. //------------------------------------------------------ internal TextElement FirstChildElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetFirstContainedNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //----------------------------------------------------- // Returns the last TextElement contained by this // TextElement. //----------------------------------------------------- internal TextElement LastChildElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetLastContainedNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Inserts a string at the end of the content spanned by this TextElement. /// /// /// string to insert. /// private void Append(string textData) { TextContainer tree; if (textData == null) { throw new ArgumentNullException("textData"); } tree = EnsureTextContainer(); tree.BeginChange(); try { // tree.InsertTextInternal(new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd), textData); } finally { tree.EndChange(); } } ////// Inserts a TextElement at the end of the content spanned by this /// TextElement. /// /// /// TextElement to insert. /// ////// This method will remove element from TextContainer it was previously /// positioned within. Any content spanned by element will also /// be moved. /// private void Append(TextElement element) { TextContainer tree; TextPointer position; if (element == null) { throw new ArgumentNullException("element"); } tree = EnsureTextContainer(); tree.BeginChange(); try { // position = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd); tree.InsertElementInternal(position, position, element); } finally { tree.EndChange(); } } // Demand creates a TextContainer if no tree is associated with this instance. // Otherwise returns the exisiting tree, and clears the tree's DeadPositionList. private TextContainer EnsureTextContainer() { TextContainer tree; TextPointer start; if (this.IsInTree) { tree = _textElementNode.GetTextTree(); tree.EmptyDeadPositionList(); } else { tree = new TextContainer(null, false /* plainTextOnly */); start = tree.Start; tree.BeginChange(); try { tree.InsertElementInternal(start, start, this); } finally { // No event will be raised, since we know there are no listeners yet! tree.EndChange(); } Invariant.Assert(this.IsInTree); } return tree; } private static bool IsValidFontFamily(object o) { FontFamily value = o as FontFamily; return (value != null); } ////// private static bool IsValidFontSize(object value) { double fontSize = (double) value; double minFontSize = TextDpi.MinWidth; double maxFontSize = Math.Min(1000000, PTS.MaxFontSize); if (Double.IsNaN(fontSize)) { return false; } if (fontSize < minFontSize) { return false; } if (fontSize > maxFontSize) { return false; } return true; } #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // The node in a TextContainer representing this TextElement. private TextTreeTextElementNode _textElementNode; //-------------------------------------------------------------------- // Typography Group Property //------------------------------------------------------------------- private TypographyProperties _typographyPropertiesGroup = Typography.Default; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: Base class for content in text based FrameworkElement. // // History: // 07/2003 : grzegorz - Created // 02/18/2004: benwest - new TOM method implementation for TextContainer rewrite. // 10/28/2004 : grzegorz - ContentElements refactoring. // //--------------------------------------------------------------------------- // Enable presharp pragma warning suppress directives. #pragma warning disable 1634, 1691 using System.Collections; using System.ComponentModel; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using MS.Internal; using MS.Internal.PresentationFramework; using MS.Internal.PtsHost.UnsafeNativeMethods; // PTS restrictions using MS.Internal.Text; namespace System.Windows.Documents { ////// /// TextElement is an base class for content in text based FrameworkElement /// controls such as Text, FlowDocument, or RichTextBox. TextElements span /// other content, applying property values or providing structural information. /// ////// public abstract class TextElement : FrameworkContentElement, IAddChild { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors static TextElement() { // For attached properties metadata specific to the type needs to be set using OverrideMetadata // instead of passing it during property registration. Otherwise all types will get it. PropertyChangedCallback typographyChanged = new PropertyChangedCallback(OnTypographyChanged); // Registering typography properties metadata DependencyProperty[] typographyProperties = Typography.TypographyPropertiesList; for (int i = 0; i < typographyProperties.Length; i++) { typographyProperties[i].OverrideMetadata(typeof(TextElement), new FrameworkPropertyMetadata(typographyChanged)); } } ////// Internal constructor to prevent publicly derived classes. /// internal TextElement() : base() { } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Extracts this TextElement from its current position, if any, and /// inserts it at a specified location. /// /// /// New start position. /// /// /// New end position. /// ////// Throws an ArgumentException if start and end are not /// positioned within the same document, or if start is positioned /// after end, or if start == null but end != null. /// ////// This method extracts the TextElement from its current position, /// leaving behind any contained content, before inserting the TextElement /// at a new location. /// /// If start is null, end must also be null, and the TextElement will /// not be inserted into a new document. /// internal void Reposition(TextPointer start, TextPointer end) { TextContainer tree; if (start != null) { ValidationHelper.VerifyPositionPair(start, end); } else if (end != null) { throw new ArgumentException(SR.Get(SRID.TextElement_UnmatchedEndPointer)); } if (start != null) { // start/end must be equally scoped. But we want to discount // this TextElement when considering scoping -- it will be // extracted before the final insert. SplayTreeNode startNode = start.GetScopingNode(); // Suppress presharp 6506: Parameter 'end' to this public method must be validated. // We already validated it indirectly above, when calling ValidationHelper.VerifyPositionPair. #pragma warning suppress 6506 SplayTreeNode endNode = end.GetScopingNode(); if (startNode == _textElementNode) { startNode = _textElementNode.GetContainingNode(); } if (endNode == _textElementNode) { endNode = _textElementNode.GetContainingNode(); } if (startNode != endNode) { throw new ArgumentException(SR.Get(SRID.InDifferentScope, "start", "end")); } } if (this.IsInTree) { tree = EnsureTextContainer(); if (start == null) { // // Case 0: Extract this element from its tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); } finally { tree.EndChange(); } } else { // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 6506 if (tree == start.TextContainer) { // // Case 1: extract and insert this TextElement within the same tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); tree.InsertElementInternal(start, end, this); } finally { tree.EndChange(); } } else { // // Case 2: extract and insert this TextElement from one tree to another tree. // tree.BeginChange(); try { tree.ExtractElementInternal(this); } finally { tree.EndChange(); } // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 56506 start.TextContainer.BeginChange(); try { start.TextContainer.InsertElementInternal(start, end, this); } finally { start.TextContainer.EndChange(); } } } } else if (start != null) { // // Case 3: insert this TextElement to a new tree (this is no current tree). // start.TextContainer.BeginChange(); try { start.TextContainer.InsertElementInternal(start, end, this); } finally { start.TextContainer.EndChange(); } } } ////// Extracts this TextElement and its content from its current /// position, if any, and inserts it at a specified location. /// /// /// New position. /// ////// This method extracts the TextElement from its current position, /// including any contained content, before inserting the TextElement /// at a new location. /// /// If textPosition is null, the TextElement will not be inserted into /// a new document. /// internal void RepositionWithContent(TextPointer textPosition) { TextContainer tree; if (textPosition == null) { if (this.IsInTree) { tree = EnsureTextContainer(); // Presharp doesn't understand that by design EnsureTextContainer can never return null. #pragma warning suppress 6506 tree.BeginChange(); try { tree.DeleteContentInternal(this.ElementStart, this.ElementEnd); } finally { tree.EndChange(); } } } else { tree = textPosition.TextContainer; // Presharp doesn't understand that by design TextPointer.TextContainer can never be null. #pragma warning suppress 56506 tree.BeginChange(); try { tree.InsertElementInternal(textPosition, textPosition, this); } finally { tree.EndChange(); } } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties internal static readonly UncommonFieldContainerTextElementField = new UncommonField (); /// /// A TextRange spanning the content of this element. /// internal TextRange TextRange { get { VerifyAccess(); TextContainer tree = EnsureTextContainer(); TextPointer contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward); contentStart.Freeze(); TextPointer contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward); contentEnd.Freeze(); return new TextRange(contentStart, contentEnd); } } ////// A TextPointer located just before the start edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Forward. /// public TextPointer ElementStart { get { TextContainer tree; TextPointer elementStart; tree = EnsureTextContainer(); elementStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward); elementStart.Freeze(); return elementStart; } } internal StaticTextPointer StaticElementStart { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, 0); } } ////// A TextPointer located just past the start edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Backward. /// public TextPointer ContentStart { get { TextContainer tree; TextPointer contentStart; tree = EnsureTextContainer(); contentStart = new TextPointer(tree, _textElementNode, ElementEdge.AfterStart, LogicalDirection.Backward); contentStart.Freeze(); return contentStart; } } internal StaticTextPointer StaticContentStart { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, 1); } } ////// A TextPointer located just before the end edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Forward. /// public TextPointer ContentEnd { get { TextContainer tree; TextPointer contentEnd; tree = EnsureTextContainer(); contentEnd = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd, LogicalDirection.Forward); contentEnd.Freeze(); return contentEnd; } } internal StaticTextPointer StaticContentEnd { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount - 1); } } // Returns true if a position belongs to inner part of this TextElement (ContentStart and ContentEnd including). internal bool Contains(TextPointer position) { TextContainer tree = EnsureTextContainer(); ValidationHelper.VerifyPosition(tree, position); return this.ContentStart.CompareTo(position) <= 0 && this.ContentEnd.CompareTo(position) >= 0; } ////// A TextPointer located just after the end edge of this TextElement. /// ////// The TextPointer returned always has its IsFrozen property set true /// and LogicalDirection set Backward. /// public TextPointer ElementEnd { get { TextContainer tree; TextPointer elementEnd; tree = EnsureTextContainer(); elementEnd = new TextPointer(tree, _textElementNode, ElementEdge.AfterEnd, LogicalDirection.Backward); elementEnd.Freeze(); return elementEnd; } } internal StaticTextPointer StaticElementEnd { get { TextContainer tree = EnsureTextContainer(); return new StaticTextPointer(tree, _textElementNode, _textElementNode.SymbolCount); } } #region DependencyProperties ////// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.RegisterAttached( "FontFamily", typeof(FontFamily), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontFamily, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), new ValidateValueCallback(IsValidFontFamily)); ///property. /// /// The FontFamily property specifies the name of font family. /// [Localizability( LocalizationCategory.Font, Modifiability = Modifiability.Unmodifiable )] public FontFamily FontFamily { get { return (FontFamily) GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontFamily(DependencyObject element, FontFamily value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontFamilyProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontFamily GetFontFamily(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontFamily)element.GetValue(FontFamilyProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontStyleProperty = DependencyProperty.RegisterAttached( "FontStyle", typeof(FontStyle), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontStyle, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontStyle property requests normal, italic, and oblique faces within a font family. /// public FontStyle FontStyle { get { return (FontStyle) GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontStyle(DependencyObject element, FontStyle value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontStyleProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontStyle GetFontStyle(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontStyle)element.GetValue(FontStyleProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontWeightProperty = DependencyProperty.RegisterAttached( "FontWeight", typeof(FontWeight), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontWeight, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontWeight property specifies the weight of the font. /// public FontWeight FontWeight { get { return (FontWeight) GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontWeight(DependencyObject element, FontWeight value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontWeightProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontWeight GetFontWeight(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontWeight)element.GetValue(FontWeightProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontStretchProperty = DependencyProperty.RegisterAttached( "FontStretch", typeof(FontStretch), typeof(TextElement), new FrameworkPropertyMetadata( FontStretches.Normal, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The FontStretch property selects a normal, condensed, or extended face from a font family. /// public FontStretch FontStretch { get { return (FontStretch) GetValue(FontStretchProperty); } set { SetValue(FontStretchProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontStretch(DependencyObject element, FontStretch value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontStretchProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static FontStretch GetFontStretch(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (FontStretch)element.GetValue(FontStretchProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached( "FontSize", typeof(double), typeof(TextElement), new FrameworkPropertyMetadata( SystemFonts.MessageFontSize, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits), new ValidateValueCallback(IsValidFontSize)); ///property. /// /// The FontSize property specifies the size of the font. /// [TypeConverter(typeof(FontSizeConverter))] [Localizability(LocalizationCategory.None)] public double FontSize { get { return (double) GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetFontSize(DependencyObject element, double value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(FontSizeProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. [TypeConverter(typeof(FontSizeConverter))] public static double GetFontSize(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (double)element.GetValue(FontSizeProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached( "Foreground", typeof(Brush), typeof(TextElement), new FrameworkPropertyMetadata( Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender | FrameworkPropertyMetadataOptions.Inherits)); ///property. /// /// The Foreground property specifies the foreground brush of an element's text content. /// public Brush Foreground { get { return (Brush) GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// DependencyProperty setter for /// The element to which to write the attached property. /// The property value to set public static void SetForeground(DependencyObject element, Brush value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(ForegroundProperty, value); } ///property. /// /// DependencyProperty getter for /// The element from which to read the attached property. public static Brush GetForeground(DependencyObject element) { if (element == null) { throw new ArgumentNullException("element"); } return (Brush)element.GetValue(ForegroundProperty); } ///property. /// /// DependencyProperty for [CommonDependencyProperty] public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(TextElement), new FrameworkPropertyMetadata((Brush)null, FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// /// The Background property defines the brush used to fill the content area. /// public Brush Background { get { return (Brush) GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// DependencyProperty for public static readonly DependencyProperty TextEffectsProperty = DependencyProperty.Register( "TextEffects", typeof(TextEffectCollection), typeof(TextElement), new FrameworkPropertyMetadata( new FreezableDefaultValueFactory(TextEffectCollection.Empty), FrameworkPropertyMetadataOptions.AffectsRender)); ///property. /// It doesn't affect layout /// /// The TextEffects property specifies effects that are added to the text of an element. /// public TextEffectCollection TextEffects { get { return (TextEffectCollection) GetValue(TextEffectsProperty); } set { SetValue(TextEffectsProperty, value); } } ////// Class providing access to all text typography properties /// public Typography Typography { get { return new Typography(this); } } #endregion DependencyProperties #region IAddChild ////// Called to add the object as a child. /// /// /// A Block to add as a child. /// ////// o must derive from either UIElement or TextElement, or an /// ArgumentException will be thrown by this method. /// void IAddChild.AddChild(object value) { Type valueType = value.GetType(); TextElement te = value as TextElement; if (te != null) { TextSchema.ValidateChild(/*parent:*/this, /*child:*/te, true /* throwIfIllegalChild */, true /* throwIfIllegalHyperlinkDescendent */); Append(te); } else { UIElement uie = value as UIElement; if (uie != null) { InlineUIContainer inlineContainer = this as InlineUIContainer; if (inlineContainer != null) { if (inlineContainer.Child != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_ThisInlineUIContainerHasAChildUIElementAlready, this.GetType().Name, ((InlineUIContainer)this).Child.GetType().Name, value.GetType().Name)); } inlineContainer.Child = uie; } else { BlockUIContainer blockContainer = this as BlockUIContainer; if (blockContainer != null) { if (blockContainer.Child != null) { throw new ArgumentException(SR.Get(SRID.TextSchema_ThisBlockUIContainerHasAChildUIElementAlready, this.GetType().Name, ((BlockUIContainer)this).Child.GetType().Name, value.GetType().Name)); } blockContainer.Child = uie; } else { if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(InlineUIContainer))) { // Create implicit InlineUIContainer wrapper for this UIElement InlineUIContainer implicitInlineUIContainer = Inline.CreateImplicitInlineUIContainer(this); Append(implicitInlineUIContainer); implicitInlineUIContainer.Child = uie; } else { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name)); } } } } else { throw new ArgumentException(SR.Get(SRID.TextSchema_ChildTypeIsInvalid, this.GetType().Name, value.GetType().Name)); } } } ////// Called when text appears under the tag in markup /// /// /// Text to Add to this TextElement /// ///void IAddChild.AddText(string text) { if (text == null) { throw new ArgumentNullException("text"); } // Check if text run is allowed in this element, // and create implicit Run if possible. if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(string))) { Append(text); } else { // Implicit Run creation if (TextSchema.IsValidChild(/*parent:*/this, /*childType:*/typeof(Run))) { // NOTE: Do not use new Run(text) constructor to avoid TextContainer creation // which would hit parser perf Run implicitRun = Inline.CreateImplicitRun(this); Append(implicitRun); implicitRun.Text = text; } else { // Otherwise text is not allowed. Throw if it is not a whitespace if (text.Trim().Length > 0) { throw new InvalidOperationException(SR.Get(SRID.TextSchema_TextIsNotAllowed, this.GetType().Name)); } // As to whitespace - it can be simply ignored } } } #endregion IAddChild #region LogicalTree /// /// Returns enumerator to logical children. /// protected internal override IEnumerator LogicalChildren { get { return this.IsEmpty ? new RangeContentEnumerator(null, null) : new RangeContentEnumerator(this.ContentStart, this.ContentEnd); } } #endregion LogicalTree #endregion Public Properties //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ #region Protected Methods ////// Notification that a specified property has been invalidated /// /// EventArgs that contains the property, metadata, old value, and new value for this change protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { // Always call base.OnPropertyChanged, otherwise Property Engine will not work. base.OnPropertyChanged(e); // Note whether or not this change due to a SetValue/ClearValue call. bool localValueChanged = e.NewValueSource == BaseValueSourceInternal.Local || e.OldValueSource == BaseValueSourceInternal.Local; if (localValueChanged || e.IsAValueChange || e.IsASubPropertyChange) { if (this.IsInTree) // No work to do if no one's listening. { // If the modified property affects layout we have some additional // bookkeeping to take care of. FrameworkPropertyMetadata fmetadata = e.Metadata as FrameworkPropertyMetadata; if (fmetadata != null) { bool affectsMeasureOrArrange = fmetadata.AffectsMeasure || fmetadata.AffectsArrange || fmetadata.AffectsParentMeasure || fmetadata.AffectsParentArrange; bool affectsRender = (fmetadata.AffectsRender && (e.IsAValueChange || !fmetadata.SubPropertiesDoNotAffectRender)); if (affectsMeasureOrArrange || affectsRender) { TextContainer textContainer = EnsureTextContainer(); textContainer.BeginChange(); try { if (localValueChanged) { TextTreeUndo.CreatePropertyUndoUnit(this, e); } if (e.IsAValueChange || e.IsASubPropertyChange) { NotifyTypographicPropertyChanged(affectsMeasureOrArrange, localValueChanged, e.Property); } } finally { textContainer.EndChange(); } } } } } } // Notify our TextContainer that a typographic property has changed // value on this TextElement. // This has the side effect of invalidating layout. internal void NotifyTypographicPropertyChanged(bool affectsMeasureOrArrange, bool localValueChanged, DependencyProperty property) { if (!this.IsInTree) // No work to do if no one's listening. { return; } TextContainer tree; TextPointer beforeStart; tree = EnsureTextContainer(); // Take note that something layout related has changed. tree.NextLayoutGeneration(); // Notify any external listeners. if (tree.HasListeners) { // Get the position before the start of this element. beforeStart = new TextPointer(tree, _textElementNode, ElementEdge.BeforeStart, LogicalDirection.Forward); beforeStart.Freeze(); // Raise ContentAffected event that spans entire TextElement (from BeforeStart to AfterEnd). tree.BeginChange(); try { tree.BeforeAddChange(); if (localValueChanged) { tree.AddLocalValueChange(); } tree.AddChange(beforeStart, _textElementNode.SymbolCount, _textElementNode.IMECharCount, PrecursorTextChangeType.PropertyModified, property, !affectsMeasureOrArrange); } finally { tree.EndChange(); } } } #endregion Protected Events //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods internal static TypographyProperties GetTypographyProperties(DependencyObject element) { TypographyProperties group = new TypographyProperties(); group.SetStandardLigatures((bool) element.GetValue(Typography.StandardLigaturesProperty)); group.SetContextualLigatures((bool) element.GetValue(Typography.ContextualLigaturesProperty)); group.SetDiscretionaryLigatures((bool) element.GetValue(Typography.DiscretionaryLigaturesProperty)); group.SetHistoricalLigatures((bool) element.GetValue(Typography.HistoricalLigaturesProperty)); group.SetAnnotationAlternates((int) element.GetValue(Typography.AnnotationAlternatesProperty)); group.SetContextualAlternates((bool) element.GetValue(Typography.ContextualAlternatesProperty)); group.SetHistoricalForms((bool) element.GetValue(Typography.HistoricalFormsProperty)); group.SetKerning((bool) element.GetValue(Typography.KerningProperty)); group.SetCapitalSpacing((bool) element.GetValue(Typography.CapitalSpacingProperty)); group.SetCaseSensitiveForms((bool) element.GetValue(Typography.CaseSensitiveFormsProperty)); group.SetStylisticSet1((bool) element.GetValue(Typography.StylisticSet1Property)); group.SetStylisticSet2((bool) element.GetValue(Typography.StylisticSet2Property)); group.SetStylisticSet3((bool) element.GetValue(Typography.StylisticSet3Property)); group.SetStylisticSet4((bool) element.GetValue(Typography.StylisticSet4Property)); group.SetStylisticSet5((bool) element.GetValue(Typography.StylisticSet5Property)); group.SetStylisticSet6((bool) element.GetValue(Typography.StylisticSet6Property)); group.SetStylisticSet7((bool) element.GetValue(Typography.StylisticSet7Property)); group.SetStylisticSet8((bool) element.GetValue(Typography.StylisticSet8Property)); group.SetStylisticSet9((bool) element.GetValue(Typography.StylisticSet9Property)); group.SetStylisticSet10((bool) element.GetValue(Typography.StylisticSet10Property)); group.SetStylisticSet11((bool) element.GetValue(Typography.StylisticSet11Property)); group.SetStylisticSet12((bool) element.GetValue(Typography.StylisticSet12Property)); group.SetStylisticSet13((bool) element.GetValue(Typography.StylisticSet13Property)); group.SetStylisticSet14((bool) element.GetValue(Typography.StylisticSet14Property)); group.SetStylisticSet15((bool) element.GetValue(Typography.StylisticSet15Property)); group.SetStylisticSet16((bool) element.GetValue(Typography.StylisticSet16Property)); group.SetStylisticSet17((bool) element.GetValue(Typography.StylisticSet17Property)); group.SetStylisticSet18((bool) element.GetValue(Typography.StylisticSet18Property)); group.SetStylisticSet19((bool) element.GetValue(Typography.StylisticSet19Property)); group.SetStylisticSet20((bool) element.GetValue(Typography.StylisticSet20Property)); group.SetFraction((FontFraction) element.GetValue(Typography.FractionProperty)); group.SetSlashedZero((bool) element.GetValue(Typography.SlashedZeroProperty)); group.SetMathematicalGreek((bool) element.GetValue(Typography.MathematicalGreekProperty)); group.SetEastAsianExpertForms((bool) element.GetValue(Typography.EastAsianExpertFormsProperty)); group.SetVariants((FontVariants) element.GetValue(Typography.VariantsProperty)); group.Set----s((FontCapitals) element.GetValue(Typography.CapitalsProperty)); group.SetNumeralStyle((FontNumeralStyle) element.GetValue(Typography.NumeralStyleProperty)); group.SetNumeralAlignment((FontNumeralAlignment) element.GetValue(Typography.NumeralAlignmentProperty)); group.SetEastAsianWidths((FontEastAsianWidths) element.GetValue(Typography.EastAsianWidthsProperty)); group.SetEastAsianLanguage((FontEastAsianLanguage) element.GetValue(Typography.EastAsianLanguageProperty)); group.SetStandardSwashes((int) element.GetValue(Typography.StandardSwashesProperty)); group.SetContextualSwashes((int) element.GetValue(Typography.ContextualSwashesProperty)); group.SetStylisticAlternates((int) element.GetValue(Typography.StylisticAlternatesProperty)); return group; } // ........................................................................ // // Helpers for Text Flow Initialization // // ........................................................................ // Recursively calls EndInit for this element and for all its descendants internal void DeepEndInit() { if (!this.IsInitialized) { if (!this.IsEmpty) { IEnumerator children = this.LogicalChildren; while (children.MoveNext()) { // child.Current could be FrameworkElement, FrameworkContentElement, // or anything else. Only recursively call self for FE & FCE. TextElement child = children.Current as TextElement; if (child != null) { child.DeepEndInit(); } } } // Mark the end of the initialization phase this.EndInit(); Invariant.Assert(this.IsInitialized); } } // Returns the common TextElement ancestor of two TextElements. internal static TextElement GetCommonAncestor(TextElement element1, TextElement element2) { if (element1 != element2) { int depth1 = 0; int depth2 = 0; TextElement element; // Calculate the depths of each TextElement within the tree. for (element = element1; element.Parent is TextElement; element = (TextElement)element.Parent) { depth1++; } for (element = element2; element.Parent is TextElement; element = (TextElement)element.Parent) { depth2++; } // Then walk up until we reach an equal depth. while (depth1 > depth2 && element1 != element2) { element1 = (TextElement)element1.Parent; depth1--; } while (depth2 > depth1 && element1 != element2) { element2 = (TextElement)element2.Parent; depth2--; } // Then, if necessary, keep going up to the root looking for a match. while (element1 != element2) { element1 = element1.Parent as TextElement; element2 = element2.Parent as TextElement; } } Invariant.Assert(element1 == element2); return element1; } #endregion Internal Methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties //----------------------------------------------------- // The TextContainer containing this TextElement. //------------------------------------------------------ internal TextContainer TextContainer { get { return EnsureTextContainer(); } } //------------------------------------------------------ // Emptiness of an element //----------------------------------------------------- internal bool IsEmpty { get { if (_textElementNode == null) return true; return (_textElementNode.ContainedNode == null); } } //------------------------------------------------------ // True if this TextElement is contained within a TextContainer. //----------------------------------------------------- internal bool IsInTree { get { return _textElementNode != null; } } //----------------------------------------------------- // Symbol offset of this.ElementStart. //----------------------------------------------------- internal int ElementStartOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) - 1; } } //------------------------------------------------------ // Symbol offset of this.ContentStart. //----------------------------------------------------- internal int ContentStartOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation); } } //------------------------------------------------------ // Symbol offset of this.ContentEnd. //------------------------------------------------------ internal int ContentEndOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 2; } } //----------------------------------------------------- // Symbol offset of this.ElementEnd. //------------------------------------------------------ internal int ElementEndOffset { get { Invariant.Assert(this.IsInTree, "TextElement is not in any TextContainer, caller should ensure this."); return _textElementNode.GetSymbolOffset(EnsureTextContainer().Generation) + _textElementNode.SymbolCount - 1; } } //----------------------------------------------------- // Symbol count of this TextElement, including start/end // edges. //----------------------------------------------------- internal int SymbolCount { get { return this.IsInTree ? _textElementNode.SymbolCount : 2; } } //----------------------------------------------------- // The node in a TextContainer representing this TextElement. //------------------------------------------------------ internal TextTreeTextElementNode TextElementNode { get { return _textElementNode; } set { _textElementNode = value; } } //------------------------------------------------------------------- // Typography properties group //-------------------------------------------------------------------- internal TypographyProperties TypographyPropertiesGroup { get { if (_typographyPropertiesGroup == null) { _typographyPropertiesGroup = GetTypographyProperties(this); } return _typographyPropertiesGroup; } } private static void OnTypographyChanged(DependencyObject element, DependencyPropertyChangedEventArgs e) { ((TextElement) element)._typographyPropertiesGroup = null; } //------------------------------------------------------ // Derived classes override this method if they want // their left edges to be visible to IMEs. This is the // case for structural elements like Paragraph but not // for formatting elements like Inline. //----------------------------------------------------- internal virtual bool IsIMEStructuralElement { get { return false; } } //------------------------------------------------------ // Plain text character count of this element's edges. // Used by the IME to convert Paragraph, TableCell, etc. // into unicode placeholders. //----------------------------------------------------- internal int IMELeftEdgeCharCount { get { int leftEdgeCharCount = 0; if (this.IsIMEStructuralElement) { if (!this.IsInTree) { // IMELeftEdgeCharCount depends on context, has no meaning outside a tree. leftEdgeCharCount = -1; } else { // The first sibling is always invisible to the IME. // This ensures we don't get into trouble creating implicit // content on IME SetText calls. leftEdgeCharCount = this.TextElementNode.IsFirstSibling ? 0 : 1; } } return leftEdgeCharCount; } } //----------------------------------------------------- // Returns true if this node is the leftmost sibling of its parent // and visible to the IMEs (ie, is a Block). // // This is interesting because when we do want to expose // element edges to the IMEs (Blocks, TableCell, etc.) we // have one exception: the first sibling. Edges of first // siblings must be hidden because the TextEditor will // implicitly create first siblings when the IMEs, for example, // insert raw text into a TableCell that lacks a Paragraph. // The IMEs can't handle the implicit edge creation, so we // hide those edges. //----------------------------------------------------- internal virtual bool IsFirstIMEVisibleSibling { get { bool isFirstIMEVisibleSibling = false; if (this.IsIMEStructuralElement) { isFirstIMEVisibleSibling = (this.TextElementNode == null) ? true : this.TextElementNode.IsFirstSibling; } return isFirstIMEVisibleSibling; } } //------------------------------------------------------ // Returns a TextElement immediately following this one // on the same level of siblings. //----------------------------------------------------- internal TextElement NextElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetNextNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //------------------------------------------------------ // Returns a TextElement immediately preceding this one // on the same level of siblings. //------------------------------------------------------ internal TextElement PreviousElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetPreviousNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //----------------------------------------------------- // Returns the first TextElement contained by this // TextElement. //------------------------------------------------------ internal TextElement FirstChildElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetFirstContainedNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } //----------------------------------------------------- // Returns the last TextElement contained by this // TextElement. //----------------------------------------------------- internal TextElement LastChildElement { get { if (!this.IsInTree) { return null; } TextTreeTextElementNode node = _textElementNode.GetLastContainedNode() as TextTreeTextElementNode; return (node != null) ? node.TextElement : null; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Inserts a string at the end of the content spanned by this TextElement. /// /// /// string to insert. /// private void Append(string textData) { TextContainer tree; if (textData == null) { throw new ArgumentNullException("textData"); } tree = EnsureTextContainer(); tree.BeginChange(); try { // tree.InsertTextInternal(new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd), textData); } finally { tree.EndChange(); } } ////// Inserts a TextElement at the end of the content spanned by this /// TextElement. /// /// /// TextElement to insert. /// ////// This method will remove element from TextContainer it was previously /// positioned within. Any content spanned by element will also /// be moved. /// private void Append(TextElement element) { TextContainer tree; TextPointer position; if (element == null) { throw new ArgumentNullException("element"); } tree = EnsureTextContainer(); tree.BeginChange(); try { // position = new TextPointer(tree, _textElementNode, ElementEdge.BeforeEnd); tree.InsertElementInternal(position, position, element); } finally { tree.EndChange(); } } // Demand creates a TextContainer if no tree is associated with this instance. // Otherwise returns the exisiting tree, and clears the tree's DeadPositionList. private TextContainer EnsureTextContainer() { TextContainer tree; TextPointer start; if (this.IsInTree) { tree = _textElementNode.GetTextTree(); tree.EmptyDeadPositionList(); } else { tree = new TextContainer(null, false /* plainTextOnly */); start = tree.Start; tree.BeginChange(); try { tree.InsertElementInternal(start, start, this); } finally { // No event will be raised, since we know there are no listeners yet! tree.EndChange(); } Invariant.Assert(this.IsInTree); } return tree; } private static bool IsValidFontFamily(object o) { FontFamily value = o as FontFamily; return (value != null); } ////// private static bool IsValidFontSize(object value) { double fontSize = (double) value; double minFontSize = TextDpi.MinWidth; double maxFontSize = Math.Min(1000000, PTS.MaxFontSize); if (Double.IsNaN(fontSize)) { return false; } if (fontSize < minFontSize) { return false; } if (fontSize > maxFontSize) { return false; } return true; } #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // The node in a TextContainer representing this TextElement. private TextTreeTextElementNode _textElementNode; //-------------------------------------------------------------------- // Typography Group Property //------------------------------------------------------------------- private TypographyProperties _typographyPropertiesGroup = Typography.Default; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.///
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ItemCollection.cs
- DeflateStream.cs
- NGCSerializationManager.cs
- MouseOverProperty.cs
- MemberCollection.cs
- FileChangesMonitor.cs
- Clock.cs
- AssociationSet.cs
- ToolStripItemDataObject.cs
- WindowsTokenRoleProvider.cs
- GC.cs
- ModelPropertyDescriptor.cs
- Propagator.JoinPropagator.SubstitutingCloneVisitor.cs
- InplaceBitmapMetadataWriter.cs
- CompModHelpers.cs
- DescriptionAttribute.cs
- StaticTextPointer.cs
- UnsafeNativeMethods.cs
- TextCompositionEventArgs.cs
- Compiler.cs
- RbTree.cs
- CryptoApi.cs
- GeometryGroup.cs
- MultilineStringConverter.cs
- DataGridColumnHeadersPresenterAutomationPeer.cs
- InvalidWMPVersionException.cs
- FormViewInsertedEventArgs.cs
- PixelFormatConverter.cs
- GestureRecognitionResult.cs
- GridViewEditEventArgs.cs
- XsltException.cs
- RegexTree.cs
- BuildProviderAppliesToAttribute.cs
- ViewSimplifier.cs
- ContextProperty.cs
- DoubleUtil.cs
- JavaScriptObjectDeserializer.cs
- FieldAccessException.cs
- CodeRemoveEventStatement.cs
- RegistrationServices.cs
- EntityClientCacheKey.cs
- DbBuffer.cs
- CharacterMetrics.cs
- _BasicClient.cs
- ComboBoxAutomationPeer.cs
- GeneralTransform.cs
- NegationPusher.cs
- SqlMethodCallConverter.cs
- CountdownEvent.cs
- ProcessModule.cs
- DeclaredTypeElementCollection.cs
- LineSegment.cs
- XmlSchemaProviderAttribute.cs
- ClientTargetSection.cs
- TextParagraph.cs
- SmiRecordBuffer.cs
- ContentTextAutomationPeer.cs
- UriExt.cs
- FormParameter.cs
- TransformerInfoCollection.cs
- DbProviderFactory.cs
- MulticastIPAddressInformationCollection.cs
- precedingsibling.cs
- RegexRunnerFactory.cs
- DeclaredTypeValidator.cs
- Pointer.cs
- ListViewDeleteEventArgs.cs
- X509CertificateStore.cs
- WebBaseEventKeyComparer.cs
- CategoryState.cs
- SuppressMergeCheckAttribute.cs
- PublishLicense.cs
- Int16AnimationUsingKeyFrames.cs
- ClassicBorderDecorator.cs
- ProxyElement.cs
- JsonUriDataContract.cs
- SmtpFailedRecipientsException.cs
- MD5.cs
- Properties.cs
- GreenMethods.cs
- Fonts.cs
- HandleExceptionArgs.cs
- SocketInformation.cs
- SlipBehavior.cs
- CustomErrorsSection.cs
- TraceProvider.cs
- XmlSchemaChoice.cs
- ReachPrintTicketSerializerAsync.cs
- NavigationWindowAutomationPeer.cs
- Preprocessor.cs
- Stroke.cs
- _HelperAsyncResults.cs
- EventWaitHandleSecurity.cs
- TemplateControlParser.cs
- ApplicationServicesHostFactory.cs
- ZoneIdentityPermission.cs
- Point3DIndependentAnimationStorage.cs
- StyleHelper.cs
- SqlComparer.cs
- PointLight.cs