Line.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Text / Line.cs / 1305600 / Line.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: Line.cs 
//
// Description: Text line formatter. 
// 
// History:
//  04/25/2003 : [....] - moving from Avalon branch. 
//
//---------------------------------------------------------------------------

using System; 
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.PtsHost; 

namespace MS.Internal.Text 
{ 
    // ---------------------------------------------------------------------
    // Text line formatter. 
    // ---------------------------------------------------------------------
    internal abstract class Line : TextSource, IDisposable
    {
        // ------------------------------------------------------------------ 
        //
        //  IDisposable Implementation 
        // 
        // -----------------------------------------------------------------
 
        #region IDisposable Implementation

        // ------------------------------------------------------------------
        // 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);
        } 
 
        #endregion IDisposable Implementation
 
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        //--------------------------------------------------------------------
 
        #region Internal Methods 

        // ----------------------------------------------------------------- 
        // Constructor.
        //
        //      owner - owner of the line.
        // ----------------------------------------------------------------- 
        internal Line(System.Windows.Controls.TextBlock owner)
        { 
            _owner = owner; 
            _textAlignment = owner.TextAlignment;
            _showParagraphEllipsis = false; 
            _wrappingWidth = _owner.RenderSize.Width;
        }

        // ----------------------------------------------------------------- 
        // Create and format text line.
        // 
        //      lineStartIndex - index of the first character in the line 
        //      width - wrapping width of the line
        //      lineProperties - properties of the line 
        //      textRunCache - run cache used by text formatter
        //      showParagraphEllipsis - true if paragraph ellipsis is shown
        //                              at the end of the line
        // ------------------------------------------------------------------ 
        internal void Format(int dcp, double width, TextParagraphProperties lineProperties, TextLineBreak textLineBreak, TextRunCache textRunCache, bool showParagraphEllipsis)
        { 
#if TEXTPANELLAYOUTDEBUG 
            TextPanelDebug.IncrementCounter("Line.Format", TextPanelDebug.Category.TextView);
#endif 
            _mirror = (lineProperties.FlowDirection == FlowDirection.RightToLeft);
            _dcp = dcp;
            _showParagraphEllipsis = showParagraphEllipsis;
            _wrappingWidth = width; 
            _line = _owner.TextFormatter.FormatLine(this, dcp, width, lineProperties, textLineBreak, textRunCache);
        } 
 
        // -----------------------------------------------------------------
        // Arrange content of formatted line. 
        //
        //      vc - Visual collection of the parent.
        //      lineOffset - Offset of the line.
        // ------------------------------------------------------------------ 
        internal virtual void Arrange(VisualCollection vc, Vector lineOffset)
        { 
        } 

        // ------------------------------------------------------------------ 
        // Render formatted line.
        //
        //      ctx - Drawing context to be used for rendering.
        //      lineOffset - Offset of the line. 
        //      wrappingWidth - Wrapping width for the line.
        // ----------------------------------------------------------------- 
        internal void Render(DrawingContext ctx, Point lineOffset) 
        {
            Debug.Assert(_line != null, "Rendering line that has not been measured yet."); 

            // Handle text trimming.
            System.Windows.Media.TextFormatting.TextLine line = _line;
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) 
            {
                line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Debug.Assert(line.HasCollapsed, "Line has not been collapsed"); 
            }
 
