mongolianshape.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / Shaping / mongolianshape.cs / 1 / mongolianshape.cs

                            //---------------------------------------------------------------------- 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2004
// 
//  File:      MongolianShape.cs
// 
//  Contents:  Implementation of Mongolian shaping engine and its factory 
//
//  Created:   04-15-2004 Nick Beal (nbeal) 
//
//-----------------------------------------------------------------------
using System;
using System.Security; 
using System.Security.Permissions;
using System.Diagnostics; 
using System.Collections; 
using System.Globalization;
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using MS.Internal.FontCache;
using MS.Internal.FontFace; 
using MS.Internal.PresentationCore;
 
 
namespace MS.Internal.Shaping
{ 
    /// 
    /// MongolianCharClass - enumeration of Mongolian character classifications
    /// 
    ///  
    ///  These values are used as weights, so the order matters.  Every value
    ///  from JoiningBase up are valid for members of a cluster (ie, chars collected 
    ///  by MongolianClusterCop.AddToCluster()). 
    /// 
    internal enum MongolianCharClass : byte 
    {
        InvalidChar,          // invalid char class --
        NonJoiningBase,       // character does not join
        NNBSP, 
        Nirugu,               // U+180a (also U+1807)
        VowelSeparator, 
        ZWNJ, 
        ZWJ,
        Combine,              // only Mongolian diacritic 
        Variant,              // Variant selector
        JoiningBase,          // character joins on both sides
        NumberOfMongolianCharClasses,
    }; 

    ///  
    /// MongolianShapeClass - enumeration of Mongolian shape classifications 
    /// 
    ///  
    ///  These values are the shaping FSM shape definitions.  As the text run
    ///  is processed the shaping FSM assigns each character a shape.
    ///  The MongolianShapeInfo.mongolianTextFeatures array maps the first several of this enum's
    ///  values to the appropriate OT font feature to apply to the character. 
    /// 
    internal enum MongolianShapeClass : byte 
    { 
        SameShape,
        UninitializedState = SameShape,              // used for detecting initialization of state machine 
        NotShaped,
        IsolatedShape,
        FinalShape,
        LastShapeWithStateTable = FinalShape,        // used for Debug.Assert check 
        InitialShape,
        MedialShape, 
        InvalidBaseShape, 
    };
 

