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
- EntityDataSourceWrapperCollection.cs
- ProfileGroupSettings.cs
- SqlRowUpdatedEvent.cs
- QuadraticBezierSegment.cs
- ProcessThreadCollection.cs
- CombinedGeometry.cs
- WSTrustFeb2005.cs
- ListViewDeleteEventArgs.cs
- ViewCellSlot.cs
- WebPartZoneBaseDesigner.cs
- RuleInfoComparer.cs
- XmlSchemaExternal.cs
- COM2PropertyDescriptor.cs
- xmlformatgeneratorstatics.cs
- ManageRequest.cs
- NameScope.cs
- StringComparer.cs
- OdbcTransaction.cs
- DoubleAnimationUsingPath.cs
- _AcceptOverlappedAsyncResult.cs
- DependencyObjectPropertyDescriptor.cs
- CellLabel.cs
- PrintPreviewGraphics.cs
- Assert.cs
- DataGridViewCellValueEventArgs.cs
- LongValidatorAttribute.cs
- GlobalizationSection.cs
- EasingKeyFrames.cs
- XPathMultyIterator.cs
- InvalidPrinterException.cs
- SuppressIldasmAttribute.cs
- ResourcePool.cs
- VisualState.cs
- GroupDescription.cs
- UserValidatedEventArgs.cs
- ReadOnlyCollectionBase.cs
- SequentialOutput.cs
- WebPartManagerInternals.cs
- SqlDataSourceView.cs
- GetPageNumberCompletedEventArgs.cs
- DuplicateDetector.cs
- SqlVisitor.cs
- AssemblyCache.cs
- NonSerializedAttribute.cs
- ChangePassword.cs
- WeakReference.cs
- SubMenuStyleCollection.cs
- JumpItem.cs
- XmlTypeAttribute.cs
- ListViewDeleteEventArgs.cs
- SqlDataSourceCommandEventArgs.cs
- LayoutSettings.cs
- StorageSetMapping.cs
- MobileControlsSectionHandler.cs
- Model3DCollection.cs
- CommandPlan.cs
- _AuthenticationState.cs
- MessageEnumerator.cs
- HtmlMobileTextWriter.cs
- DbConvert.cs
- ConstructorNeedsTagAttribute.cs
- CompiledXpathExpr.cs
- KnownColorTable.cs
- TemplateControlCodeDomTreeGenerator.cs
- MD5CryptoServiceProvider.cs
- PageRanges.cs
- SettingsPropertyNotFoundException.cs
- OdbcTransaction.cs
- DateTimeUtil.cs
- Size.cs
- ConfigXmlSignificantWhitespace.cs
- ExpandSegmentCollection.cs
- ObjectSelectorEditor.cs
- ValueType.cs
- ObjectTag.cs
- GeneralTransformGroup.cs
- DrawingVisual.cs
- WindowsTab.cs
- xmlNames.cs
- ColorConvertedBitmapExtension.cs
- DataColumnMappingCollection.cs
- MetaDataInfo.cs
- DocumentReferenceCollection.cs
- GridPatternIdentifiers.cs
- NativeMethodsOther.cs
- ValueChangedEventManager.cs
- ValueType.cs
- DbUpdateCommandTree.cs
- ReadOnlyTernaryTree.cs
- SrgsToken.cs
- DesignerWidgets.cs
- GridViewEditEventArgs.cs
- SubstitutionList.cs
- ObjectListCommandEventArgs.cs
- Baml2006ReaderSettings.cs
- Rect3D.cs
- EnumValidator.cs
- ReflectTypeDescriptionProvider.cs
- InputGestureCollection.cs
- StrokeNodeData.cs