File: Core\CSharp\System\Windows\Media\TextFormatting\TextLine.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//-----------------------------------------------------------------------
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
//
//  File:      TextLine.cs
//
//  Contents:  Text line API
//
//  Spec:      http://team/sites/Avalon/Specs/Text%20Formatting%20API.doc
//
//  Created:   2-25-2003 Worachai Chaoweeraprasit (wchao)
//
//------------------------------------------------------------------------
 
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using MS.Internal.TextFormatting;
using MS.Internal.PresentationCore;
 
 
namespace System.Windows.Media.TextFormatting
{
    /// <summary>
    /// Once a line is complete, FormatLine returns a TextLine object to the client. 
    /// The text layout client may then use the TextLines measurement and drawing methods.
    /// </summary>
    public abstract class TextLine : ITextMetrics, IDisposable
    {
        /// <summary>
        /// Constructing a TextLine. This constructor must be called for every class that is inherited from TextLine
        /// </summary>
        /// <param name="pixelsPerDip">pixelsPerDip should be set to the TextSource's PixelsPerDip</param>
        protected TextLine(double pixelsPerDip)
        {
            _pixelsPerDip = pixelsPerDip;
        }
 
        protected TextLine()
        {
 
        }
 
        /// <summary>
        /// Clean up text line internal resource
        /// </summary>
        public abstract void Dispose();
 
 
        /// <summary>
        /// Client to draw the line
        /// </summary>
        /// <param name="drawingContext">drawing context</param>
        /// <param name="origin">drawing origin</param>
        /// <param name="inversion">indicate the inversion of the drawing surface</param>
        public abstract void Draw(
            DrawingContext      drawingContext,
            Point               origin,
            InvertAxes          inversion
            );
 
 
        /// <summary>
        /// Client to collapse the line and get a collapsed line that fits for display
        /// </summary>
        /// <param name="collapsingPropertiesList">a list of collapsing properties</param>
        public abstract TextLine Collapse(
            params TextCollapsingProperties[]   collapsingPropertiesList
            );
 
 
        /// <summary>
        /// Client to get a collection of collapsed cha----r ranges after a line has been collapsed
        /// </summary>
        public abstract IList<TextCollapsedRange> GetTextCollapsedRanges();
 
 
        /// <summary>
        /// Client to get the character hit corresponding to the specified 
        /// distance from the beginning of the line.
        /// </summary>
        /// <param name="distance">distance in text flow direction from the beginning of the line</param>
        /// <returns>character hit</returns>
        public abstract CharacterHit GetCharacterHitFromDistance(
            double      distance
            );
 
        
        /// <summary>
        /// Client to get the distance from the beginning of the line from the specified 
        /// character hit.
        /// </summary>
        /// <param name="characterHit">character hit of the character to query the distance.</param>
        /// <returns>distance in text flow direction from the beginning of the line.</returns>
        public abstract double GetDistanceFromCharacterHit(
            CharacterHit    characterHit
            );
 
 
        /// <summary>
        /// Client to get the next character hit for caret navigation
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <returns>the next character hit</returns>
        public abstract CharacterHit GetNextCaretCharacterHit(
            CharacterHit    characterHit
            );
 
 
        /// <summary>
        /// Client to get the previous character hit for caret navigation
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <returns>the previous character hit</returns>
        public abstract CharacterHit GetPreviousCaretCharacterHit(
            CharacterHit    characterHit
            );
 
 
        /// <summary>
        /// Client to get the previous character hit after backspacing
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <returns>the character hit after backspacing</returns>
        public abstract CharacterHit GetBackspaceCaretCharacterHit(
            CharacterHit    characterHit
            );
 
        public double PixelsPerDip
        {
            get { return _pixelsPerDip; }
            set { _pixelsPerDip = value; }
        }
 
        private double _pixelsPerDip = MS.Internal.FontCache.Util.PixelsPerDip;
 
        /// <summary>
        /// Determine whether the input character hit is a valid caret stop. 
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <param name="cpFirst">the starting cp index of the line</param>
        /// <remarks>
        /// It is used by Framework to iterate through each codepoint in the line to 
        /// see if the code point is a caret stop. In general, the leading edge of 
        /// codepoint is a valid caret stop if moving forward and then backward will 
        /// return back to it,  vice versa for the trailing edge of a codepoint. 
        /// </remarks>
        [FriendAccessAllowed]
        internal bool IsAtCaretCharacterHit(CharacterHit characterHit, int cpFirst)
        {   
            // TrailingLength is used as a flag to indicate whether the character 
            // hit is on the leading or trailing edge of the character.
            if (characterHit.TrailingLength == 0)
            {
                CharacterHit nextHit = GetNextCaretCharacterHit(characterHit);
                if (nextHit == characterHit)
                {
                    // At this point we only know that no caret stop is available 
                    // after the input, we caliberate the input to the end of the line.
                    nextHit = new CharacterHit(cpFirst + Length - 1, 1);
                }
 
                CharacterHit previousHit = GetPreviousCaretCharacterHit(nextHit);
                return previousHit == characterHit;
            }
            else
            {
                CharacterHit previousHit = GetPreviousCaretCharacterHit(characterHit);              
                CharacterHit nextHit     = GetNextCaretCharacterHit(previousHit);
                return nextHit == characterHit; 
            }
        }
        
 
 