    /// 
    /// The MongolianShape, class defines the Mongolian Shaping Engine.
    ///  
    internal class MongolianShape : BaseShape
    { 
        ///  
        /// All required shaping Features (GSUB)
        ///  
        private static readonly Feature[]   _requiredFeatures    =
        {
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.GlyphCompositionDecomposition,1),
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.RequiredLigatures,1), 
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.ContextualAlternates,1),
        }; 
 
        private static readonly ScriptTags[] _supportedScripts = new ScriptTags[]{ScriptTags.Mongolian};
 
        /// 
        /// Constructor for the Mongolian Open Type Shaping Engine.
        /// 
        internal MongolianShape() 
        {
        } 
 
        public override ScriptTags[] SupportedScripts
        { 
            get
            {
                return _supportedScripts;
            } 
        }
 
        ///  
        /// MongolianShape.GetCharClassifier - Base shape
        ///  
        /// 
        ///     This will normally be overridden by derived shapers. It is used in OnLoadFont
        /// 
        protected override ShaperCharacterClassifier GetCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) 
        {
            return new MongolianCharClassifier (scriptTag, fontFace); 
        } 

        ///  
        ///     MongolianShape.GetGlyphs - Mongolian implementation of the GetGlyphs() helper function.
        /// 
        /// shaping currentRun
        /// Text item 
        /// number of glyphs
        ///  
        /// Critical - calls critical code 
        /// 
        [SecurityCritical] 
        protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item )
        {
            bool combinerCharSeen = false;;
            int charsCount = 0; 

            // initialize the features array 
            ShaperBuffers.InitializeFeatureList(0,(ushort)_requiredFeatures.Length); 
            if (ShaperBuffers.TextFeatures.FeaturesCount == 0)
            { 
                // The first time GetGlyphs is called, add the required features
                // (they'll always be first in the array from now on).
                for (int i = 0; i < _requiredFeatures.Length; ++i)
                { 
                    ShaperBuffers.TextFeatures.AddFeature( _requiredFeatures[i] );
                } 
            } 

            // initialize the cluster cop/state machine 
            MongolianShapeFSM  stateMachine = new MongolianShapeFSM( ShaperBuffers.TextFeatures );


            // Shape and initialize the glyph list 
            // process the char stream, creating shape info, applying features
            // as necessary 
            CharShapeInfo currShape; 
            while ( currentRun.GetNextShape (out currShape) )
            { 
                MongolianCharClass currClass = (MongolianCharClass)(currShape & CharShapeInfo.ShaperClassMask);

                if (currClass == MongolianCharClass.VowelSeparator)
                { 
                    // if the next character is not one of the expected vowels, then
                    // treat this instead as a NNBSP. 
                    char nextChar = currentRun.NextChar; 
                    if (nextChar != '\u1820' && nextChar != '\u1821')
                    { 
                        currClass = MongolianCharClass.NNBSP;
                    }
                }
 
                stateMachine.StepToNextState(ref currentRun, currClass);
 
                if (currClass == MongolianCharClass.Combine) 
                {
                        // we can only have one combining mark per cluster, and it can't be the first character. 
                        if (combinerCharSeen || charsCount == 0)  // if either of these restrictions aren't true, dotted circle time
                        {
                            //  Set the flag so that we know to insert a dotted circle...
                            currShape = CharShapeInfo.RequiresInsertedBase; 
                            stateMachine.ForceInvalidBaseState();
                        } 
 
                        combinerCharSeen = true;
                } 
                else
                {
                    combinerCharSeen = false;
                } 

 
                currentRun.SetGlyphPropertiesUsingShapeInfo(currShape); 
                ++charsCount;
            } 

            return (currentRun.GlyphsCount);    // we're done

 
        }
 
 
        /// 
        ///    MongolianShape.ApplySubstitutionFeatures - default implementation of the GetGlyphs() helper function. 
        /// 
        /// shaping currentRun
        /// Set of gsub features to be applied to the unicode run.
        /// result of applying features 
        /// 
        /// Critical - this method calls unsafe methods. 
        ///  
        [SecurityCritical]
        protected override OpenTypeLayoutResult ApplySubstitutionFeatures( 
                                                        ref ShapingWorkspace currentRun,
                                                        FeatureSet       featureSet  )
        {
                //  Apply the Mongolian Text Features from currentRun 
            ShaperFontClient fontClient = currentRun.FontClient;
            return fontClient.SubstituteGlyphs( 
                                ref currentRun, 
                                ShaperBuffers.TextFeatures.Features,
                                ShaperBuffers.TextFeatures.FeaturesCount ); 

        }

    } 

    ///  
    /// MongolianShapeFSM - Mongolian shaping state machine 
    /// 
    ///  
    /// 
    internal struct MongolianShapeFSM
    {
        private MongolianShapeClass _currentShape; 
        private MongolianShapeClass _previousShape;
        private ushort              _currentStateRowIx; 
        private ShaperFeaturesList  _featuresList; 

        ///  
        /// MongolianShapeFSM constructor
        /// 
        public MongolianShapeFSM ( ShaperFeaturesList featuresList )
        { 
            _previousShape       = MongolianShapeClass.UninitializedState;
            _currentShape        = MongolianShapeClass.NotShaped; 
 
            _featuresList = featuresList;
 
            // currentStartRowIx == the first entry in the active state table for the
            // current base char shape.
            _currentStateRowIx = 0;
 
        }
 
 
        /// 
        ///   MongolianShapeFSM.ForceInvalidBaseState - force state machine to state 
        /// 
        /// 
        ///   This is used to force the state machine to invalid base state
        ///   (useful when a 'dotted circle' base character is inserted) 
        /// 
        ///  
        /// Critical - calls critical code (UpdatePendingShape) 
        /// 
        [SecurityCritical] 
        internal void ForceInvalidBaseState ()
        {
            _previousShape = _currentShape =  MongolianShapeClass.NotShaped;                     // save new shape
            _currentStateRowIx = _rowFirstEntryIx[ (int)MongolianCharClass.InvalidChar ]; 
        }
 
 
        /// 
        /// MongolianShapeFSM.StartSyllable - start of new syllable (potentially) 
        /// 
        /// 
        /// This routine is used at the start of each cluster.  If the base + this
        /// first non-base char are the valid start of a new cluster, return 
        /// 
        /// the starting state 
        /// new settings for current shape info 
        /// 
        /// Critical - possibly calls critical code (ForceInvalidBaseState) 
        /// 
        [SecurityCritical]
        private void SetStartState ( ref ShapingWorkspace currentRun,
                                                MongolianCharClass  firstCharClass ) 
        {
            Debug.Assert (_currentShape == MongolianShapeClass.NotShaped && 
                          _currentStateRowIx == 0 , "Mongolian FSM SetStartState should not be called now."); 

            _previousShape = _currentShape; 

            switch (firstCharClass)
            {
                case MongolianCharClass.Combine: 
                case MongolianCharClass.Variant:
                case MongolianCharClass.VowelSeparator: 
                    ForceInvalidBaseState (); 
                    break;
 
                case MongolianCharClass.JoiningBase:
                    //   Joining base chars mean that the starting shape state is not NotShaped...
                    _currentShape =
                            (currentRun.CurrentCharIx == 0 && currentRun.HasLeadingJoin) ? 
                        MongolianShapeClass.FinalShape : MongolianShapeClass.IsolatedShape;
 
                    _currentStateRowIx = _baseTableFirstEntryIx[ (int)_currentShape ]; 
                    _featuresList.AddFeature(currentRun.CurrentCharIx,
                                             _mongolianTextFeatures[(int)_currentShape]); 
                    break;

                default:
 
                    _currentStateRowIx = _rowFirstEntryIx[ (int)firstCharClass ];
                    break; 
            } 

 
        }

        /// 
        ///   MongolianShapeFSM.StepToNextState - process the latest character. 
        /// 
        ///  
        ///   This routine steps the state machine to its next state 
        ///   based on the current state, the last character that caused a
        ///   state change and the next char. It may affect the previous character's 
        ///   shape if the feature id which is embedded in the shape info needs to be
        ///   changed.
        /// 
        /// new settings for current shape info 
        /// 
        /// Critical - calls critical code, uses unsafe accessors 
        ///  
        [SecurityCritical]
        internal void StepToNextState (  ref ShapingWorkspace currentRun, MongolianCharClass  nextCharClass ) 
        {
            Debug.Assert ( (int)nextCharClass < NumberOfCharClasses );

            if ( _currentShape != MongolianShapeClass.SameShape ) 
            {
                if (_previousShape == MongolianShapeClass.UninitializedState) 
                { 
                    SetStartState(ref currentRun, nextCharClass);
                    return; 
                }
            }

 
            // The state tables are abbreviated (only enough rows per state to cover
            // the events that are valid for the current state.  So, first check if 
            // we should be looking up the next state in the state table. 
            // get the shape state table entry.
            byte shapeTableEntry = _mongolianShapeStateTable[ _currentStateRowIx + (int)nextCharClass ]; 

            switch (shapeTableEntry)
            {
                case NoChange: 
                    // this means this latest character doesn't affect the current state AT ALL.
                    break; 
 
                case ToInvalidBase:
                    ForceInvalidBaseState(); 
                    break;

                default:
 
                    // keep track of where we're coming from.
                    _previousShape = _currentShape; 
                    // change our state (or shape) 
                    _currentShape = (MongolianShapeClass) (shapeTableEntry & 0xf);
                    Debug.Assert(_currentShape <= MongolianShapeClass.LastShapeWithStateTable); 

                    // adjust the state table indices..
                    _currentStateRowIx = (ushort)( _baseTableFirstEntryIx[ (int)_currentShape ]
                                                    + _rowFirstEntryIx[ (int)nextCharClass ]); 

                    break; 
            } 

            UpdateShapeInfo(ref currentRun, shapeTableEntry); 


        }
 

        ///  
        ///   MongolianShapeFSM.UpdateShapeInfo - process the latest character. 
        /// 
        ///  
        ///   This routine returns the new shape state based on the newest
        ///   state info
        /// 
        /// shape info for this character 
        private void UpdateShapeInfo ( ref ShapingWorkspace currentRun, byte shapeTableEntry )
        { 
 
            // update the previous shape information.  Check if the upper nibble of shapeTableEntry
            // holds information for updating the previous shape; if not, then we only will be 
            // setting this char's shape.
            if ((shapeTableEntry >> 4) != NoChange)
            {
                _previousShape = (MongolianShapeClass) (shapeTableEntry >> 4); 

                // update the previous shape's feature tag.  If this updated feature tag matches 
                // the latestCountedFeature, then its not a new feature. 
                // For example, in the following sequence...
                // 
                //  Event                                           Feature Tags:
                //  1st char processed, set to Isolated form       Iso     N.A     N.A.   N.A.
                //  2nd char, changes 1st form, sets own form      Ini     Final   N.A.   N.A.
                //  3rd char, changes 2nd form, set own            Ini     Mid     Final  N.A. 
                //  4th char, changes 3rd form, sets own           Ini     Mid     Mid    Final
                // 
                // ... we expect the "start of feature" flag to be set on the 1st, 2nd, and 4th 
                // shapes (once we've processed all four chars)
                _featuresList.UpdatePreviousShapedChar(_mongolianTextFeatures[(int)_previousShape]); 

            }

 
            _featuresList.AddFeature(   currentRun.CurrentCharIx,
                    shapeTableEntry ==  NoChange ?  (uint)MongolianShapeClass.SameShape : 
                                                                          _mongolianTextFeatures[(int)_currentShape] ); 
            return;
        } 


        // these const's are for making the  mongolianShapeStateTable more
        // readable. 
        private const byte NoChange = (byte)MongolianShapeClass.SameShape;
        private const byte NotShaped =   (byte)MongolianShapeClass.NotShaped; 
        private const byte Isolated =    (byte) MongolianShapeClass.IsolatedShape; 
        private const byte Final =       (byte) MongolianShapeClass.FinalShape;
 
        private const byte NoChangeToPriorShape = NoChange << 4;
        private const byte ToNotShaped =        NoChangeToPriorShape | NotShaped;
        private const byte ToIsolated =         NoChangeToPriorShape | Isolated;
        private const byte ToFinal =            NoChangeToPriorShape | Final; 

        private const byte FromIsolatedShape = (byte) MongolianShapeClass.IsolatedShape << 4; 
        private const byte IsolatedToNotShaped = FromIsolatedShape | NotShaped; 
        private const byte IsolatedToIsolated = FromIsolatedShape | Isolated;
 
        private const byte FromInitialShape = (byte) MongolianShapeClass.InitialShape << 4;
        private const byte InitialToNotShaped = FromInitialShape | NotShaped;
        private const byte InitialToFinal =     FromInitialShape | Final;
 
        private const byte FromMedialShape = (byte) MongolianShapeClass.MedialShape << 4;
        private const byte MedialToNotShaped =  FromMedialShape | NotShaped; 
        private const byte MedialToFinal =      FromMedialShape | Final; 

        private const byte FromFinalShape = (byte) MongolianShapeClass.FinalShape << 4; 
        private const byte FinalToNotShaped =   FromFinalShape | NotShaped;

        private const byte InvalidBase = (byte)MongolianShapeClass.InvalidBaseShape << 4;
        private const byte ToInvalidBase =      InvalidBase | NotShaped; 

        private const int NumberOfCharClasses = (int) MongolianCharClass.NumberOfMongolianCharClasses; 
 
        // This is the Mongolian shape state table.
        private static readonly byte[] _mongolianShapeStateTable = 
        {
        //  Current state is NotShaped...
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)     3 (Nirugu)    4 (VS)        5 (ZWNJ)      6 (ZWJ)        7 (Combine)   8 (Variant)   9 (Joining)      Next/ Current
            NoChange,      ToNotShaped,   ToNotShaped,  NoChange,     ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToIsolated,   // 0-INVALID BASE 
            ToInvalidBase, NoChange,      ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToIsolated,   // 1-NONJOINING
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToFinal,      // 2-NNBSP 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  NoChange,     ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToFinal,      // 3-NIRUGU 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToInvalidBase,ToNotShaped,  ToNotShaped,  ToNotShaped,   ToInvalidBase,ToInvalidBase,ToFinal,      // 4-VOWEL SEPARATOR
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToInvalidBase,ToInvalidBase, NoChange,     NoChange,     ToIsolated,   // 5-ZWNJ 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToInvalidBase,ToInvalidBase, NoChange,     NoChange,     ToFinal,      // 6-ZWJ

        //  Current state is Isolated Shape...
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)      3 (Nirugu)         4 (VS)      5 (ZWNJ)    6 (ZWJ)            7 (Combine) 8 (Variant) 9 (Joining)         Next/ Current 
            ToNotShaped,   ToNotShaped,   ToNotShaped,   InitialToNotShaped,ToNotShaped,ToNotShaped,InitialToNotShaped,NoChange,   NoChange,   InitialToFinal, // JOINING
 
        //  Current state is Final Shape... 
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)      3 (Nirugu)     4 (VS)          5 (ZWNJ)     6 (ZWJ)           7 (Combine) 8 (Variant) 9 (Joining)         Next/ Current
            ToNotShaped,   ToNotShaped,   MedialToNotShaped,MedialToFinal, ToNotShaped, ToNotShaped, MedialToNotShaped,NoChange,   NoChange,   MedialToFinal,// JOINING 
            ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,  ToInvalidBase,ToInvalidBase,   ToInvalidBase,ToInvalidBase,ToInvalidBase,// NONJOINING (impossible to get here)
            ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,  ToInvalidBase,ToInvalidBase,   ToInvalidBase,ToInvalidBase,ToInvalidBase,// NNBSP (impossible to get here)
            ToNotShaped,   ToNotShaped,   ToNotShaped,   ToNotShaped,   ToNotShaped,    ToNotShaped, MedialToNotShaped,ToNotShaped,ToNotShaped,MedialToFinal,// NIRUGU
 
        };
 
 
        // This array has the starting offset for the 'current char class'.  This
        // offset is relative to the first entry in the current shape state in whatever 
        // state lookup table is active. This table is used instead of multiplying the current
        // row value by 9 every time we access the shape state table.  This is
        // used when the current state is NotShaped.
        private static readonly ushort[] _rowFirstEntryIx = 
        {
            0,              // DottedCircle 
            1 * (int)NumberOfCharClasses,             // NonJoiningBase 
            2 * (int)NumberOfCharClasses,             // NNBSP
            3 * (int)NumberOfCharClasses,             // Nirugu 
            4 * (int)NumberOfCharClasses,             // VowelSeparator
            5 * (int)NumberOfCharClasses,             // ZWNJ
            6 * (int)NumberOfCharClasses,             // ZWJ
            0 * (int)NumberOfCharClasses,             // Combine 
            0 * (int)NumberOfCharClasses,             // Variant
            0 * (int)NumberOfCharClasses,             // Joining 
        }; 

        // this array has the starting offset for the current shape state.  This 
        // offset is relative to the first entry in _baseCharShapeStateTable[].  The
        // numbers are 'tally of all previous shape rows X 9 entries per row'.
        private static readonly ushort[] _baseTableFirstEntryIx =
        { 
            0,                                        // SameShape
            0,                                        // NotShaped 
            7 * (int)NumberOfCharClasses,             // IsolatedShape 
            8 * (int)NumberOfCharClasses,             // FinalShape
        }; 

        private static readonly uint[] _mongolianTextFeatures  =
        {
            0,                 // Same         (this is required by ShaperFeaturesList) 
            1,                 // NotShaped    (this is required by ShaperFeaturesList)
            (uint)FeatureTags.IsolatedForms,      // IsolatedShape 
            (uint)FeatureTags.TerminalForms,      // FinalShape 
            (uint)FeatureTags.InitialForms,       // InitialShape
            (uint)FeatureTags.MedialForms,        // MedialShape 
            1,                 // InvalidBaseShape    (this is required by ShaperFeaturesList)
        };

 
    }
 
    ///  
    /// MongolianCharClassifier -
    ///  
    internal class MongolianCharClassifier : ShaperCharacterClassifier
    {
        private ushort _mvsGlyph;
        private ushort _vs1Glyph; 
        private ushort _vs2Glyph;
        private ushort _vs3Glyph; 
 
        public MongolianCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) : base(scriptTag, fontFace)
        { 
          _unknownClass =    InvalidChar;
          _spaceClass =      NonJoiningBase;
          _zwControlClass =  NonJoiningBase;
          _zwjClass =        JoiningBase; 
          _zwnjClass =       NonJoiningBase;
          _shyClass =        InvalidChar; 
 
          _firstChar     = '\u1800';     // this is the first Hebrew Unicode char
          _lastChar      = '\u18AF';     // this is the last Hebrew Unicode char 
          _xorMask       = 0x1800;     // this mask is used in GetCharShapeInfo
          _xorRange      = 0x0b0;     // this is used in GetCharShapeInfo

          _charClassTable = _mongolianCharClasses; 

        } 
 
        /// 
        /// MongolianCharClassifier.ToShapeInfo - returns CharShapeInfo for the Unicode character 
        /// 
        public override CharShapeInfo ToShapeInfo (char unicodeChar )
        {
 
            CharShapeInfo charShape;
            if (unicodeChar == UnicodeCharacter.NarrowNoBreakSpace) 
            { 
                charShape = (CharShapeInfo)((byte)StartOfCluster | (byte)MongolianCharClass.NNBSP);
            } 
            else
            {
                charShape = base.ToShapeInfo(unicodeChar);
 
                if (unicodeChar >= '\u180b' && unicodeChar <= '\u180e')
                { 
                        charShape |= CharShapeInfo.IsUnicodeLayoutControl; 
                }
            } 

            return charShape;
        }
 
        /// 
        /// SetUnicodeControlGlyph - called to save local copy of pertinent glyph ids 
        ///  
        /// 
        ///            This function is called by ShapingWorkspace when a Unicode control 
        ///            character is detected in the text run.  This allows us to cache
        ///            the glyph id for use in IsUnicodeControlGlyph (which may be used
        ///            to suppress the display of Unicode control characters).  This
        ///            overrided function allows us to save the glyph id's of the 
        ///            Mongolian control characters
        ///  
        public override void SetUnicodeControlGlyph (char unicodeChar, ushort glyph) 
        {
            if (glyph != 0) 
            {
              switch (unicodeChar)
              {
                case '\u180b':              // Variant1 
                    _vs1Glyph = glyph;
                    break; 
                case '\u180c':              // Variant2 
                    _vs2Glyph = glyph;
                    break; 
                case '\u180d':              // Variant3
                    _vs3Glyph = glyph;
                    break;
                case '\u180e':              // VowelSeparator 
                    _mvsGlyph = glyph;
                    break; 
                default: 
                    base.SetUnicodeControlGlyph(unicodeChar, glyph);
                    break; 
              }
            }

        } 

        public override bool IsUnicodeControlGlyph( ushort glyph ) 
        { 
            if (glyph != 0)
            { 
                if (glyph == _mvsGlyph ||
                    glyph == _vs1Glyph ||
                    glyph == _vs2Glyph ||
                    glyph == _vs3Glyph) 
                {
                    return true; 
                } 
            }
 
            return base.IsUnicodeControlGlyph (glyph);
        }

