Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ForwardPositionQuery.cs
- ProfileEventArgs.cs
- ColorPalette.cs
- EncryptedReference.cs
- WebRequestModuleElementCollection.cs
- RawMouseInputReport.cs
- Condition.cs
- ObjectFullSpanRewriter.cs
- HttpWebRequest.cs
- ComponentConverter.cs
- Shape.cs
- IBuiltInEvidence.cs
- ElementsClipboardData.cs
- Pipe.cs
- BypassElement.cs
- DBParameter.cs
- WebPartsPersonalizationAuthorization.cs
- WebReference.cs
- EntitySetRetriever.cs
- PageEventArgs.cs
- RegexNode.cs
- XmlSchemaImport.cs
- CodePageEncoding.cs
- Subtree.cs
- DataGridCell.cs
- ValueTypeFixupInfo.cs
- CharStorage.cs
- DesignTimeXamlWriter.cs
- QueryOpeningEnumerator.cs
- SourceFileBuildProvider.cs
- TableProvider.cs
- TypeGenericEnumerableViewSchema.cs
- SecurityToken.cs
- StringBuilder.cs
- MulticastDelegate.cs
- EncodingDataItem.cs
- HtmlInputCheckBox.cs
- HighlightComponent.cs
- MethodBody.cs
- FormParameter.cs
- WebException.cs
- FilePresentation.cs
- unitconverter.cs
- WrappedDispatcherException.cs
- ProfileSection.cs
- AppearanceEditorPart.cs
- ParameterCollection.cs
- SqlCommand.cs
- RuleInfoComparer.cs
- Zone.cs
- CodeNamespaceCollection.cs
- XmlObjectSerializerWriteContext.cs
- Module.cs
- RolePrincipal.cs
- ReadWriteObjectLock.cs
- UriTemplateVariablePathSegment.cs
- OptimizerPatterns.cs
- SmtpReplyReaderFactory.cs
- RSAPKCS1KeyExchangeFormatter.cs
- BamlResourceContent.cs
- SqlComparer.cs
- PieceNameHelper.cs
- GridItemCollection.cs
- ObjectAnimationBase.cs
- DirectoryNotFoundException.cs
- DefaultValueMapping.cs
- NameValueSectionHandler.cs
- FigureParaClient.cs
- BuildProvidersCompiler.cs
- IdentityVerifier.cs
- IPPacketInformation.cs
- CheckBoxField.cs
- InvalidComObjectException.cs
- NavigationPropertyEmitter.cs
- PointKeyFrameCollection.cs
- ContentDisposition.cs
- XsltOutput.cs
- Size3D.cs
- XPathSelectionIterator.cs
- ImageListStreamer.cs
- QilStrConcat.cs
- PlaceHolder.cs
- Pen.cs
- Registry.cs
- KoreanLunisolarCalendar.cs
- DocumentPageTextView.cs
- ApplicationDirectory.cs
- OleAutBinder.cs
- XmlNamedNodeMap.cs
- Convert.cs
- DataGridViewCellFormattingEventArgs.cs
- TraceContext.cs
- SplitterEvent.cs
- CodeGenerator.cs
- SqlResolver.cs
- Stroke.cs
- CategoryAttribute.cs
- TextTreeInsertUndoUnit.cs
- ContentPosition.cs
- ScrollBar.cs