        /// <summary>
        /// Client to get an array of bounding rectangles of a range of characters within a text line.
        /// </summary>
        /// <param name="firstTextSourceCharacterIndex">index of first character of specified range</param>
        /// <param name="textLength">number of characters of the specified range</param>
        /// <returns>an array of bounding rectangles.</returns>
        public abstract IList<TextBounds> GetTextBounds(
            int     firstTextSourceCharacterIndex,
            int     textLength
            );
 
 
        /// <summary>
        /// Client to get a collection of TextRun span objects within a line
        /// </summary>
        public abstract IList<TextSpan<TextRun>> GetTextRunSpans();
 
 
        /// <summary>
        /// Client to get IndexedGlyphRuns enumerable to enumerate each IndexedGlyphRun object 
        /// in the line. Through IndexedGlyphRun client can obtain glyph information of 
        /// a text source character. 
        /// </summary>
        public abstract IEnumerable<IndexedGlyphRun> GetIndexedGlyphRuns();        
 
 
        /// <summary>
        /// Client to get a boolean value indicates whether content of the line overflows 
        /// the specified paragraph width.
        /// </summary>
        public abstract bool HasOverflowed 
        { get; }
 
 
        /// <summary>
        /// Client to get a boolean value indicates whether a line has been collapsed
        /// </summary>
        public abstract bool HasCollapsed 
        { get; }
 
 
        /// <summary>
        /// Client to get a Boolean flag indicating whether the line is truncated in the 
        /// middle of a word. This flag is set only when TextParagraphProperties.TextWrapping 
        /// is set to TextWrapping.Wrap and a single word is longer than the formatting 
        /// paragraph width. In such situation, TextFormatter truncates the line in the middle 
        /// of the word to honor the desired behavior specified by TextWrapping.Wrap setting.
        /// </summary>
        public virtual bool IsTruncated
        {
            get { return false; }
        }
 
 
        /// <summary>
        /// Client to acquire a state at the point where line is broken by line breaking process; 
        /// can be null when the line ends by the ending of the paragraph. Client may pass this 
        /// value back to TextFormatter as an input argument to TextFormatter.FormatLine when 
        /// formatting the next line within the same paragraph.
        /// </summary>
        public abstract TextLineBreak GetTextLineBreak();
 
        #region ITextMetrics
 
        /// <summary>
        /// Client to get the number of text source positions of this line
        /// </summary>
        public abstract int Length 
        { get; }
 
 
        /// <summary>
        /// Client to get the number of whitespace characters at the end of the line.
        /// </summary>
        public abstract int TrailingWhitespaceLength 
        { get; }
 
 
        /// <summary>
        /// Client to get the number of characters following the last character 
        /// of the line that may trigger reformatting of the current line.
        /// </summary>
        public abstract int DependentLength 
        { get; }
 
 
        /// <summary>
        /// Client to get the number of newline characters at line end
        /// </summary>
        public abstract int NewlineLength 
        { get; }
 
 
        /// <summary>
        /// Client to get distance from paragraph start to line start
        /// </summary>
        public abstract double Start 
        { get; }
 
 
        /// <summary>
        /// Client to get the total width of this line
        /// </summary>
        public abstract double Width 
        { get; }
 
 
        /// <summary>
        /// Client to get the total width of this line including width of whitespace characters at the end of the line.
        /// </summary>
        public abstract double WidthIncludingTrailingWhitespace 
        { get; }
 
 
        /// <summary>
        /// Client to get the height of the line
        /// </summary>
        public abstract double Height 
        { get; }
 
 
        /// <summary>
        /// Client to get the height of the text (or other content) in the line; this property may differ from the Height
        /// property if the client specified the line height
        /// </summary>
        public abstract double TextHeight
        { get; }
 
 
        /// <summary>
        /// Client to get the height of the actual black of the line
        /// </summary>
        public abstract double Extent 
        { get; }
 
 
        /// <summary>
        /// Client to get the distance from top to baseline of this text line
        /// </summary>
        public abstract double Baseline 
        { get; }
 
 
        /// <summary>
        /// Client to get the distance from the top of the text (or other content) to the baseline of this text line;
        /// this property may differ from the Baseline property if the client specified the line height
        /// </summary>
        public abstract double TextBaseline
        { get; }
 
 
        /// <summary>
        /// Client to get the distance from the before edge of line height 
        /// to the baseline of marker of the line if any.
        /// </summary>
        public abstract double MarkerBaseline 
        { get; }
 
 
        /// <summary>
        /// Client to get the overall height of the list items marker of the line if any.
        /// </summary>
        public abstract double MarkerHeight 
        { get; }
 
 
        /// <summary>
        /// Client to get the distance covering all black preceding the leading edge of the line.
        /// </summary>
        public abstract double OverhangLeading 
        { get; }
 
 
        /// <summary>
        /// Client to get the distance covering all black following the trailing edge of the line.
        /// </summary>
        public abstract double OverhangTrailing 
        { get; }
 
 
        /// <summary>
        /// Client to get the distance from the after edge of line height to the after edge of the extent of the line.
        /// </summary>
        public abstract double OverhangAfter 
        { get; }       
        #endregion
    }
 
 
    /// <summary>
    /// Indicate the inversion of axes of the drawing surface
    /// </summary>
    [Flags]
    public enum InvertAxes
    {
        /// <summary>
        /// Drawing surface is not inverted in either axis
        /// </summary>
        None = 0,
 
        /// <summary>
        /// Drawing surface is inverted in horizontal axis
        /// </summary>
        Horizontal = 1,
 
        /// <summary>
        /// Drawing surface is inverted in vertical axis
        /// </summary>
        Vertical = 2,
 
        /// <summary>
        /// Drawing surface is inverted in both axes
        /// </summary>
        Both = (Horizontal | Vertical),
    }
}