File: Core\CSharp\MS\Internal\TextFormatting\LexicalChunk.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//-----------------------------------------------------------------------
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation
//
//  File:      LexicalChunk.cs
//
//  Contents:  Lexical chunk represents the character analysis of a piece of raw character string.
//
//  Created:   6-13-2005 Worachai Chaoweeraprasit (wchao)
//
//------------------------------------------------------------------------
 
 
using System;
using System.Windows.Media.TextFormatting;
using MS.Internal.Generic;
 
 
namespace MS.Internal.TextFormatting
{
    /// <summary>
    /// Lexical chunk represents the character analysis of a piece of raw character string.
    /// It contains the analyzing result of the string by the lexical services component i.e. 
    /// word-breaker or hyphenator or both. 
    /// 
    /// The number of character indices represented by a chunk may not map exactly to the same number
    /// of LSCP in the LS character position space. This is because two adjacent character indices in 
    /// a chunk may be mapped by two non-adjacent LSCP in the LS positions. Between two LSRun could 
    /// exist a hidden-run which occupies real LSCP but represents no actual displayable character. 
    /// 
    /// The mapping between the character offsets and the offsets to the correspondent LSCP is retained
    /// in a span vector that is indexed by the character offsets.
    /// </summary>
    internal struct LexicalChunk
    {
        private TextLexicalBreaks       _breaks;        // lexical breaks of chunk characters
        private SpanVector<int>         _ichVector;     // spans of offsets to the ich-correspondence LSCP
 
 
        internal TextLexicalBreaks Breaks
        {
            get { return _breaks; }
        }
 
 
        /// <summary>
        /// Boolean value indicates whether this chunk contains no valid break info
        /// </summary>
        internal bool IsNoBreak
        {
            get { return _breaks == null; }
        }
 
 
        /// <summary>
        /// Contruct lexical chunk from character analysis
        /// </summary>
        internal LexicalChunk(
            TextLexicalBreaks   breaks,
            SpanVector<int>     ichVector
            )
        {
            Invariant.Assert(breaks != null);
            _breaks = breaks;
            _ichVector = ichVector;
        }
 
 
        /// <summary>
        /// Convert the specified LSCP to character index
        /// </summary>
        internal int LSCPToCharacterIndex(int lsdcp)
        {
            if (_ichVector.Count > 0)
            {
                int ich = 0;
                int cchLast = 0;
                int lsdcpLast = 0;
 
                for (int i = 0; i < _ichVector.Count; i++)
                {
                    Span<int> span = _ichVector[i];
                    int lsdcpCurrent = span.Value;
 
                    if (lsdcpCurrent > lsdcp)
                    {
                        return ich - cchLast + Math.Min(cchLast, lsdcp - lsdcpLast);
                    }
 
                    ich += span.Length;
                    cchLast = span.Length;
                    lsdcpLast = lsdcpCurrent;
                }
 
                return ich - cchLast + Math.Min(cchLast, lsdcp - lsdcpLast);
            }
 
            return lsdcp;
        }
 
 
        /// <summary>
        /// Convert the specified character index to LSCP
        /// </summary>
        internal int CharacterIndexToLSCP(int ich)
        {
            if (_ichVector.Count > 0)
            {
                SpanRider<int> ichRider = new SpanRider<int>(_ichVector);
                ichRider.At(ich);
                return ichRider.CurrentValue + ich - ichRider.CurrentSpanStart;
            }
 
            return ich;
        }
    }
}