Line.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / MS / Internal / Text / Line.cs / 1 / 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;
            } 
        }
 
        #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