#region Classification Tables 

        // these consts are so the tables below will be more readable 
        private const MongolianCharClass StartOfCluster = (MongolianCharClass)CharShapeInfo.IsStartOfCluster; 
        private const byte InvalidChar = (byte)(MongolianCharClass.InvalidChar | StartOfCluster);
        private const byte NonJoiningBase = (byte)(MongolianCharClass.NonJoiningBase | StartOfCluster); 
        private const byte JoiningBase = (byte)(MongolianCharClass.JoiningBase | StartOfCluster);
        private const byte Combine = (byte)MongolianCharClass.Combine;
        private const byte Variant = (byte)MongolianCharClass.Variant;
        private const byte VowelSeparator = (byte)(MongolianCharClass.VowelSeparator | StartOfCluster); 
        private const byte Nirugu = (byte)(MongolianCharClass.Nirugu | StartOfCluster);
 
 
        static byte[] _mongolianCharClasses =
        { 
            // Mongolian
            //180   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase,
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     Nirugu, 
            NonJoiningBase,     NonJoiningBase,     Nirugu,             Variant,
            Variant,            Variant,            VowelSeparator,     InvalidChar, 
 
            //181   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase, 
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase,
            NonJoiningBase,     NonJoiningBase,     InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
            //182   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //183   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //184   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
 
            //185   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //186   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //187   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
            //188   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase, 
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //189   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //18A   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        Combine,            InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
        };
 
#endregion  // end of Classification Tables 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------- 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2004
// 
//  File:      MongolianShape.cs
// 
//  Contents:  Implementation of Mongolian shaping engine and its factory 
//
//  Created:   04-15-2004 Nick Beal (nbeal) 
//
//-----------------------------------------------------------------------
using System;
using System.Security; 
using System.Security.Permissions;
using System.Diagnostics; 
using System.Collections; 
using System.Globalization;
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using MS.Internal.FontCache;
using MS.Internal.FontFace; 
using MS.Internal.PresentationCore;
 
 
namespace MS.Internal.Shaping
{ 
    /// 
    /// MongolianCharClass - enumeration of Mongolian character classifications
    /// 
    ///  
    ///  These values are used as weights, so the order matters.  Every value
    ///  from JoiningBase up are valid for members of a cluster (ie, chars collected 
    ///  by MongolianClusterCop.AddToCluster()). 
    /// 
    internal enum MongolianCharClass : byte 
    {
        InvalidChar,          // invalid char class --
        NonJoiningBase,       // character does not join
        NNBSP, 
        Nirugu,               // U+180a (also U+1807)
        VowelSeparator, 
        ZWNJ, 
        ZWJ,
        Combine,              // only Mongolian diacritic 
        Variant,              // Variant selector
        JoiningBase,          // character joins on both sides
        NumberOfMongolianCharClasses,
    }; 

    ///  
    /// MongolianShapeClass - enumeration of Mongolian shape classifications 
    /// 
    ///  
    ///  These values are the shaping FSM shape definitions.  As the text run
    ///  is processed the shaping FSM assigns each character a shape.
    ///  The MongolianShapeInfo.mongolianTextFeatures array maps the first several of this enum's
    ///  values to the appropriate OT font feature to apply to the character. 
    /// 
    internal enum MongolianShapeClass : byte 
    { 
        SameShape,
        UninitializedState = SameShape,              // used for detecting initialization of state machine 
        NotShaped,
        IsolatedShape,
        FinalShape,
        LastShapeWithStateTable = FinalShape,        // used for Debug.Assert check 
        InitialShape,
        MedialShape, 
        InvalidBaseShape, 
    };
 

    /// 
    /// The MongolianShape, class defines the Mongolian Shaping Engine.
    ///  
    internal class MongolianShape : BaseShape
    { 
        ///  
        /// All required shaping Features (GSUB)
        ///  
        private static readonly Feature[]   _requiredFeatures    =
        {
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.GlyphCompositionDecomposition,1),
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.RequiredLigatures,1), 
            new Feature(0,ushort.MaxValue,(uint)FeatureTags.ContextualAlternates,1),
        }; 
 
        private static readonly ScriptTags[] _supportedScripts = new ScriptTags[]{ScriptTags.Mongolian};
 
        /// 
        /// Constructor for the Mongolian Open Type Shaping Engine.
        /// 
        internal MongolianShape() 
        {
        } 
 
        public override ScriptTags[] SupportedScripts
        { 
            get
            {
                return _supportedScripts;
            } 
        }
 
        ///  
        /// MongolianShape.GetCharClassifier - Base shape
        ///  
        /// 
        ///     This will normally be overridden by derived shapers. It is used in OnLoadFont
        /// 
        protected override ShaperCharacterClassifier GetCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) 
        {
            return new MongolianCharClassifier (scriptTag, fontFace); 
        } 

        ///  
        ///     MongolianShape.GetGlyphs - Mongolian implementation of the GetGlyphs() helper function.
        /// 
        /// shaping currentRun
        /// Text item 
        /// number of glyphs
        ///  
        /// Critical - calls critical code 
        /// 
        [SecurityCritical] 
        protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item )
        {
            bool combinerCharSeen = false;;
            int charsCount = 0; 

            // initialize the features array 
            ShaperBuffers.InitializeFeatureList(0,(ushort)_requiredFeatures.Length); 
            if (ShaperBuffers.TextFeatures.FeaturesCount == 0)
            { 
                // The first time GetGlyphs is called, add the required features
                // (they'll always be first in the array from now on).
                for (int i = 0; i < _requiredFeatures.Length; ++i)
                { 
                    ShaperBuffers.TextFeatures.AddFeature( _requiredFeatures[i] );
                } 
            } 

            // initialize the cluster cop/state machine 
            MongolianShapeFSM  stateMachine = new MongolianShapeFSM( ShaperBuffers.TextFeatures );


            // Shape and initialize the glyph list 
            // process the char stream, creating shape info, applying features
            // as necessary 
            CharShapeInfo currShape; 
            while ( currentRun.GetNextShape (out currShape) )
            { 
                MongolianCharClass currClass = (MongolianCharClass)(currShape & CharShapeInfo.ShaperClassMask);

                if (currClass == MongolianCharClass.VowelSeparator)
                { 
                    // if the next character is not one of the expected vowels, then
                    // treat this instead as a NNBSP. 
                    char nextChar = currentRun.NextChar; 
                    if (nextChar != '\u1820' && nextChar != '\u1821')
                    { 
                        currClass = MongolianCharClass.NNBSP;
                    }
                }
 
                stateMachine.StepToNextState(ref currentRun, currClass);
 
                if (currClass == MongolianCharClass.Combine) 
                {
                        // we can only have one combining mark per cluster, and it can't be the first character. 
                        if (combinerCharSeen || charsCount == 0)  // if either of these restrictions aren't true, dotted circle time
                        {
                            //  Set the flag so that we know to insert a dotted circle...
                            currShape = CharShapeInfo.RequiresInsertedBase; 
                            stateMachine.ForceInvalidBaseState();
                        } 
 
                        combinerCharSeen = true;
                } 
                else
                {
                    combinerCharSeen = false;
                } 

 
                currentRun.SetGlyphPropertiesUsingShapeInfo(currShape); 
                ++charsCount;
            } 

            return (currentRun.GlyphsCount);    // we're done

 
        }
 
 
        /// 
        ///    MongolianShape.ApplySubstitutionFeatures - default implementation of the GetGlyphs() helper function. 
        /// 
        /// shaping currentRun
        /// Set of gsub features to be applied to the unicode run.
        /// result of applying features 
        /// 
        /// Critical - this method calls unsafe methods. 
        ///  
        [SecurityCritical]
        protected override OpenTypeLayoutResult ApplySubstitutionFeatures( 
                                                        ref ShapingWorkspace currentRun,
                                                        FeatureSet       featureSet  )
        {
                //  Apply the Mongolian Text Features from currentRun 
            ShaperFontClient fontClient = currentRun.FontClient;
            return fontClient.SubstituteGlyphs( 
                                ref currentRun, 
                                ShaperBuffers.TextFeatures.Features,
                                ShaperBuffers.TextFeatures.FeaturesCount ); 

        }

    } 

    ///  
    /// MongolianShapeFSM - Mongolian shaping state machine 
    /// 
    ///  
    /// 
    internal struct MongolianShapeFSM
    {
        private MongolianShapeClass _currentShape; 
        private MongolianShapeClass _previousShape;
        private ushort              _currentStateRowIx; 
        private ShaperFeaturesList  _featuresList; 

        ///  
        /// MongolianShapeFSM constructor
        /// 
        public MongolianShapeFSM ( ShaperFeaturesList featuresList )
        { 
            _previousShape       = MongolianShapeClass.UninitializedState;
            _currentShape        = MongolianShapeClass.NotShaped; 
 
            _featuresList = featuresList;
 
            // currentStartRowIx == the first entry in the active state table for the
            // current base char shape.
            _currentStateRowIx = 0;
 
        }
 
 
        /// 
        ///   MongolianShapeFSM.ForceInvalidBaseState - force state machine to state 
        /// 
        /// 
        ///   This is used to force the state machine to invalid base state
        ///   (useful when a 'dotted circle' base character is inserted) 
        /// 
        ///  
        /// Critical - calls critical code (UpdatePendingShape) 
        /// 
        [SecurityCritical] 
        internal void ForceInvalidBaseState ()
        {
            _previousShape = _currentShape =  MongolianShapeClass.NotShaped;                     // save new shape
            _currentStateRowIx = _rowFirstEntryIx[ (int)MongolianCharClass.InvalidChar ]; 
        }
 
 
        /// 
        /// MongolianShapeFSM.StartSyllable - start of new syllable (potentially) 
        /// 
        /// 
        /// This routine is used at the start of each cluster.  If the base + this
        /// first non-base char are the valid start of a new cluster, return 
        /// 
        /// the starting state 
        /// new settings for current shape info 
        /// 
        /// Critical - possibly calls critical code (ForceInvalidBaseState) 
        /// 
        [SecurityCritical]
        private void SetStartState ( ref ShapingWorkspace currentRun,
                                                MongolianCharClass  firstCharClass ) 
        {
            Debug.Assert (_currentShape == MongolianShapeClass.NotShaped && 
                          _currentStateRowIx == 0 , "Mongolian FSM SetStartState should not be called now."); 

            _previousShape = _currentShape; 

            switch (firstCharClass)
            {
                case MongolianCharClass.Combine: 
                case MongolianCharClass.Variant:
                case MongolianCharClass.VowelSeparator: 
                    ForceInvalidBaseState (); 
                    break;
 
                case MongolianCharClass.JoiningBase:
                    //   Joining base chars mean that the starting shape state is not NotShaped...
                    _currentShape =
                            (currentRun.CurrentCharIx == 0 && currentRun.HasLeadingJoin) ? 
                        MongolianShapeClass.FinalShape : MongolianShapeClass.IsolatedShape;
 
                    _currentStateRowIx = _baseTableFirstEntryIx[ (int)_currentShape ]; 
                    _featuresList.AddFeature(currentRun.CurrentCharIx,
                                             _mongolianTextFeatures[(int)_currentShape]); 
                    break;

                default:
 
                    _currentStateRowIx = _rowFirstEntryIx[ (int)firstCharClass ];
                    break; 
            } 

 
        }

        /// 
        ///   MongolianShapeFSM.StepToNextState - process the latest character. 
        /// 
        ///  
        ///   This routine steps the state machine to its next state 
        ///   based on the current state, the last character that caused a
        ///   state change and the next char. It may affect the previous character's 
        ///   shape if the feature id which is embedded in the shape info needs to be
        ///   changed.
        /// 
        /// new settings for current shape info 
        /// 
        /// Critical - calls critical code, uses unsafe accessors 
        ///  
        [SecurityCritical]
        internal void StepToNextState (  ref ShapingWorkspace currentRun, MongolianCharClass  nextCharClass ) 
        {
            Debug.Assert ( (int)nextCharClass < NumberOfCharClasses );

            if ( _currentShape != MongolianShapeClass.SameShape ) 
            {
                if (_previousShape == MongolianShapeClass.UninitializedState) 
                { 
                    SetStartState(ref currentRun, nextCharClass);
                    return; 
                }
            }

 
            // The state tables are abbreviated (only enough rows per state to cover
            // the events that are valid for the current state.  So, first check if 
            // we should be looking up the next state in the state table. 
            // get the shape state table entry.
            byte shapeTableEntry = _mongolianShapeStateTable[ _currentStateRowIx + (int)nextCharClass ]; 

            switch (shapeTableEntry)
            {
                case NoChange: 
                    // this means this latest character doesn't affect the current state AT ALL.
                    break; 
 
                case ToInvalidBase:
                    ForceInvalidBaseState(); 
                    break;

                default:
 
                    // keep track of where we're coming from.
                    _previousShape = _currentShape; 
                    // change our state (or shape) 
                    _currentShape = (MongolianShapeClass) (shapeTableEntry & 0xf);
                    Debug.Assert(_currentShape <= MongolianShapeClass.LastShapeWithStateTable); 

                    // adjust the state table indices..
                    _currentStateRowIx = (ushort)( _baseTableFirstEntryIx[ (int)_currentShape ]
                                                    + _rowFirstEntryIx[ (int)nextCharClass ]); 

                    break; 
            } 

            UpdateShapeInfo(ref currentRun, shapeTableEntry); 


        }
 

        ///  
        ///   MongolianShapeFSM.UpdateShapeInfo - process the latest character. 
        /// 
        ///  
        ///   This routine returns the new shape state based on the newest
        ///   state info
        /// 
        /// shape info for this character 
        private void UpdateShapeInfo ( ref ShapingWorkspace currentRun, byte shapeTableEntry )
        { 
 
            // update the previous shape information.  Check if the upper nibble of shapeTableEntry
            // holds information for updating the previous shape; if not, then we only will be 
            // setting this char's shape.
            if ((shapeTableEntry >> 4) != NoChange)
            {
                _previousShape = (MongolianShapeClass) (shapeTableEntry >> 4); 

                // update the previous shape's feature tag.  If this updated feature tag matches 
                // the latestCountedFeature, then its not a new feature. 
                // For example, in the following sequence...
                // 
                //  Event                                           Feature Tags:
                //  1st char processed, set to Isolated form       Iso     N.A     N.A.   N.A.
                //  2nd char, changes 1st form, sets own form      Ini     Final   N.A.   N.A.
                //  3rd char, changes 2nd form, set own            Ini     Mid     Final  N.A. 
                //  4th char, changes 3rd form, sets own           Ini     Mid     Mid    Final
                // 
                // ... we expect the "start of feature" flag to be set on the 1st, 2nd, and 4th 
                // shapes (once we've processed all four chars)
                _featuresList.UpdatePreviousShapedChar(_mongolianTextFeatures[(int)_previousShape]); 

            }

 
            _featuresList.AddFeature(   currentRun.CurrentCharIx,
                    shapeTableEntry ==  NoChange ?  (uint)MongolianShapeClass.SameShape : 
                                                                          _mongolianTextFeatures[(int)_currentShape] ); 
            return;
        } 


        // these const's are for making the  mongolianShapeStateTable more
        // readable. 
        private const byte NoChange = (byte)MongolianShapeClass.SameShape;
        private const byte NotShaped =   (byte)MongolianShapeClass.NotShaped; 
        private const byte Isolated =    (byte) MongolianShapeClass.IsolatedShape; 
        private const byte Final =       (byte) MongolianShapeClass.FinalShape;
 
        private const byte NoChangeToPriorShape = NoChange << 4;
        private const byte ToNotShaped =        NoChangeToPriorShape | NotShaped;
        private const byte ToIsolated =         NoChangeToPriorShape | Isolated;
        private const byte ToFinal =            NoChangeToPriorShape | Final; 

        private const byte FromIsolatedShape = (byte) MongolianShapeClass.IsolatedShape << 4; 
        private const byte IsolatedToNotShaped = FromIsolatedShape | NotShaped; 
        private const byte IsolatedToIsolated = FromIsolatedShape | Isolated;
 
        private const byte FromInitialShape = (byte) MongolianShapeClass.InitialShape << 4;
        private const byte InitialToNotShaped = FromInitialShape | NotShaped;
        private const byte InitialToFinal =     FromInitialShape | Final;
 
        private const byte FromMedialShape = (byte) MongolianShapeClass.MedialShape << 4;
        private const byte MedialToNotShaped =  FromMedialShape | NotShaped; 
        private const byte MedialToFinal =      FromMedialShape | Final; 

        private const byte FromFinalShape = (byte) MongolianShapeClass.FinalShape << 4; 
        private const byte FinalToNotShaped =   FromFinalShape | NotShaped;

        private const byte InvalidBase = (byte)MongolianShapeClass.InvalidBaseShape << 4;
        private const byte ToInvalidBase =      InvalidBase | NotShaped; 

        private const int NumberOfCharClasses = (int) MongolianCharClass.NumberOfMongolianCharClasses; 
 
        // This is the Mongolian shape state table.
        private static readonly byte[] _mongolianShapeStateTable = 
        {
        //  Current state is NotShaped...
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)     3 (Nirugu)    4 (VS)        5 (ZWNJ)      6 (ZWJ)        7 (Combine)   8 (Variant)   9 (Joining)      Next/ Current
            NoChange,      ToNotShaped,   ToNotShaped,  NoChange,     ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToIsolated,   // 0-INVALID BASE 
            ToInvalidBase, NoChange,      ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToIsolated,   // 1-NONJOINING
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToFinal,      // 2-NNBSP 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  NoChange,     ToNotShaped,  ToNotShaped,  ToNotShaped,   NoChange,     NoChange,     ToFinal,      // 3-NIRUGU 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToInvalidBase,ToNotShaped,  ToNotShaped,  ToNotShaped,   ToInvalidBase,ToInvalidBase,ToFinal,      // 4-VOWEL SEPARATOR
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToInvalidBase,ToInvalidBase, NoChange,     NoChange,     ToIsolated,   // 5-ZWNJ 
            ToInvalidBase, ToNotShaped,   ToNotShaped,  ToNotShaped,  ToNotShaped,  ToInvalidBase,ToInvalidBase, NoChange,     NoChange,     ToFinal,      // 6-ZWJ

        //  Current state is Isolated Shape...
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)      3 (Nirugu)         4 (VS)      5 (ZWNJ)    6 (ZWJ)            7 (Combine) 8 (Variant) 9 (Joining)         Next/ Current 
            ToNotShaped,   ToNotShaped,   ToNotShaped,   InitialToNotShaped,ToNotShaped,ToNotShaped,InitialToNotShaped,NoChange,   NoChange,   InitialToFinal, // JOINING
 
        //  Current state is Final Shape... 
        //  0 (Invalid)    1 (NonJoining) 2 (NNBSP)      3 (Nirugu)     4 (VS)          5 (ZWNJ)     6 (ZWJ)           7 (Combine) 8 (Variant) 9 (Joining)         Next/ Current
            ToNotShaped,   ToNotShaped,   MedialToNotShaped,MedialToFinal, ToNotShaped, ToNotShaped, MedialToNotShaped,NoChange,   NoChange,   MedialToFinal,// JOINING 
            ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,  ToInvalidBase,ToInvalidBase,   ToInvalidBase,ToInvalidBase,ToInvalidBase,// NONJOINING (impossible to get here)
            ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,  ToInvalidBase,ToInvalidBase,   ToInvalidBase,ToInvalidBase,ToInvalidBase,// NNBSP (impossible to get here)
            ToNotShaped,   ToNotShaped,   ToNotShaped,   ToNotShaped,   ToNotShaped,    ToNotShaped, MedialToNotShaped,ToNotShaped,ToNotShaped,MedialToFinal,// NIRUGU
 
        };
 
 
        // This array has the starting offset for the 'current char class'.  This
        // offset is relative to the first entry in the current shape state in whatever 
        // state lookup table is active. This table is used instead of multiplying the current
        // row value by 9 every time we access the shape state table.  This is
        // used when the current state is NotShaped.
        private static readonly ushort[] _rowFirstEntryIx = 
        {
            0,              // DottedCircle 
            1 * (int)NumberOfCharClasses,             // NonJoiningBase 
            2 * (int)NumberOfCharClasses,             // NNBSP
            3 * (int)NumberOfCharClasses,             // Nirugu 
            4 * (int)NumberOfCharClasses,             // VowelSeparator
            5 * (int)NumberOfCharClasses,             // ZWNJ
            6 * (int)NumberOfCharClasses,             // ZWJ
            0 * (int)NumberOfCharClasses,             // Combine 
            0 * (int)NumberOfCharClasses,             // Variant
            0 * (int)NumberOfCharClasses,             // Joining 
        }; 

        // this array has the starting offset for the current shape state.  This 
        // offset is relative to the first entry in _baseCharShapeStateTable[].  The
        // numbers are 'tally of all previous shape rows X 9 entries per row'.
        private static readonly ushort[] _baseTableFirstEntryIx =
        { 
            0,                                        // SameShape
            0,                                        // NotShaped 
            7 * (int)NumberOfCharClasses,             // IsolatedShape 
            8 * (int)NumberOfCharClasses,             // FinalShape
        }; 

        private static readonly uint[] _mongolianTextFeatures  =
        {
            0,                 // Same         (this is required by ShaperFeaturesList) 
            1,                 // NotShaped    (this is required by ShaperFeaturesList)
            (uint)FeatureTags.IsolatedForms,      // IsolatedShape 
            (uint)FeatureTags.TerminalForms,      // FinalShape 
            (uint)FeatureTags.InitialForms,       // InitialShape
            (uint)FeatureTags.MedialForms,        // MedialShape 
            1,                 // InvalidBaseShape    (this is required by ShaperFeaturesList)
        };

 
    }
 
    ///  
    /// MongolianCharClassifier -
    ///  
    internal class MongolianCharClassifier : ShaperCharacterClassifier
    {
        private ushort _mvsGlyph;
        private ushort _vs1Glyph; 
        private ushort _vs2Glyph;
        private ushort _vs3Glyph; 
 
        public MongolianCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) : base(scriptTag, fontFace)
        { 
          _unknownClass =    InvalidChar;
          _spaceClass =      NonJoiningBase;
          _zwControlClass =  NonJoiningBase;
          _zwjClass =        JoiningBase; 
          _zwnjClass =       NonJoiningBase;
          _shyClass =        InvalidChar; 
 
          _firstChar     = '\u1800';     // this is the first Hebrew Unicode char
          _lastChar      = '\u18AF';     // this is the last Hebrew Unicode char 
          _xorMask       = 0x1800;     // this mask is used in GetCharShapeInfo
          _xorRange      = 0x0b0;     // this is used in GetCharShapeInfo

          _charClassTable = _mongolianCharClasses; 

        } 
 
        /// 
        /// MongolianCharClassifier.ToShapeInfo - returns CharShapeInfo for the Unicode character 
        /// 
        public override CharShapeInfo ToShapeInfo (char unicodeChar )
        {
 
            CharShapeInfo charShape;
            if (unicodeChar == UnicodeCharacter.NarrowNoBreakSpace) 
            { 
                charShape = (CharShapeInfo)((byte)StartOfCluster | (byte)MongolianCharClass.NNBSP);
            } 
            else
            {
                charShape = base.ToShapeInfo(unicodeChar);
 
                if (unicodeChar >= '\u180b' && unicodeChar <= '\u180e')
                { 
                        charShape |= CharShapeInfo.IsUnicodeLayoutControl; 
                }
            } 

            return charShape;
        }
 
        /// 
        /// SetUnicodeControlGlyph - called to save local copy of pertinent glyph ids 
        ///  
        /// 
        ///            This function is called by ShapingWorkspace when a Unicode control 
        ///            character is detected in the text run.  This allows us to cache
        ///            the glyph id for use in IsUnicodeControlGlyph (which may be used
        ///            to suppress the display of Unicode control characters).  This
        ///            overrided function allows us to save the glyph id's of the 
        ///            Mongolian control characters
        ///  
        public override void SetUnicodeControlGlyph (char unicodeChar, ushort glyph) 
        {
            if (glyph != 0) 
            {
              switch (unicodeChar)
              {
                case '\u180b':              // Variant1 
                    _vs1Glyph = glyph;
                    break; 
                case '\u180c':              // Variant2 
                    _vs2Glyph = glyph;
                    break; 
                case '\u180d':              // Variant3
                    _vs3Glyph = glyph;
                    break;
                case '\u180e':              // VowelSeparator 
                    _mvsGlyph = glyph;
                    break; 
                default: 
                    base.SetUnicodeControlGlyph(unicodeChar, glyph);
                    break; 
              }
            }

        } 

        public override bool IsUnicodeControlGlyph( ushort glyph ) 
        { 
            if (glyph != 0)
            { 
                if (glyph == _mvsGlyph ||
                    glyph == _vs1Glyph ||
                    glyph == _vs2Glyph ||
                    glyph == _vs3Glyph) 
                {
                    return true; 
                } 
            }
 
            return base.IsUnicodeControlGlyph (glyph);
        }

#region Classification Tables 

        // these consts are so the tables below will be more readable 
        private const MongolianCharClass StartOfCluster = (MongolianCharClass)CharShapeInfo.IsStartOfCluster; 
        private const byte InvalidChar = (byte)(MongolianCharClass.InvalidChar | StartOfCluster);
        private const byte NonJoiningBase = (byte)(MongolianCharClass.NonJoiningBase | StartOfCluster); 
        private const byte JoiningBase = (byte)(MongolianCharClass.JoiningBase | StartOfCluster);
        private const byte Combine = (byte)MongolianCharClass.Combine;
        private const byte Variant = (byte)MongolianCharClass.Variant;
        private const byte VowelSeparator = (byte)(MongolianCharClass.VowelSeparator | StartOfCluster); 
        private const byte Nirugu = (byte)(MongolianCharClass.Nirugu | StartOfCluster);
 
 
        static byte[] _mongolianCharClasses =
        { 
            // Mongolian
            //180   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase,
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     Nirugu, 
            NonJoiningBase,     NonJoiningBase,     Nirugu,             Variant,
            Variant,            Variant,            VowelSeparator,     InvalidChar, 
 
            //181   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase, 
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase,
            NonJoiningBase,     NonJoiningBase,     InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
            //182   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //183   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //184   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
 
            //185   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //186   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //187   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
            //188   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     NonJoiningBase, 
            NonJoiningBase,     NonJoiningBase,     NonJoiningBase,     JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 

            //189   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
 
            //18A   0, 4, 8, C          1, 5, 9, D          2, 6, A, E          3, 7, B, F
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase, 
            JoiningBase,        JoiningBase,        JoiningBase,        JoiningBase,
            JoiningBase,        Combine,            InvalidChar,        InvalidChar,
            InvalidChar,        InvalidChar,        InvalidChar,        InvalidChar,
 
        };
 
#endregion  // end of Classification Tables 
    }
} 

// 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