Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / documents / TextBoxLine.cs / 1305600 / TextBoxLine.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // File: TextBoxLine.cs // // Description: TextLine wrapper used by TextBoxView. // //--------------------------------------------------------------------------- using System; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal; using MS.Internal.PtsHost; using MS.Internal.Text; namespace System.Windows.Controls { ////// TextLine wrapper used by TextBoxView. /// internal class TextBoxLine : TextSource, IDisposable { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Constructor. /// /// Owner of the line. internal TextBoxLine(TextBoxView owner) { _owner = owner; } #endregion Constructors // ------------------------------------------------------------------ // // Public Methods // // ----------------------------------------------------------------- #region Public Methods ////// Free all resources associated with the line. Prepare it for reuse. /// public void Dispose() { // Dispose text line if (_line != null) { _line.Dispose(); _line = null; } GC.SuppressFinalize(this); } ////// Get a text run at specified text source position. /// public override TextRun GetTextRun(int dcp) { TextRun run = null; StaticTextPointer position = _owner.Host.TextContainer.CreateStaticPointerAtOffset(dcp); switch (position.GetPointerContext(LogicalDirection.Forward)) { case TextPointerContext.Text: run = HandleText(position); break; case TextPointerContext.None: run = new TextEndOfParagraph(_syntheticCharacterLength); break; case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: case TextPointerContext.EmbeddedElement: default: Invariant.Assert(false, "Unsupported position type."); break; } Invariant.Assert(run != null, "TextRun has not been created."); Invariant.Assert(run.Length > 0, "TextRun has to have positive length."); return run; } ////// Get text immediately before specified text source position. /// public override TextSpanGetPrecedingText(int dcp) { CharacterBufferRange precedingText = CharacterBufferRange.Empty; CultureInfo culture = null; if (dcp > 0) { // Create TextPointer at dcp ITextPointer position = _owner.Host.TextContainer.CreatePointerAtOffset(dcp, LogicalDirection.Backward); // Return text in run. If it is at start of TextContainer this will return an empty string. // Typically the caller requires just the preceding character. Worst case is the entire // preceding sentence, which we approximate with a 128 char limit. int runLength = Math.Min(128, position.GetTextRunLength(LogicalDirection.Backward)); char []text = new char[runLength]; position.GetTextInRun(LogicalDirection.Backward, text, 0, runLength); precedingText = new CharacterBufferRange(text, 0, runLength); culture = DynamicPropertyReader.GetCultureInfo((Control)_owner.Host); } return new TextSpan ( precedingText.Length, new CultureSpecificCharacterBufferRange(culture, precedingText)); } /// /// TextFormatter to map a text source character index to a text effect character index /// /// text source character index ///the text effect index corresponding to the text effect character index public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex) { return textSourceCharacterIndex; } #endregion Public Methods //-------------------------------------------------------------------- // // Internal Methods // //-------------------------------------------------------------------- #region Internal Methods ////// Create and format text line. /// /// First character position for the line. /// Width to pass to LS formatter. /// Line wrapping width. /// Line's properties. /// Run cache. /// Text formatter. ////// formatWidth/paragraphWidth is an attempt to work around bug 114719. /// Unfortunately, Line Services cannot guarantee that once a line /// has been measured, measuring the same content with the actual line /// width will produce the same line. /// /// For example, suppose we format dcp 0 with paragraphWidth = 100. /// Suppose this results in a line from dcp 0 - 10, with width = 95. /// /// We would expect that a call to FormatLine with dcp = 0, /// paragraphWidth = 95 would result in the same 10 char line. /// But in practice it might return a 9 char line. /// /// The workaround is to pass in an explicit formatting width across /// multiple calls, even if the paragraphWidth changes. /// internal void Format(int dcp, double formatWidth, double paragraphWidth, LineProperties lineProperties, TextRunCache textRunCache, TextFormatter formatter) { _lineProperties = lineProperties; _dcp = dcp; _paragraphWidth = paragraphWidth; // We must ignore TextAlignment here since formatWidth does not // necessarilly equal paragraphWidth. We'll adjust on later calls. lineProperties.IgnoreTextAlignment = (lineProperties.TextAlignment != TextAlignment.Justify); try { _line = formatter.FormatLine(this, dcp, formatWidth, lineProperties, null, textRunCache); } finally { lineProperties.IgnoreTextAlignment = false; } } ////// Create and return visual node for the line. /// internal TextBoxLineDrawingVisual CreateVisual() { TextBoxLineDrawingVisual visual = new TextBoxLineDrawingVisual(); // Calculate shift in line offset to render trailing spaces or avoid clipping text. double delta = CalculateXOffsetShift(); DrawingContext ctx = visual.RenderOpen(); _line.Draw(ctx, new Point(delta, 0), ((_lineProperties.FlowDirection == FlowDirection.RightToLeft) ? InvertAxes.Horizontal : InvertAxes.None)); ctx.Close(); return visual; } ////// Retrieve bounds of an object/character at specified text position. /// /// position of an object/character /// flow direction of object/character ///Bounds of an object/character internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection) { return GetBoundsFromPosition(characterIndex, 1, out flowDirection); } ////// Returns a collection of rectangles (Rect) that form the bounds of the region /// specified between the start and end points. /// /// Starting point of the region /// Length in characters of the region /// Offset of line in x direction, to be added to line bounds /// Offset of line in y direction, to be added to line bounds ////// This function calls GetTextBounds for the line, and then checks if there are /// text run bounds. If they exist, it uses those as the bounding rectangles. If not, /// it returns the rectangle for the first (and only) element of the text bounds. /// internal ListGetRangeBounds(int cp, int cch, double xOffset, double yOffset) { List rectangles = new List (); // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); double adjustedXOffset = xOffset + delta; IList textBounds = _line.GetTextBounds(cp, cch); Invariant.Assert(textBounds.Count > 0); for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++) { Rect rect = textBounds[boundIndex].Rectangle; rect.X += adjustedXOffset; rect.Y += yOffset; rectangles.Add(rect); } return rectangles; } /// /// Retrieve text position index from the distance. /// /// distance relative to the beginning of the line ///Text position index internal CharacterHit GetTextPositionFromDistance(double distance) { // Adjust distance to account for a line shift due to rendering of trailing spaces double delta = CalculateXOffsetShift(); return _line.GetCharacterHitFromDistance(distance - delta); } ////// Retrieve text position for next caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetNextCaretCharacterHit(CharacterHit index) { return _line.GetNextCaretCharacterHit(index); } ////// Retrieve text position for previous caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index) { return _line.GetPreviousCaretCharacterHit(index); } ////// Retrieve text position for backspace caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetBackspaceCaretCharacterHit(CharacterHit index) { return _line.GetBackspaceCaretCharacterHit(index); } ////// Returns true of char hit is at caret unit boundary. /// /// /// CharacterHit to be tested. /// internal bool IsAtCaretCharacterHit(CharacterHit charHit) { return _line.IsAtCaretCharacterHit(charHit, _dcp); } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// Calculated width of the line. /// internal double Width { get { if (IsWidthAdjusted) { // Trailing spaces add to width return _line.WidthIncludingTrailingWhitespace; } else { return _line.Width; } } } ////// Height of the line; line advance distance. /// internal double Height { get { return _line.Height; } } ////// Is this the last line of the paragraph? /// internal bool EndOfParagraph { get { // If there are no Newline characters, it is not the end of paragraph. if (_line.NewlineLength == 0) { return false; } // Since there are Newline characters in the line, do more expensive and // accurate check. IList> runs = _line.GetTextRunSpans(); return (((TextSpan )runs[runs.Count-1]).Value is TextEndOfParagraph); } } /// /// Length of the line excluding any synthetic characters. /// internal int Length { get { return _line.Length - (EndOfParagraph ? 1 : 0); } } ////// Length of the line excluding any synthetic characters and line breaks. /// internal int ContentLength { get { return _line.Length - _line.NewlineLength; } } ////// True if line ends in hard line break. /// internal bool HasLineBreak { get { return (_line.NewlineLength > 0); } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods ////// Fetch the next run at text position. /// private TextRun HandleText(StaticTextPointer position) { // Calculate the end of the run by finding either: // a) the next intersection of highlight ranges, or // b) the natural end of this textrun StaticTextPointer endOfRunPosition = _owner.Host.TextContainer.Highlights.GetNextPropertyChangePosition(position, LogicalDirection.Forward); // Clamp the text run at an arbitrary limit, so we don't make // an unbounded allocation. if (position.GetOffsetToPosition(endOfRunPosition) > 4096) { endOfRunPosition = position.CreatePointer(4096); } // Factor in any speller error squiggles on the run. TextDecorationCollection highlightDecorations = position.TextContainer.Highlights.GetHighlightValue(position, LogicalDirection.Forward, typeof(SpellerHighlightLayer)) as TextDecorationCollection; TextRunProperties properties; if (highlightDecorations == null) { properties = _lineProperties.DefaultTextRunProperties; } else { if (_spellerErrorProperties == null) { _spellerErrorProperties = new TextProperties((TextProperties)_lineProperties.DefaultTextRunProperties, highlightDecorations); } properties = _spellerErrorProperties; } // Get character buffer for the text run. char[] textBuffer = new char[position.GetOffsetToPosition(endOfRunPosition)]; // Copy characters from text run into buffer. Since we are dealing with plain text content, // we expect to get all the characters from position to endOfRunPosition. int charactersCopied = position.GetTextInRun(LogicalDirection.Forward, textBuffer, 0, textBuffer.Length); Invariant.Assert(charactersCopied == textBuffer.Length); // Create text run, using characters copied as length return new TextCharacters(textBuffer, 0, charactersCopied, properties); } ////// Retrieve bounds of an object/character at specified text index. /// /// character index of an object/character /// number of positions occupied by object/character /// flow direction of object/character ///Bounds of an object/character private Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection) { Rect rect; // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); IListtextBounds = _line.GetTextBounds(cp, cch); Invariant.Assert(textBounds != null && textBounds.Count == 1, "Expecting exactly one TextBounds for a single text position."); IList runBounds = textBounds[0].TextRunBounds; if (runBounds != null) { Invariant.Assert(runBounds.Count == 1, "Expecting exactly one TextRunBounds for a single text position."); rect = runBounds[0].Rectangle; } else { rect = textBounds[0].Rectangle; } rect.X += delta; flowDirection = textBounds[0].FlowDirection; return rect; } /// /// Returns amount of shift for X-offset to render trailing spaces /// and TextAlignment offset. /// private double CalculateXOffsetShift() { double xOffset = 0; if (_lineProperties.TextAlignmentInternal == TextAlignment.Right) { xOffset = _paragraphWidth - _line.Width; } else if (_lineProperties.TextAlignmentInternal == TextAlignment.Center) { xOffset = (_paragraphWidth - _line.Width) / 2; } if (IsXOffsetAdjusted) { if (_lineProperties.TextAlignmentInternal == TextAlignment.Center) { // Return trailing spaces length divided by two so line remains centered. xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2; } else { xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace); } } return xOffset; } #endregion Private Methods //------------------------------------------------------------------- // // Private Properites // //-------------------------------------------------------------------- #region Private Properties ////// True if line's X-offset needs adjustment to render trailing spaces. /// private bool IsXOffsetAdjusted { get { return ((_lineProperties.TextAlignmentInternal == TextAlignment.Right || _lineProperties.TextAlignmentInternal == TextAlignment.Center) && IsWidthAdjusted); } } ////// True if line's width is adjusted to include trailing spaces. For right and center alignment we need to /// adjust line offset as well, but for left alignment we need to only make a width asjustment. /// private bool IsWidthAdjusted { get { // Trailing spaces rendered only around hard breaks return (HasLineBreak || EndOfParagraph); } } #endregion Private Properties //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields ////// Owner of the line. /// private readonly TextBoxView _owner; ////// Cached text line. /// private TextLine _line; ////// Index of the first character in the line. /// private int _dcp; ////// Properties of the line. /// private LineProperties _lineProperties; ////// Properties of the line when covered by a spelling error squiggle. /// private TextProperties _spellerErrorProperties; ////// Width of the enclosing paragraph, used for TextAlignment calculations. /// private double _paragraphWidth; ////// TextEndOfParagraph character count. /// private const int _syntheticCharacterLength = 1; #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. // // File: TextBoxLine.cs // // Description: TextLine wrapper used by TextBoxView. // //--------------------------------------------------------------------------- using System; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal; using MS.Internal.PtsHost; using MS.Internal.Text; namespace System.Windows.Controls { ////// TextLine wrapper used by TextBoxView. /// internal class TextBoxLine : TextSource, IDisposable { //------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors ////// Constructor. /// /// Owner of the line. internal TextBoxLine(TextBoxView owner) { _owner = owner; } #endregion Constructors // ------------------------------------------------------------------ // // Public Methods // // ----------------------------------------------------------------- #region Public Methods ////// Free all resources associated with the line. Prepare it for reuse. /// public void Dispose() { // Dispose text line if (_line != null) { _line.Dispose(); _line = null; } GC.SuppressFinalize(this); } ////// Get a text run at specified text source position. /// public override TextRun GetTextRun(int dcp) { TextRun run = null; StaticTextPointer position = _owner.Host.TextContainer.CreateStaticPointerAtOffset(dcp); switch (position.GetPointerContext(LogicalDirection.Forward)) { case TextPointerContext.Text: run = HandleText(position); break; case TextPointerContext.None: run = new TextEndOfParagraph(_syntheticCharacterLength); break; case TextPointerContext.ElementStart: case TextPointerContext.ElementEnd: case TextPointerContext.EmbeddedElement: default: Invariant.Assert(false, "Unsupported position type."); break; } Invariant.Assert(run != null, "TextRun has not been created."); Invariant.Assert(run.Length > 0, "TextRun has to have positive length."); return run; } ////// Get text immediately before specified text source position. /// public override TextSpanGetPrecedingText(int dcp) { CharacterBufferRange precedingText = CharacterBufferRange.Empty; CultureInfo culture = null; if (dcp > 0) { // Create TextPointer at dcp ITextPointer position = _owner.Host.TextContainer.CreatePointerAtOffset(dcp, LogicalDirection.Backward); // Return text in run. If it is at start of TextContainer this will return an empty string. // Typically the caller requires just the preceding character. Worst case is the entire // preceding sentence, which we approximate with a 128 char limit. int runLength = Math.Min(128, position.GetTextRunLength(LogicalDirection.Backward)); char []text = new char[runLength]; position.GetTextInRun(LogicalDirection.Backward, text, 0, runLength); precedingText = new CharacterBufferRange(text, 0, runLength); culture = DynamicPropertyReader.GetCultureInfo((Control)_owner.Host); } return new TextSpan ( precedingText.Length, new CultureSpecificCharacterBufferRange(culture, precedingText)); } /// /// TextFormatter to map a text source character index to a text effect character index /// /// text source character index ///the text effect index corresponding to the text effect character index public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex) { return textSourceCharacterIndex; } #endregion Public Methods //-------------------------------------------------------------------- // // Internal Methods // //-------------------------------------------------------------------- #region Internal Methods ////// Create and format text line. /// /// First character position for the line. /// Width to pass to LS formatter. /// Line wrapping width. /// Line's properties. /// Run cache. /// Text formatter. ////// formatWidth/paragraphWidth is an attempt to work around bug 114719. /// Unfortunately, Line Services cannot guarantee that once a line /// has been measured, measuring the same content with the actual line /// width will produce the same line. /// /// For example, suppose we format dcp 0 with paragraphWidth = 100. /// Suppose this results in a line from dcp 0 - 10, with width = 95. /// /// We would expect that a call to FormatLine with dcp = 0, /// paragraphWidth = 95 would result in the same 10 char line. /// But in practice it might return a 9 char line. /// /// The workaround is to pass in an explicit formatting width across /// multiple calls, even if the paragraphWidth changes. /// internal void Format(int dcp, double formatWidth, double paragraphWidth, LineProperties lineProperties, TextRunCache textRunCache, TextFormatter formatter) { _lineProperties = lineProperties; _dcp = dcp; _paragraphWidth = paragraphWidth; // We must ignore TextAlignment here since formatWidth does not // necessarilly equal paragraphWidth. We'll adjust on later calls. lineProperties.IgnoreTextAlignment = (lineProperties.TextAlignment != TextAlignment.Justify); try { _line = formatter.FormatLine(this, dcp, formatWidth, lineProperties, null, textRunCache); } finally { lineProperties.IgnoreTextAlignment = false; } } ////// Create and return visual node for the line. /// internal TextBoxLineDrawingVisual CreateVisual() { TextBoxLineDrawingVisual visual = new TextBoxLineDrawingVisual(); // Calculate shift in line offset to render trailing spaces or avoid clipping text. double delta = CalculateXOffsetShift(); DrawingContext ctx = visual.RenderOpen(); _line.Draw(ctx, new Point(delta, 0), ((_lineProperties.FlowDirection == FlowDirection.RightToLeft) ? InvertAxes.Horizontal : InvertAxes.None)); ctx.Close(); return visual; } ////// Retrieve bounds of an object/character at specified text position. /// /// position of an object/character /// flow direction of object/character ///Bounds of an object/character internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection) { return GetBoundsFromPosition(characterIndex, 1, out flowDirection); } ////// Returns a collection of rectangles (Rect) that form the bounds of the region /// specified between the start and end points. /// /// Starting point of the region /// Length in characters of the region /// Offset of line in x direction, to be added to line bounds /// Offset of line in y direction, to be added to line bounds ////// This function calls GetTextBounds for the line, and then checks if there are /// text run bounds. If they exist, it uses those as the bounding rectangles. If not, /// it returns the rectangle for the first (and only) element of the text bounds. /// internal ListGetRangeBounds(int cp, int cch, double xOffset, double yOffset) { List rectangles = new List (); // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); double adjustedXOffset = xOffset + delta; IList textBounds = _line.GetTextBounds(cp, cch); Invariant.Assert(textBounds.Count > 0); for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++) { Rect rect = textBounds[boundIndex].Rectangle; rect.X += adjustedXOffset; rect.Y += yOffset; rectangles.Add(rect); } return rectangles; } /// /// Retrieve text position index from the distance. /// /// distance relative to the beginning of the line ///Text position index internal CharacterHit GetTextPositionFromDistance(double distance) { // Adjust distance to account for a line shift due to rendering of trailing spaces double delta = CalculateXOffsetShift(); return _line.GetCharacterHitFromDistance(distance - delta); } ////// Retrieve text position for next caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetNextCaretCharacterHit(CharacterHit index) { return _line.GetNextCaretCharacterHit(index); } ////// Retrieve text position for previous caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index) { return _line.GetPreviousCaretCharacterHit(index); } ////// Retrieve text position for backspace caret position. /// /// CharacterHit for current position ///Text position index internal CharacterHit GetBackspaceCaretCharacterHit(CharacterHit index) { return _line.GetBackspaceCaretCharacterHit(index); } ////// Returns true of char hit is at caret unit boundary. /// /// /// CharacterHit to be tested. /// internal bool IsAtCaretCharacterHit(CharacterHit charHit) { return _line.IsAtCaretCharacterHit(charHit, _dcp); } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //-------------------------------------------------------------------- #region Internal Properties ////// Calculated width of the line. /// internal double Width { get { if (IsWidthAdjusted) { // Trailing spaces add to width return _line.WidthIncludingTrailingWhitespace; } else { return _line.Width; } } } ////// Height of the line; line advance distance. /// internal double Height { get { return _line.Height; } } ////// Is this the last line of the paragraph? /// internal bool EndOfParagraph { get { // If there are no Newline characters, it is not the end of paragraph. if (_line.NewlineLength == 0) { return false; } // Since there are Newline characters in the line, do more expensive and // accurate check. IList> runs = _line.GetTextRunSpans(); return (((TextSpan )runs[runs.Count-1]).Value is TextEndOfParagraph); } } /// /// Length of the line excluding any synthetic characters. /// internal int Length { get { return _line.Length - (EndOfParagraph ? 1 : 0); } } ////// Length of the line excluding any synthetic characters and line breaks. /// internal int ContentLength { get { return _line.Length - _line.NewlineLength; } } ////// True if line ends in hard line break. /// internal bool HasLineBreak { get { return (_line.NewlineLength > 0); } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //------------------------------------------------------------------- #region Private Methods ////// Fetch the next run at text position. /// private TextRun HandleText(StaticTextPointer position) { // Calculate the end of the run by finding either: // a) the next intersection of highlight ranges, or // b) the natural end of this textrun StaticTextPointer endOfRunPosition = _owner.Host.TextContainer.Highlights.GetNextPropertyChangePosition(position, LogicalDirection.Forward); // Clamp the text run at an arbitrary limit, so we don't make // an unbounded allocation. if (position.GetOffsetToPosition(endOfRunPosition) > 4096) { endOfRunPosition = position.CreatePointer(4096); } // Factor in any speller error squiggles on the run. TextDecorationCollection highlightDecorations = position.TextContainer.Highlights.GetHighlightValue(position, LogicalDirection.Forward, typeof(SpellerHighlightLayer)) as TextDecorationCollection; TextRunProperties properties; if (highlightDecorations == null) { properties = _lineProperties.DefaultTextRunProperties; } else { if (_spellerErrorProperties == null) { _spellerErrorProperties = new TextProperties((TextProperties)_lineProperties.DefaultTextRunProperties, highlightDecorations); } properties = _spellerErrorProperties; } // Get character buffer for the text run. char[] textBuffer = new char[position.GetOffsetToPosition(endOfRunPosition)]; // Copy characters from text run into buffer. Since we are dealing with plain text content, // we expect to get all the characters from position to endOfRunPosition. int charactersCopied = position.GetTextInRun(LogicalDirection.Forward, textBuffer, 0, textBuffer.Length); Invariant.Assert(charactersCopied == textBuffer.Length); // Create text run, using characters copied as length return new TextCharacters(textBuffer, 0, charactersCopied, properties); } ////// Retrieve bounds of an object/character at specified text index. /// /// character index of an object/character /// number of positions occupied by object/character /// flow direction of object/character ///Bounds of an object/character private Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection) { Rect rect; // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); IListtextBounds = _line.GetTextBounds(cp, cch); Invariant.Assert(textBounds != null && textBounds.Count == 1, "Expecting exactly one TextBounds for a single text position."); IList runBounds = textBounds[0].TextRunBounds; if (runBounds != null) { Invariant.Assert(runBounds.Count == 1, "Expecting exactly one TextRunBounds for a single text position."); rect = runBounds[0].Rectangle; } else { rect = textBounds[0].Rectangle; } rect.X += delta; flowDirection = textBounds[0].FlowDirection; return rect; } /// /// Returns amount of shift for X-offset to render trailing spaces /// and TextAlignment offset. /// private double CalculateXOffsetShift() { double xOffset = 0; if (_lineProperties.TextAlignmentInternal == TextAlignment.Right) { xOffset = _paragraphWidth - _line.Width; } else if (_lineProperties.TextAlignmentInternal == TextAlignment.Center) { xOffset = (_paragraphWidth - _line.Width) / 2; } if (IsXOffsetAdjusted) { if (_lineProperties.TextAlignmentInternal == TextAlignment.Center) { // Return trailing spaces length divided by two so line remains centered. xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2; } else { xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace); } } return xOffset; } #endregion Private Methods //------------------------------------------------------------------- // // Private Properites // //-------------------------------------------------------------------- #region Private Properties ////// True if line's X-offset needs adjustment to render trailing spaces. /// private bool IsXOffsetAdjusted { get { return ((_lineProperties.TextAlignmentInternal == TextAlignment.Right || _lineProperties.TextAlignmentInternal == TextAlignment.Center) && IsWidthAdjusted); } } ////// True if line's width is adjusted to include trailing spaces. For right and center alignment we need to /// adjust line offset as well, but for left alignment we need to only make a width asjustment. /// private bool IsWidthAdjusted { get { // Trailing spaces rendered only around hard breaks return (HasLineBreak || EndOfParagraph); } } #endregion Private Properties //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields ////// Owner of the line. /// private readonly TextBoxView _owner; ////// Cached text line. /// private TextLine _line; ////// Index of the first character in the line. /// private int _dcp; ////// Properties of the line. /// private LineProperties _lineProperties; ////// Properties of the line when covered by a spelling error squiggle. /// private TextProperties _spellerErrorProperties; ////// Width of the enclosing paragraph, used for TextAlignment calculations. /// private double _paragraphWidth; ////// TextEndOfParagraph character count. /// private const int _syntheticCharacterLength = 1; #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
- Header.cs
- InfoCardArgumentException.cs
- ZipIOExtraFieldZip64Element.cs
- TextParaLineResult.cs
- ByteKeyFrameCollection.cs
- EntityDataSourceViewSchema.cs
- NotFiniteNumberException.cs
- SettingsPropertyNotFoundException.cs
- CodeSnippetCompileUnit.cs
- TransactionFlowAttribute.cs
- ListViewHitTestInfo.cs
- UiaCoreApi.cs
- RelatedCurrencyManager.cs
- _RegBlobWebProxyDataBuilder.cs
- ContentAlignmentEditor.cs
- TextParaLineResult.cs
- ProjectedSlot.cs
- EntityClientCacheEntry.cs
- ToolZone.cs
- ActivityCompletionCallbackWrapper.cs
- PasswordRecovery.cs
- AnnotationMap.cs
- ObjectNavigationPropertyMapping.cs
- TagPrefixInfo.cs
- TrustSection.cs
- OdbcConnectionHandle.cs
- CheckBox.cs
- MemberDescriptor.cs
- HttpVersion.cs
- ModelFactory.cs
- CollectionView.cs
- RC2CryptoServiceProvider.cs
- MimeFormatExtensions.cs
- SystemIPAddressInformation.cs
- WebPermission.cs
- ControlParameter.cs
- PropertyGeneratedEventArgs.cs
- SourceFileBuildProvider.cs
- _LoggingObject.cs
- HtmlInputButton.cs
- ToolStripSplitButton.cs
- SoapAttributeOverrides.cs
- SqlTriggerContext.cs
- DiscoveryDocumentSearchPattern.cs
- _ContextAwareResult.cs
- AuthenticationSection.cs
- DataGridViewColumnCollection.cs
- DataControlImageButton.cs
- FixUpCollection.cs
- OdbcError.cs
- XmlnsDefinitionAttribute.cs
- SecurityProtocolCorrelationState.cs
- SettingsProperty.cs
- Win32.cs
- CodeTypeDelegate.cs
- ObjectViewListener.cs
- FormClosedEvent.cs
- Ports.cs
- ObjectDataSourceDisposingEventArgs.cs
- CodePageEncoding.cs
- FilteredDataSetHelper.cs
- MatrixTransform.cs
- ExpressionEvaluator.cs
- RetriableClipboard.cs
- DeviceSpecificChoice.cs
- AnnotationHelper.cs
- DataTableMappingCollection.cs
- UmAlQuraCalendar.cs
- EFTableProvider.cs
- PageBreakRecord.cs
- WebEventCodes.cs
- OleDbParameterCollection.cs
- SmiContextFactory.cs
- PerformanceCounterTraceRecord.cs
- ListSortDescription.cs
- XmlNullResolver.cs
- CompilerHelpers.cs
- StreamInfo.cs
- CookieHandler.cs
- BookmarkEventArgs.cs
- TypeConverterHelper.cs
- TextRangeEditLists.cs
- Crypto.cs
- InteropAutomationProvider.cs
- IsolationInterop.cs
- InternalSafeNativeMethods.cs
- GridView.cs
- SQLInt64Storage.cs
- PanelStyle.cs
- ErrorHandler.cs
- Control.cs
- GPRECTF.cs
- BlobPersonalizationState.cs
- QueryContinueDragEvent.cs
- InternalDispatchObject.cs
- ValidatorUtils.cs
- SigningCredentials.cs
- RichTextBoxAutomationPeer.cs
- SelectedCellsChangedEventArgs.cs
- CursorConverter.cs