            double delta = CalculateXOffsetShift();
            line.Draw(ctx, new Point(lineOffset.X + delta, lineOffset.Y), (_mirror ? InvertAxes.Horizontal : InvertAxes.None));
        }
 
        // ------------------------------------------------------------------
        // Retrieve bounds of an object/character at specified text position. 
        // 
        //      characterIndex - position of an object/character
        //      flowDirection - flow direction of object/character 
        //
        // Returns: Bounds of an object/character.
        // -----------------------------------------------------------------
        internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection) 
        {
            return GetBoundsFromPosition(characterIndex, 1, out flowDirection); 
        } 

        ///  
        /// Returns an ArrayList of rectangles (Rect) that form the bounds of the region specified between
        /// the start and end points
        /// 
        ///  
        /// int offset indicating the starting point of the region for which bounds are required
        ///  
        /// Length in characters of the region for which bounds are required 
        /// 
        ///  
        /// Offset of line in x direction, to be added to line bounds to get actual rectangle for line
        /// 
        /// 
        /// Offset of line in y direction, to be added to line bounds to get actual rectangle for line 
        /// 
        ///  
        /// 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 List GetRangeBounds(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;
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            {
                // We should not shift offset in this case 
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                textBounds = line.GetTextBounds(cp, cch);
            } 
            else
            {
                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 - distance relative to the beginning of the line
        // 
        // Returns: 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();
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            {
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                return line.GetCharacterHitFromDistance(distance); 
            }
            return _line.GetCharacterHitFromDistance(distance - delta); 
        }

        //--------------------------------------------------------------------
        // Retrieve text position for next caret position 
        //
        // index: CharacterHit for current position 
        // 
        // Returns: Text position index.
        //------------------------------------------------------------------- 
        internal CharacterHit GetNextCaretCharacterHit(CharacterHit index)
        {
            return _line.GetNextCaretCharacterHit(index);
        } 

        //-------------------------------------------------------------------- 
        // Retrieve text position for previous caret position 
        //
        // index: CharacterHit for current position 
        //
        // Returns: Text position index.
        //--------------------------------------------------------------------
        internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index) 
        {
            return _line.GetPreviousCaretCharacterHit(index); 
        } 

        //------------------------------------------------------------------- 
        // Retrieve text position for backspace caret position
        //
        // index: CharacterHit for current position
        // 
        // Returns: 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);
        }
 
        // -----------------------------------------------------------------
        // Find out if there are any inline objects. 
        // ----------------------------------------------------------------- 
        internal virtual bool HasInlineObjects()
        { 
            return false;
        }

        // ----------------------------------------------------------------- 
        //  Hit tests to the correct ContentElement within the line.
        // 
        //      offset - offset within the line. 
        //
        // Returns: ContentElement which has been hit. 
        // ------------------------------------------------------------------
        internal virtual IInputElement InputHitTest(double offset)
        {
            return null; 
        }
 
        ///  
        /// Passes linebreak object back up from contained line
        ///  
        internal TextLineBreak GetTextLineBreak()
        {
            if(_line == null)
            { 
                return null;
            } 
 
            return _line.GetTextLineBreak();
        } 

        // -----------------------------------------------------------------
        // Get length of content hidden by ellipses.
        // 
        //      wrappingWidth - Wrapping width for the line.
        // 
        // Returns: Length of collapsed content (number of characters hidden 
        //          by ellipses).
        // ------------------------------------------------------------------ 
        internal int GetEllipsesLength()
        {
            // There are no ellipses, if:
            // * there is no overflow in the line 
            // * text trimming is turned off
            if (!_line.HasOverflowed) { return 0; } 
            if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) { return 0; } 

            // Create collapsed text line to get length of collapsed content. 
            System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
            Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed");
            IList collapsedRanges = collapsedLine.GetTextCollapsedRanges();
            if (collapsedRanges != null) 
            {
                Debug.Assert(collapsedRanges.Count == 1, "Multiple collapsed ranges are not supported."); 
                TextCollapsedRange collapsedRange = collapsedRanges[0]; 
                return collapsedRange.Length;
            } 
            return 0;
        }

 
        // ------------------------------------------------------------------
        // Gets width of content, collapsed at wrappingWidth (if necessary) 
        // 
        //      wrappingWidth - Wrapping width for the line.
        // 
        // Returns: Width of content, after collapse (may be greater than wrappingWidth)
        //
        // -----------------------------------------------------------------
        internal double GetCollapsedWidth() 
        {
            // There are no ellipses, if: 
            // * there is no overflow in the line 
            // * text trimming is turned off
            if (!_line.HasOverflowed) 
            {
                return Width;
            }
            if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) 
            {
                return Width; 
            } 

            // Create collapsed text line to get length of collapsed content. 
            System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
            Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed");

            return collapsedLine.Width; 
        }
 
        #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; 
                }
            } 
        } 

        // ------------------------------------------------------------------ 
        // Distance from the beginning of paragraph edge to the line edge.
        // -----------------------------------------------------------------
        internal double Start
        { 
            get
            { 
                if (IsXOffsetAdjusted) 
                {
                    return _line.Start + CalculateXOffsetShift(); 
                }
                else
                {
                    return _line.Start; 
                }
            } 
        } 

        // ------------------------------------------------------------------ 
        // Height of the line; line advance distance.
        // ------------------------------------------------------------------
        internal double Height { get { return _line.Height; } }
 
        // -----------------------------------------------------------------
        // Distance from top to baseline of this text line. 
        // ------------------------------------------------------------------ 
        internal double BaselineOffset { get { return _line.Baseline; } }
 
        // -----------------------------------------------------------------
        // 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 ? _syntheticCharacterLength : 0); } }

        // ----------------------------------------------------------------- 
        // Length of the line excluding any synthetic characters and line breaks.
        // ------------------------------------------------------------------ 
        internal int ContentLength { get { return _line.Length - _line.NewlineLength; } } 

        #endregion Internal Properties 

        //--------------------------------------------------------------------
        //
        //  Protected Methods 
        //
        //------------------------------------------------------------------- 
 
        #region Protected Methods
 
        // ------------------------------------------------------------------
        // Retrieve bounds of an object/character at specified text index.
        //
        //      cp - character index of an object/character 
        //      cch - number of positions occupied by object/character
        //      flowDirection - flow direction of object/character 
        // 
        // Returns: Bounds of an object/character.
        // ----------------------------------------------------------------- 
        protected Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection)
        {
            Rect rect;
 
            // Adjust x offset for trailing spaces
            double delta = CalculateXOffsetShift(); 
            IList textBounds; 
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            { 
                // We should not shift offset in this case
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                textBounds = line.GetTextBounds(cp, cch);
            } 
            else 
            {
                textBounds = _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)
            { 
                Debug.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;
        } 

        // -----------------------------------------------------------------
        // Get collapsing properties.
        // 
        //      wrappingWidth - wrapping width for collapsed line.
        //      paraProperties - paragraph properties. 
        // 
        // Returns: Line collapsing properties.
        // ----------------------------------------------------------------- 
        protected TextCollapsingProperties GetCollapsingProps(double wrappingWidth, LineProperties paraProperties)
        {
            Debug.Assert(paraProperties.TextTrimming != TextTrimming.None, "Text trimming must be enabled.");
            TextCollapsingProperties collapsingProps; 
            if (paraProperties.TextTrimming == TextTrimming.CharacterEllipsis)
            { 
                collapsingProps = new TextTrailingCharacterEllipsis(wrappingWidth, paraProperties.DefaultTextRunProperties); 
            }
            else 
            {
                collapsingProps = new TextTrailingWordEllipsis(wrappingWidth, paraProperties.DefaultTextRunProperties);
            }
 
            return collapsingProps;
        } 
 
        /// 
        /// Returns amount of shift for X-offset to render trailing spaces 
        /// 
        protected double CalculateXOffsetShift()
        {
            // Assert that textblock autosize is working correctly and that moving the offset back 
            // will not result in the front of the line being taken off rendered area
            if (IsXOffsetAdjusted) 
            { 
                if (_textAlignment == TextAlignment.Center)
                { 
                    // Return trailing spaces length divided by two so line remains centered
                    return (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2;
                }
                else 
                {
                    return (_line.Width - _line.WidthIncludingTrailingWhitespace); 
                } 
            }
            else 
            {
                return 0.0;
            }
        } 

        #endregion Protected Methods 
 
        //--------------------------------------------------------------------
        // 
        //  Protected Properites
        //
        //-------------------------------------------------------------------
 
        #region Protected Properties
 
        ///  
        /// True if eliipsis is displayed in the line
        ///  
        protected bool ShowEllipsis
        {
            get
            { 
                if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None)
                { 
                    return false; 
                }
                if (_line.HasOverflowed || _showParagraphEllipsis) 
                {
                    return true;
                }
                return false; 
            }
        } 
 
        /// 
        /// True if line ends in hard line break 
        /// 
        protected bool HasLineBreak
        {
            get 
            {
                return (_line.NewlineLength > 0); 
            } 
        }
 
        /// 
        /// True if line's X-offset needs adjustment to render trailing spaces
        /// 
        protected bool IsXOffsetAdjusted 
        {
            get 
            { 
                return ((_textAlignment == TextAlignment.Right || _textAlignment == 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
        ///  
        protected bool IsWidthAdjusted 
        {
            get 
            {
                bool adjusted = false;

                // Trailing spaces rendered only around hard breaks 
                if (HasLineBreak || EndOfParagraph)
                { 
                    // Lines with ellipsis are not shifted because ellipsis would not appear after trailing spaces 
                    if (!ShowEllipsis)
                    { 
                        adjusted = true;
                    }
                }
                return adjusted; 
            }
        } 
 
        #endregion Protected Properties
 

        //--------------------------------------------------------------------
        //
        //  Private Fields 
        //
        //-------------------------------------------------------------------- 
 
        #region Private Fields
 
        // -----------------------------------------------------------------
        // Owner of the line.
        // ------------------------------------------------------------------
        protected System.Windows.Controls.TextBlock _owner; 

        // ----------------------------------------------------------------- 
        // Cached text line. 
        // -----------------------------------------------------------------
        protected System.Windows.Media.TextFormatting.TextLine _line; 

        // -----------------------------------------------------------------
        // Index of the first character in the line.
        // ------------------------------------------------------------------ 
        protected int _dcp;
 
        // ----------------------------------------------------------------- 
        // Synthetic character length.
        // ------------------------------------------------------------------ 
        protected static int _syntheticCharacterLength = 1;

        // ------------------------------------------------------------------
        // Is text mirrored? 
        // -----------------------------------------------------------------
        protected bool _mirror; 
 
        /// 
        ///  Alignment direction of line. Set during formatting. 
        /// 
        protected TextAlignment _textAlignment;

        ///  
        /// Does the line habe paragraph ellipsis. This is determined during formatting depending upon
        /// the type of line properties passed. 
        ///  
        protected bool _showParagraphEllipsis;
 
        /// 
        /// Wrapping width of line
        /// 
        protected double _wrappingWidth; 

        #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: Line.cs 
//
// Description: Text line formatter. 
// 
// History:
//  04/25/2003 : [....] - moving from Avalon branch. 
//
//---------------------------------------------------------------------------

using System; 
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.PtsHost; 

namespace MS.Internal.Text 
{ 
    // ---------------------------------------------------------------------
    // Text line formatter. 
    // ---------------------------------------------------------------------
    internal abstract class Line : TextSource, IDisposable
    {
        // ------------------------------------------------------------------ 
        //
        //  IDisposable Implementation 
        // 
        // -----------------------------------------------------------------
 
        #region IDisposable Implementation

        // ------------------------------------------------------------------
        // 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);
        } 
 
        #endregion IDisposable Implementation
 
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        //--------------------------------------------------------------------
 
        #region Internal Methods 

        // ----------------------------------------------------------------- 
        // Constructor.
        //
        //      owner - owner of the line.
        // ----------------------------------------------------------------- 
        internal Line(System.Windows.Controls.TextBlock owner)
        { 
            _owner = owner; 
            _textAlignment = owner.TextAlignment;
            _showParagraphEllipsis = false; 
            _wrappingWidth = _owner.RenderSize.Width;
        }

        // ----------------------------------------------------------------- 
        // Create and format text line.
        // 
        //      lineStartIndex - index of the first character in the line 
        //      width - wrapping width of the line
        //      lineProperties - properties of the line 
        //      textRunCache - run cache used by text formatter
        //      showParagraphEllipsis - true if paragraph ellipsis is shown
        //                              at the end of the line
        // ------------------------------------------------------------------ 
        internal void Format(int dcp, double width, TextParagraphProperties lineProperties, TextLineBreak textLineBreak, TextRunCache textRunCache, bool showParagraphEllipsis)
        { 
#if TEXTPANELLAYOUTDEBUG 
            TextPanelDebug.IncrementCounter("Line.Format", TextPanelDebug.Category.TextView);
#endif 
            _mirror = (lineProperties.FlowDirection == FlowDirection.RightToLeft);
            _dcp = dcp;
            _showParagraphEllipsis = showParagraphEllipsis;
            _wrappingWidth = width; 
            _line = _owner.TextFormatter.FormatLine(this, dcp, width, lineProperties, textLineBreak, textRunCache);
        } 
 
        // -----------------------------------------------------------------
        // Arrange content of formatted line. 
        //
        //      vc - Visual collection of the parent.
        //      lineOffset - Offset of the line.
        // ------------------------------------------------------------------ 
        internal virtual void Arrange(VisualCollection vc, Vector lineOffset)
        { 
        } 

        // ------------------------------------------------------------------ 
        // Render formatted line.
        //
        //      ctx - Drawing context to be used for rendering.
        //      lineOffset - Offset of the line. 
        //      wrappingWidth - Wrapping width for the line.
        // ----------------------------------------------------------------- 
        internal void Render(DrawingContext ctx, Point lineOffset) 
        {
            Debug.Assert(_line != null, "Rendering line that has not been measured yet."); 

            // Handle text trimming.
            System.Windows.Media.TextFormatting.TextLine line = _line;
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None) 
            {
                line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Debug.Assert(line.HasCollapsed, "Line has not been collapsed"); 
            }
 
            double delta = CalculateXOffsetShift();
            line.Draw(ctx, new Point(lineOffset.X + delta, lineOffset.Y), (_mirror ? InvertAxes.Horizontal : InvertAxes.None));
        }
 
        // ------------------------------------------------------------------
        // Retrieve bounds of an object/character at specified text position. 
        // 
        //      characterIndex - position of an object/character
        //      flowDirection - flow direction of object/character 
        //
        // Returns: Bounds of an object/character.
        // -----------------------------------------------------------------
        internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection) 
        {
            return GetBoundsFromPosition(characterIndex, 1, out flowDirection); 
        } 

        ///  
        /// Returns an ArrayList of rectangles (Rect) that form the bounds of the region specified between
        /// the start and end points
        /// 
        ///  
        /// int offset indicating the starting point of the region for which bounds are required
        ///  
        /// Length in characters of the region for which bounds are required 
        /// 
        ///  
        /// Offset of line in x direction, to be added to line bounds to get actual rectangle for line
        /// 
        /// 
        /// Offset of line in y direction, to be added to line bounds to get actual rectangle for line 
        /// 
        ///  
        /// 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 List GetRangeBounds(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;
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            {
                // We should not shift offset in this case 
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                textBounds = line.GetTextBounds(cp, cch);
            } 
            else
            {
                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 - distance relative to the beginning of the line
        // 
        // Returns: 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();
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            {
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); 
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                return line.GetCharacterHitFromDistance(distance); 
            }
            return _line.GetCharacterHitFromDistance(distance - delta); 
        }

        //--------------------------------------------------------------------
        // Retrieve text position for next caret position 
        //
        // index: CharacterHit for current position 
        // 
        // Returns: Text position index.
        //------------------------------------------------------------------- 
        internal CharacterHit GetNextCaretCharacterHit(CharacterHit index)
        {
            return _line.GetNextCaretCharacterHit(index);
        } 

        //-------------------------------------------------------------------- 
        // Retrieve text position for previous caret position 
        //
        // index: CharacterHit for current position 
        //
        // Returns: Text position index.
        //--------------------------------------------------------------------
        internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index) 
        {
            return _line.GetPreviousCaretCharacterHit(index); 
        } 

        //------------------------------------------------------------------- 
        // Retrieve text position for backspace caret position
        //
        // index: CharacterHit for current position
        // 
        // Returns: 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);
        }
 
        // -----------------------------------------------------------------
        // Find out if there are any inline objects. 
        // ----------------------------------------------------------------- 
        internal virtual bool HasInlineObjects()
        { 
            return false;
        }

        // ----------------------------------------------------------------- 
        //  Hit tests to the correct ContentElement within the line.
        // 
        //      offset - offset within the line. 
        //
        // Returns: ContentElement which has been hit. 
        // ------------------------------------------------------------------
        internal virtual IInputElement InputHitTest(double offset)
        {
            return null; 
        }
 
        ///  
        /// Passes linebreak object back up from contained line
        ///  
        internal TextLineBreak GetTextLineBreak()
        {
            if(_line == null)
            { 
                return null;
            } 
 
            return _line.GetTextLineBreak();
        } 

        // -----------------------------------------------------------------
        // Get length of content hidden by ellipses.
        // 
        //      wrappingWidth - Wrapping width for the line.
        // 
        // Returns: Length of collapsed content (number of characters hidden 
        //          by ellipses).
        // ------------------------------------------------------------------ 
        internal int GetEllipsesLength()
        {
            // There are no ellipses, if:
            // * there is no overflow in the line 
            // * text trimming is turned off
            if (!_line.HasOverflowed) { return 0; } 
            if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) { return 0; } 

            // Create collapsed text line to get length of collapsed content. 
            System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
            Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed");
            IList collapsedRanges = collapsedLine.GetTextCollapsedRanges();
            if (collapsedRanges != null) 
            {
                Debug.Assert(collapsedRanges.Count == 1, "Multiple collapsed ranges are not supported."); 
                TextCollapsedRange collapsedRange = collapsedRanges[0]; 
                return collapsedRange.Length;
            } 
            return 0;
        }

 
        // ------------------------------------------------------------------
        // Gets width of content, collapsed at wrappingWidth (if necessary) 
        // 
        //      wrappingWidth - Wrapping width for the line.
        // 
        // Returns: Width of content, after collapse (may be greater than wrappingWidth)
        //
        // -----------------------------------------------------------------
        internal double GetCollapsedWidth() 
        {
            // There are no ellipses, if: 
            // * there is no overflow in the line 
            // * text trimming is turned off
            if (!_line.HasOverflowed) 
            {
                return Width;
            }
            if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None) 
            {
                return Width; 
            } 

            // Create collapsed text line to get length of collapsed content. 
            System.Windows.Media.TextFormatting.TextLine collapsedLine = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
            Debug.Assert(collapsedLine.HasCollapsed, "Line has not been collapsed");

            return collapsedLine.Width; 
        }
 
        #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; 
                }
            } 
        } 

        // ------------------------------------------------------------------ 
        // Distance from the beginning of paragraph edge to the line edge.
        // -----------------------------------------------------------------
        internal double Start
        { 
            get
            { 
                if (IsXOffsetAdjusted) 
                {
                    return _line.Start + CalculateXOffsetShift(); 
                }
                else
                {
                    return _line.Start; 
                }
            } 
        } 

        // ------------------------------------------------------------------ 
        // Height of the line; line advance distance.
        // ------------------------------------------------------------------
        internal double Height { get { return _line.Height; } }
 
        // -----------------------------------------------------------------
        // Distance from top to baseline of this text line. 
        // ------------------------------------------------------------------ 
        internal double BaselineOffset { get { return _line.Baseline; } }
 
        // -----------------------------------------------------------------
        // 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 ? _syntheticCharacterLength : 0); } }

        // ----------------------------------------------------------------- 
        // Length of the line excluding any synthetic characters and line breaks.
        // ------------------------------------------------------------------ 
        internal int ContentLength { get { return _line.Length - _line.NewlineLength; } } 

        #endregion Internal Properties 

        //--------------------------------------------------------------------
        //
        //  Protected Methods 
        //
        //------------------------------------------------------------------- 
 
        #region Protected Methods
 
        // ------------------------------------------------------------------
        // Retrieve bounds of an object/character at specified text index.
        //
        //      cp - character index of an object/character 
        //      cch - number of positions occupied by object/character
        //      flowDirection - flow direction of object/character 
        // 
        // Returns: Bounds of an object/character.
        // ----------------------------------------------------------------- 
        protected Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection)
        {
            Rect rect;
 
            // Adjust x offset for trailing spaces
            double delta = CalculateXOffsetShift(); 
            IList textBounds; 
            if (_line.HasOverflowed && _owner.ParagraphProperties.TextTrimming != TextTrimming.None)
            { 
                // We should not shift offset in this case
                Invariant.Assert(DoubleUtil.AreClose(delta, 0));
                System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties));
                Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); 
                textBounds = line.GetTextBounds(cp, cch);
            } 
            else 
            {
                textBounds = _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)
            { 
                Debug.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;
        } 

        // -----------------------------------------------------------------
        // Get collapsing properties.
        // 
        //      wrappingWidth - wrapping width for collapsed line.
        //      paraProperties - paragraph properties. 
        // 
        // Returns: Line collapsing properties.
        // ----------------------------------------------------------------- 
        protected TextCollapsingProperties GetCollapsingProps(double wrappingWidth, LineProperties paraProperties)
        {
            Debug.Assert(paraProperties.TextTrimming != TextTrimming.None, "Text trimming must be enabled.");
            TextCollapsingProperties collapsingProps; 
            if (paraProperties.TextTrimming == TextTrimming.CharacterEllipsis)
            { 
                collapsingProps = new TextTrailingCharacterEllipsis(wrappingWidth, paraProperties.DefaultTextRunProperties); 
            }
            else 
            {
                collapsingProps = new TextTrailingWordEllipsis(wrappingWidth, paraProperties.DefaultTextRunProperties);
            }
 
            return collapsingProps;
        } 
 
        /// 
        /// Returns amount of shift for X-offset to render trailing spaces 
        /// 
        protected double CalculateXOffsetShift()
        {
            // Assert that textblock autosize is working correctly and that moving the offset back 
            // will not result in the front of the line being taken off rendered area
            if (IsXOffsetAdjusted) 
            { 
                if (_textAlignment == TextAlignment.Center)
                { 
                    // Return trailing spaces length divided by two so line remains centered
                    return (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2;
                }
                else 
                {
                    return (_line.Width - _line.WidthIncludingTrailingWhitespace); 
                } 
            }
            else 
            {
                return 0.0;
            }
        } 

        #endregion Protected Methods 
 
        //--------------------------------------------------------------------
        // 
        //  Protected Properites
        //
        //-------------------------------------------------------------------
 
        #region Protected Properties
 
        ///  
        /// True if eliipsis is displayed in the line
        ///  
        protected bool ShowEllipsis
        {
            get
            { 
                if (_owner.ParagraphProperties.TextTrimming == TextTrimming.None)
                { 
                    return false; 
                }
                if (_line.HasOverflowed || _showParagraphEllipsis) 
                {
                    return true;
                }
                return false; 
            }
        } 
 
        /// 
        /// True if line ends in hard line break 
        /// 
        protected bool HasLineBreak
        {
            get 
            {
                return (_line.NewlineLength > 0); 
            } 
        }
 
        /// 
        /// True if line's X-offset needs adjustment to render trailing spaces
        /// 
        protected bool IsXOffsetAdjusted 
        {
            get 
            { 
                return ((_textAlignment == TextAlignment.Right || _textAlignment == 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
        ///  
        protected bool IsWidthAdjusted 
        {
            get 
            {
                bool adjusted = false;

                // Trailing spaces rendered only around hard breaks 
                if (HasLineBreak || EndOfParagraph)
                { 
                    // Lines with ellipsis are not shifted because ellipsis would not appear after trailing spaces 
                    if (!ShowEllipsis)
                    { 
                        adjusted = true;
                    }
                }
                return adjusted; 
            }
        } 
 
        #endregion Protected Properties
 

        //--------------------------------------------------------------------
        //
        //  Private Fields 
        //
        //-------------------------------------------------------------------- 
 
        #region Private Fields
 
        // -----------------------------------------------------------------
        // Owner of the line.
        // ------------------------------------------------------------------
        protected System.Windows.Controls.TextBlock _owner; 

        // ----------------------------------------------------------------- 
        // Cached text line. 
        // -----------------------------------------------------------------
        protected System.Windows.Media.TextFormatting.TextLine _line; 

        // -----------------------------------------------------------------
        // Index of the first character in the line.
        // ------------------------------------------------------------------ 
        protected int _dcp;
 
        // ----------------------------------------------------------------- 
        // Synthetic character length.
        // ------------------------------------------------------------------ 
        protected static int _syntheticCharacterLength = 1;

        // ------------------------------------------------------------------
        // Is text mirrored? 
        // -----------------------------------------------------------------
        protected bool _mirror; 
 
        /// 
        ///  Alignment direction of line. Set during formatting. 
        /// 
        protected TextAlignment _textAlignment;

        ///  
        /// Does the line habe paragraph ellipsis. This is determined during formatting depending upon
        /// the type of line properties passed. 
        ///  
        protected bool _showParagraphEllipsis;
 
        /// 
        /// Wrapping width of line
        /// 
        protected double _wrappingWidth; 

        #endregion Private Fields 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK