ShapingWorkspace.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / MS / Internal / Shaping / ShapingWorkspace.cs / 1 / ShapingWorkspace.cs

                            //---------------------------------------------------------------------- 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2005
// 
//  File:      ShapingWorkspace.cs
// 
//  Contents:  support for all the shaping engines - all the local 
//             variables for GetGlyphs and helpers are wrapped and
//             all unsafe pointer manipulation 
//             is done in this class.
//
//  Created:   06-24-2005 by Nick Beal
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Security;
using System.Security.Permissions; 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; 
using MS.Internal.FontCache;
using MS.Internal.FontFace; 
using System.Windows.Media; 
using System.Windows.Media.TextFormatting;
using MS.Internal.PresentationCore; 
using MS.Utility;

namespace MS.Internal.Shaping
{ 

 
 
        /// 
        ///     ShapingWorkspace  provides safe interactions with the various buffers 
        ///     used by GetGlyphs.
        /// 
        /// 
        ///     This struct is created every time a shaping engine's GetGlyphs() method is called. 
        ///
        ///     All interaction on the unsafe buffers used for text characters and their related 
        ///     buffers (char map, cluster map, etc) done during IShaper.GetGlyphs methods 
        ///     are done through this struct's accessors and methods.
        ///  
        internal struct ShapingWorkspace
        {

            // These are shorthand aliaes for setting flags in GetGlyphs context. 
            internal const ushort GlyphFlagsNone = (ushort)(GlyphFlags.Unresolved);
            internal const ushort GlyphFlagsBase = (ushort)(GlyphFlags.ClusterStart | GlyphFlags.Unresolved); 
            internal const ushort GlyphFlagsZeroWidth = (ushort)(GlyphFlags.ZeroWidth | GlyphFlags.Unresolved); 
            internal const ushort GlyphFlagsDiacritic = (ushort)(GlyphFlags.Diacritic | GlyphFlags.Unresolved);
 
            /// 
            /// ShapingWorkspace - initializer for GetGlyphs helper currentRun
            /// 
            ///  
            ///     This function is always called from IShaper.GetGlyphs.
            ///  
            ///  
            ///     Critical: This code accepts checked pointers and extracts
            ///         unsafe pointers. 
            /// 
            [SecurityCritical]
            unsafe public ShapingWorkspace (
                Item                                        item, 
                ShapingOptions                              shapingFlags,
 
                ShaperFontClient                            shaperFontClient, 
                ShaperBuffers                               shaperBuffers,
 
                CheckedCharPointer                          chars,
                int                                         charCount,

                CheckedCharacterShapingPropertiesPointer    charProperties, 
                CheckedUShortPointer                        charClusterMap)
            { 
 
                Invariant.Assert(charCount > 0,"ShapingWorkspace: invalid char count");
                _charsCount = (ushort)charCount; 

                // save the shaping directives from our client
                _forceControlCharsInvisible = ((shapingFlags & ShapingOptions.DisplayControlCode) == 0);
                _forceInhibitLigature = ((shapingFlags & ShapingOptions.InhibitLigature) != 0); 

                // note if we have a leading ZWJ 
                _hasLeadingJoin = ((item.Flags & ItemFlags.LeadingJoin) != 0); 

                // initialize our shaper buffers and set up our local references 
                shaperBuffers.Initialize( (ushort)charCount, (ushort)charCount);
                _charMap = shaperBuffers.CharMap;
                _glyphInfoList = shaperBuffers.GlyphInfoList;
 
                // keep track of our font client, char converter
                _fontClient = shaperFontClient; 
                _charConverter = _fontClient.CharConverter; 

                // unpack the pointer containers and initialize our pointer 
                _pChars = chars.Probe(0, charCount);
                _pCharProps = charProperties.Probe(0, charCount);
                _pClusters = charClusterMap.Probe(0, charCount);
                _pShapes = (CharShapeInfo *)_pClusters; 

                // initialize our various counts 
                _addedGlyphsCount = 0; 
                _nextCharIx = _nextGlyphIx = 0;
                _lastCharIx = (ushort)(charCount - 1); 

                // initialize our local booleans
                _inited = true;
                _isAutoInsert = _controlCharsSeen = _finishedShaping = false; 
                _isSerializedClusterEntriesRequired = true;
 
            } 

            // various accessors, function... 
            // I have laid these out alphabetically.  If a particular variable has
            // an accessor with a different name than the variable, I've added a
            // comment in the position of the variable...
 

            ///  
            /// AddGlyphs - add more glyphs to glyphinfolist 
            /// 
            ///  
            ///     This function can be used to increase or decrease the logical
            ///     size of the glyph info lists.
            ///     If increasing the size the GlyphInfoList is not actually
            ///     resized, but the _addedGlyphsCount is incremented (the actual 
            ///     resize will occur later - this is to minimize the overhead of
            ///     resizing).  The resizing will actually occur when GlyphsCount 
            ///     accessor is invoked. 
            ///     If decreasing the logical size of the glyph info lists, a check
            ///     is made so that any pending added glyphs are taken into account 
            ///     in the logical resizing and the _nextGlyphIx is adjusted if it
            ///     is affected by the reduction of the list size.
            /// 
            ///  
            /// Critical - The method calls critical code (GlyphInfoList.SetLength)
            ///  
            [SecurityCritical] 
            public int AddGlyphs(int addCount)
            { 
                if (addCount < 0)
                {
                    int glyphsCount = GlyphInfoList.Length;
 
                    // we're decreasing the extent of our glyphs list
                    // NOTE: we saved glyphsCount above because 
                    // GlyphsCount may increase the glyphInfoList 
                    // size (if there're pending "add glyphs")
                    if ((GlyphsCount + addCount) > 0) 
                    {
                        GlyphInfoList.SetLength (GlyphsCount + addCount);
                    }
 
                    if (_nextGlyphIx >= glyphsCount + addCount)
                    { 
                        _nextGlyphIx = (ushort)((int)_nextGlyphIx + addCount); 
                    }
                } 
                else
                {
                    _addedGlyphsCount += addCount;
                } 
                return addCount;
            } 
 
            /// 
            ///     AddLigatureChars - Updates the current glyph info's ligature count. 
            /// 
            /// 
            ///         This function updates the current glyph info's ligature count and
            ///         maps the charmap, cluster (or shape) values for each of the following 
            ///         chars that are part of the ligature.
            ///  
            ///  
            /// Critical - The method reads/write unsafe pointers
            ///  
            [SecurityCritical]
            unsafe public void AddLigatureChars(int baseCharOffset, ushort ligaturesCount)
            {
                if (ligaturesCount > 1) 
                {
                   Debug.Assert(baseCharOffset == -1 || baseCharOffset == 0,"AddLigaturChars: unexpected base offset"); 
                   Invariant.Assert((ushort)(_nextCharIx + baseCharOffset + ligaturesCount) <= _charsCount, 
                                    "AddLigatureChars: invalid input params");
                    _nextCharIx = (ushort)(_nextCharIx + baseCharOffset); 

                    ushort glyphIx = _charMap[_nextCharIx];
                    ushort clusterIxOrShape = FontClient.IsScriptSupportedByFont ?
                        (ushort)CharShapeInfo.NoFlagsSet : _pClusters[_nextCharIx]; 

                   _glyphInfoList.LigatureCounts[ glyphIx ] = ligaturesCount; 
                    AddGlyphs( -(ligaturesCount - 1) );  // reduce size of GlyphInfoList 

                    while (--ligaturesCount > 0) 
                    {
                        ++_nextCharIx;
                        _charMap[_nextCharIx] = glyphIx;
                        _pClusters[_nextCharIx] = clusterIxOrShape; 
                    }
                } 
            } 

            public bool                              AreLigaturesInhibited 
            {
               get { return _forceInhibitLigature; }
            }
 
            public IScriptCharConverter              CharConverter
            { 
                get { return _charConverter; } 
            }
 
            public UshortList                        CharMap // also see CurrentGlyphIx
            {
               get { return _charMap; }
            } 

            public ushort                            CharsCount 
            { 
               get { return _charsCount; }
            } 

           /// 
           ///     ShapingWorkspace.CompileShapingProperties - helper function for GetGlyphs.
           ///  
           /// 
           ///      This is the last helper function called by shaping engine's GetGlyph call. 
           ///      All the glyphs and glyph properties resulting from shaping the text is trans- 
           ///      ferred into the output arrays/lists.
           ///  
           /// 
           ///     Critical: This code is unsafe
           /// 
           [SecurityCritical] 
           unsafe public void CompileShapingProperties (
               bool                           forceDiacriticsToZeroWidth, 
               out int                        glyphCount, 
               out ushort[]                   glyphIndices,
               out GlyphShapingProperties[]   glyphProperties 
           )
           {
               Invariant.Assert(_charsCount < ushort.MaxValue, "CompileShapingProperties, too many characters");
               Invariant.Assert(_glyphInfoList.Length > 0,  "CompileShapingProperties, glyphsCount <= 0"); 

               ushort firstClusterGlyph = 0; 
               ushort firstClusterChar  = 0; 
               ushort afterClusterGlyph;
               ushort afterClusterChar; 
               ushort markFlags = (ushort)(forceDiacriticsToZeroWidth  ?
                 (GlyphFlags.Diacritic | GlyphFlags.ZeroWidth) : GlyphFlags.Diacritic);

               glyphCount = _glyphInfoList.Length ; 
               glyphIndices    = _glyphInfoList.Glyphs.GetCopy();   // create output copy of glyphs
               glyphProperties = new GlyphShapingProperties[glyphCount]; 
 

               // Go through all the characters and compile shaping properties. Mapping is local 
               // to cluster, so doing every cluster as a whole.
               for(int iChar = 1; iChar <= _charsCount; iChar++)
               {
                   if (iChar < _charsCount && _pClusters[iChar] == firstClusterGlyph) 
                   {
                       //We are still inside same cluster 
                       continue; 
                   }
 
                   // New cluster found. Get boundaries
                   afterClusterChar  = (ushort)iChar;
                   afterClusterGlyph = (iChar < _charsCount) ? _pClusters[iChar] : (ushort)glyphCount;
 
                   //Cluster map should come valid from shaping engine
                   Debug.Assert(firstClusterGlyph < afterClusterGlyph); 
 
                   int localMap = 0;
                   for(int iClusterChar = firstClusterChar; iClusterChar < afterClusterChar; iClusterChar++) 
                   {
                       // Clusters should be independent, otherwise they should be merged by shaping engine
                       Debug.Assert(_charMap[iClusterChar] >= firstClusterGlyph);
                       Debug.Assert(_charMap[iClusterChar] < afterClusterGlyph); 

                       if (_isSerializedClusterEntriesRequired && iClusterChar > firstClusterChar) 
                       { 
                            // Its possible that the clusters have mappings that will make line services
                            // uphappy.  An example is "Ra+halant+Ra+halant+Ra+halant+Ra+halant+Ra+halant" 
                            // The first "Ra+halant" will be a reph, repositioned to the end of the cluster.
                            // The font may have formed a glyph from the base
                            // "Ra" and the final "halant", so that the glyphs' first character values will be
                            // (relative to the start of the cluster) 0,1,3,6 and the ligature counts will 
                            // be 2,2,2,2.  The character map will be 0,1,1,3,3,0,4,4 (ie, the cluster's 1st
                            // and 6th character map to the 1st glyph). We'll discover that here if the 
                            // current char is mapped to an earlier glyph. 
                           int prevCharIx = iClusterChar - 1;
                           if (_charMap[iClusterChar] < _charMap[prevCharIx]) 
                           {
                                // this cluster has "interesting" mapping.  LS (Line Services)
                                // doesn't like interesting mapping so lets remap cluster so that
                                // all the entries in the map are sequential. 
                               ushort glyphIx = _charMap[iClusterChar];
                               _charMap[iClusterChar] = _charMap[prevCharIx]; 
                               while (prevCharIx > firstClusterChar && _charMap[prevCharIx] != glyphIx) 
                               {
                                    _charMap[prevCharIx] = _charMap[prevCharIx - 1]; 
                                    _pCharProps[prevCharIx].EngineReserved =
                                        (byte)(_charMap[prevCharIx] - firstClusterGlyph);

                                    --prevCharIx; 
                               }
 
                               ushort newGlyphIx = _charMap[iClusterChar]; 
                               while (++glyphIx <= newGlyphIx)
                               { 
                                   _glyphInfoList.FirstChars[glyphIx] += 1;
                               }

 
                           }
 
 
                       }
 
                       localMap = _charMap[iClusterChar] - firstClusterGlyph;

                       // Shaping porperties do not support more than 255 glyph/chars in single cluster.
                       // if cluster is longer than 255 glyphs, make everything beyond that map to glyph 255 
                       if (localMap > 255)
                       { 
                           localMap = 255; 
                       }
 
                       // Only set canGlyphAlone on space when it is 1:1 mapping with the glyph.
                       bool canGlyphAlone = (Classification.CharAttributeOf((int)Classification.GetUnicodeClassUTF16(_pChars[iClusterChar])).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0
                                          && afterClusterChar  - firstClusterChar == 1     // cluster is 1 char long
                                          && afterClusterGlyph - firstClusterGlyph == 1;   // cluster is 1 glyph long 

                       _pCharProps[iClusterChar].CanGlyphAlone = canGlyphAlone; 
                       _pCharProps[iClusterChar].EngineReserved= (byte)localMap; 
                   }
 
                   // make sure the start of the cluster is marked...
                   // set the cluster start flag for the last cluster
                   _glyphInfoList.GlyphFlags[firstClusterGlyph] |= (ushort)GlyphFlags.ClusterStart;
 
                   // go through all the glyphs of the cluster
                   for(int iClusterGlyph = firstClusterGlyph; iClusterGlyph < afterClusterGlyph; iClusterGlyph++) 
                   { 
                       ushort firstChar = _glyphInfoList.FirstChars[iClusterGlyph];
                       ushort ligaCount = _glyphInfoList.LigatureCounts[iClusterGlyph]; 
                       ushort glyphFlags = _glyphInfoList.GlyphFlags[iClusterGlyph];

                       // check for any adjustments that need to be made in the glyph
                       // flags 

                       // First, validate the glyph id 
                       if (glyphIndices[iClusterGlyph] > FontClient.GetMaxGlyphId) 
                       {
                            // invalid glyph index (too big to be valid), so just hide it. 
                            glyphFlags  = GlyphFlagsZeroWidth;
                            glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph;
                       }
 
                       // If the glyph's missing...
                       if ((glyphFlags & (ushort)GlyphFlags.Missing) != 0) 
                       { 
                           // for missing glyphs, check if we know something about it...
 
                           // (check if its a unicode control character)
                           if ((glyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0)
                           {
                               glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph; 
                               glyphFlags  = GlyphFlagsZeroWidth;
                           } 
                       } 
                        // if its a mark glyph ...
                       else if ( ((glyphFlags & (ushort)GlyphFlags.GlyphTypeMask) == 
                                            (ushort)GlyphFlags.Mark)  ||
                                   (iClusterGlyph != firstClusterGlyph &&
                                   (glyphFlags & (ushort)GlyphFlags.GlyphTypeMask) ==
                                            (ushort)GlyphFlags.Unresolved) 
                                 )
                       { 
                           // set our diacritic glyph flags. 
                           glyphFlags = (ushort)(glyphFlags | markFlags);
                       } 
                       // check if this is a unicode control char (ZWJ, etc) and we want to hide
                       // such...
                       else if ((glyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 &&
                                _forceControlCharsInvisible && _controlCharsSeen && 
                                FontClient.IsUnicodeControlGlyph(glyphIndices[iClusterGlyph]))
                       { 
                            glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph; 
                            glyphFlags = GlyphFlagsZeroWidth;
                       } 

                       // Clusters should be independent, otherwise they should be merged by shaping engine
                       Debug.Assert(firstChar >= firstClusterChar);
                       Debug.Assert(firstChar < afterClusterChar); 

                       localMap = firstChar - firstClusterChar; 
 
                       // Shaping porperties do not support more than 255 glyph/chars in single cluster.
                       // if cluster is longer than 255 glyphs, make everything beyond that map to glyph 255 
                       if (localMap >= 255)
                       {
                           localMap = 255;
                       } 

                       if (ligaCount > 255) 
                       { 
                           ligaCount = 255;
                       } 

                       glyphProperties[iClusterGlyph] =
                            new GlyphShapingProperties(glyphFlags,
                                                       (ushort)((ligaCount << 8) | localMap) ); 
                   }
 
                   firstClusterChar  = afterClusterChar; 
                   firstClusterGlyph = afterClusterGlyph;
               } 
           }

          // the "Current???" accessors are used in the various engines shaping loops
 
          /// 
          /// CurrentChar - returns current char 
          ///  
          /// 
          /// Critical - The method reads into  an unvalidated unsafe array 
          /// 
          unsafe public char                        CurrentChar
          {
              [SecurityCritical] 
              get { return _pChars[_nextCharIx]; }
          } 
 
          /// 
          /// CurrentCharIx - returns current char index 
          /// 
          public ushort                             CurrentCharIx
          {
              get { return (ushort)_nextCharIx; } 
          }
 
 
          /// 
          /// CurrentGlyph - sets/gets current glyph 
          /// 
          public ushort                             CurrentGlyph
          {
              get { return _glyphInfoList.Glyphs[ _charMap[_nextCharIx] ]; } 
              set { _glyphInfoList.Glyphs[ _charMap[_nextCharIx] ] = value; }
          } 
 
          /// 
          /// CurrentShape - returns/sets current char shape info 
          /// 
          /// 
          /// Critical - The method reads into  an unvalidated unsafe array
          ///  
          unsafe public CharShapeInfo               CurrentShape
          { 
              [SecurityCritical] 
              get { return _pShapes[_nextCharIx]; }
              [SecurityCritical] 
              set { _pShapes[_nextCharIx] = value; }
          }

          public ShaperFontClient                   FontClient 
          {
              get { return _fontClient; } 
          } 

          ///  
          /// Critical - The method reads into  an unsafe array
          /// 
          [SecurityCritical]
          unsafe public char GetChar(ushort charIx) 
          {
            return (charIx < _charsCount) ? _pChars[charIx] : '\u0000'; 
          } 

          public ushort GetGlyph(ushort glyphIx) 
          {
             return _glyphInfoList.Glyphs[glyphIx];
          }
 
          public ushort GetGlyphIx(ushort charIx)
          { 
             return _charMap[charIx]; 
          }
 
         /// 
         /// Critical - The method reads into  an unsafe array
         /// 
         [SecurityCritical] 
         public bool GetNextCharProperties (out char nextChar, out ushort nextGlyph, out CharShapeInfo nextShape)
         { 
            ToNextChar(); 

            nextChar = CurrentChar; 
            nextGlyph = CharConverter.ToGlyph(nextChar);
            nextShape = CharConverter.ToShapeInfo(nextChar);

            return !_finishedShaping; 
         }
 
         ///  
         /// Critical - The method reads into  an unsafe array
         ///  
         [SecurityCritical]
         public bool GetNextChar(out char nextChar)
         {
            ToNextChar(); 

           nextChar = CurrentChar; 
           return !_finishedShaping; 
         }
 
         /// 
         /// Critical - The method reads into  an unsafe array
         /// 
         [SecurityCritical] 
         public bool GetNextShape(out CharShapeInfo nextShape)
         { 
            ToNextChar(); 

           nextShape = CharConverter.ToShapeInfo(CurrentChar); 
           return !_finishedShaping;
         }

             ///  
             /// Critical - The method reads into  an unsafe array
             ///  
             [SecurityCritical] 
             unsafe public CharShapeInfo GetShapeInfo(int charIx)
             { 
                 return (CharShapeInfo)((charIx >= 0 && charIx < _charsCount) ? _pShapes[charIx] : CharShapeInfo.NoFlagsSet);
             }

 

             ///  
             /// GlyphsCount - returns glyphs count 
             /// 
             public int                                 GlyphsCount 
             {
                get {   if (_nextGlyphIx == GlyphInfoList.Length && _addedGlyphsCount > 0)
                        {
                            // if we are at the end of the glyph list and there're deferred 
                            // glyph additions, add the deferred glyphs now.
                            _isAutoInsert = true; // inhibit updating "inserted" glyphs 
                            InsertGlyphs((ushort)GlyphInfoList.Length,(ushort)_addedGlyphsCount); 
                            _addedGlyphsCount = 0;
                        } 

                        return GlyphInfoList.Length;
                    }
 
             }
 
 
             public GlyphInfoList                      GlyphInfoList
             { 
                 get { return _glyphInfoList; }
             }

             public bool                               HasLeadingJoin 
             {
                 get { return _hasLeadingJoin; } 
             } 

             public bool                               HideControlChars 
             {
                 get { return _forceControlCharsInvisible && _controlCharsSeen; }
             }
 

             public bool                               IsFinished 
             { 
                 get { return _finishedShaping; }
             } 

             /// 
             /// InsertGlyphs - insert more glyphs into glyphinfolist
             ///  
             public int InsertGlyphs(ushort insertionPoint,
                                       ushort insertCount) 
             { 
                int insertedCount = 0;
                int glyphsCount = GlyphInfoList.Length; 

                 if ( insertionPoint < glyphsCount )
                 {
                     GlyphInfoList.Insert(insertionPoint, insertCount); 
                     if (GlyphInfoList.Length > glyphsCount)
                     { 
                        insertedCount = GlyphInfoList.Length - glyphsCount; 
                     }
 
                 }
                 else if ( insertionPoint == glyphsCount )
                 {
                     if (_inited) 
                         GlyphInfoList.Insert( 0, insertCount > CharsCount ? insertCount : CharsCount);
                     else 
                         GlyphInfoList.Insert(glyphsCount, insertCount); 

                     if (GlyphInfoList.Length > glyphsCount) 
                     {
                        insertedCount = GlyphInfoList.Length - glyphsCount;
                     }
 
                 }
 
                 // if we have inserted glyphs in front of the current glyph index, 
                 // increment the glyph index.  The assumption is made that the
                 // inserted glyph(s) should be mapped to the same character as the 
                 // first glyph that's being displaced (so we don't adjust the
                 // charmap entry that points to this glyph position)
                 if (!_inited && !_isAutoInsert && insertionPoint <= _nextGlyphIx && _nextGlyphIx <= glyphsCount)
                 { 
                    for (int i = 0; i <= _nextCharIx; ++i)
                    { 
                        if (_charMap[i] > insertionPoint) 
                        {
                           _charMap[i] += (ushort)insertedCount; 
                        }
                    }

                    // normally, "afterInsertionGlyphIx" will be the first glyph position 
                    // after the inserted members of GlyphInfoList.  There's one exception;
                    // when the insertion point is at glyphsCount (this implies that 
                    // _nextGlyphIx also is at glyphsCount) we are "inserting" glyphs 
                    // "in front of" the last glyph but the insertion code above actually
                    // added the elements to the end of the glyphs array. So, in this end 
                    // case, the inserted elements are set up from the last entry in the glyphs
                    // array (last before we added these glyphs, of course).
                    ushort afterInsertionGlyphIx = insertionPoint < glyphsCount ?
                        (ushort)(insertionPoint + insertedCount) : (ushort)(glyphsCount - 1); 
                    Debug.Assert(afterInsertionGlyphIx < glyphsCount + insertedCount,"improper use of InsertGlyphs");
 
                    for (int i = 0; i < insertedCount; ++i) 
                    {
                        GlyphInfoList.FirstChars[insertionPoint + i] = GlyphInfoList.FirstChars[afterInsertionGlyphIx]; 
                        GlyphInfoList.LigatureCounts[insertionPoint + i] = GlyphInfoList.LigatureCounts[afterInsertionGlyphIx];
                        GlyphInfoList.GlyphFlags[insertionPoint + i] = GlyphInfoList.GlyphFlags[afterInsertionGlyphIx];
                    }
 
                    _nextGlyphIx = (ushort)(_nextGlyphIx + insertedCount);
                 } 
 
                 _isAutoInsert = false;     // always reset this
                 return insertedCount; 
             }

            public bool MoveGlyphs (ushort destGlyphIx, ushort srcGlyphIx, ushort moveCount             )
            { 
                ushort glyphsCount = (ushort)_glyphInfoList.Length;
 
                if (srcGlyphIx + moveCount <= srcGlyphIx ||     // make sure no overflow 
                    destGlyphIx + moveCount <= destGlyphIx ||   // make sure no overflow
                    (srcGlyphIx + moveCount - 1) >= glyphsCount ||    // and make sure valid move arguments 
                    (destGlyphIx + moveCount - 1) >= glyphsCount)     // and make sure valid move arguments
                {
                    return false;
                } 

                if (srcGlyphIx < destGlyphIx && srcGlyphIx + moveCount > destGlyphIx) 
                { 
                    // buffers overlap, copy from end of src buffer
                    // src:     ++++++++++++++++++++++++++++ 
                    // dest:         ++++++++++++++++++++++++++++
                    srcGlyphIx += moveCount;
                    destGlyphIx += moveCount;
                    while (moveCount-- > 0) 
                    {
                        _glyphInfoList.Glyphs[--destGlyphIx] = _glyphInfoList.Glyphs[--srcGlyphIx]; 
                    } 
                }
                else if (srcGlyphIx != destGlyphIx) 
                {
                    while (moveCount-- > 0)
                    {
                        _glyphInfoList.Glyphs[destGlyphIx++] = _glyphInfoList.Glyphs[srcGlyphIx++]; 
                    }
                } 
 
                return true;
            } 

             /// 
             /// NextChar - returns next char
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array 
             ///  
             unsafe public char                        NextChar
             { 
                 [SecurityCritical]
                 get { return
                         (_nextCharIx + 1 < _charsCount ) ?
                               _pChars[_nextCharIx + 1] : (char)0; } 
             }
 
             ///  
             /// NextGlyphIx - returns/sets next glyphIx
             ///  
             public ushort                                 NextGlyphIx
             {
                 get { return _nextGlyphIx; }
             } 

             ///  
             /// ShapingWorkspace.PopulateClusterMap - helper function for GetGlyphs. 
             /// 
             ///  
             ///     This function creates the cluster map based on shape flags.  The
             ///     shape engine will have set the IsStartOfCluster flag for all
             ///     characters that start a cluster. (CAUTION:  the cluster array
             ///     and the shape flag array are actually the same memory block 
             ///     so don't try to use a given character's shape info after
             ///     setting its cluster info. ) 
             ///  
             /// 
             /// Critical - uses pointers, unsafe code 
             /// 
             [SecurityCritical]
             unsafe public void PopulateClusterMap ()
             { 

                if (!FontClient.IsFeatureTypeSupportedByFont) return;   // nothing to do (SetCurrentClusterInfo already set the map up) 
 
                  ushort *clusterMap = _pClusters;
 
                  Invariant.Assert(_glyphInfoList.Length > 0,  "PopulateClusterMap, glyphsCount <= 0");

                  Reset(0,0,_charsCount);
 

                  // Step 1. Create the cluster map based on the shape flags... 
 

                  // this loop goes through all the shapes (one per Unicode character) and 
                  // creates the cluster map.  When each start of cluster is found the
                  // associated glyph is assumed to be the value for this new cluster unless
                  // there's reason to suspect its not.
                  int firstGlyphInCluster   =  0; 
                  int  firstCharInCluster = 0;
                  int  earliestGlyphRef = 0; 
                  int  earliestCharRef = 0; 
                  int  currentCharIx;
                  int  currentGlyphIx; 
                  int  currentGlyphFirstChar;

                  // add the glyphs to the glyph array
                  while (ToNextChar()) 
                  {
                      currentCharIx = _nextCharIx; 
                      currentGlyphIx = _charMap[_nextCharIx]; 
                      Invariant.Assert(currentGlyphIx < _glyphInfoList.Length, "illegal glyph ix in charMap");
 

                      // It is possible that this current character is part of a ligature glyph that actually spans
                      // multiple clusters (including a previous cluster, so check the glyph's FirstChar
                      // clustermap entry (it might be even earlier than currentGlyphIx) 
                      currentGlyphFirstChar = (int)_glyphInfoList.FirstChars[currentGlyphIx];
                      if (currentGlyphFirstChar < firstCharInCluster) 
                      { 
                          // Since currentGlyphFirstChar < firstCharInCluster, clusterMap[currentGlyphFirstChar]
                          // is already filled with its glyph id so we can use it and check if the glyph it 
                          // references is earlier than what we currently know about.
                          if (clusterMap[currentGlyphFirstChar] < earliestGlyphRef)
                          {
                              earliestGlyphRef = clusterMap[currentGlyphFirstChar]; 
                          }
 
                          if (currentGlyphFirstChar < earliestCharRef) 
                          {
                              earliestCharRef = currentGlyphFirstChar; 
                          }
                      }

 
                      // As each character is processed, we'll keep track of the earliest glyph referenced
                      // in the glyphs that are part of the current cluster.  This information will be used 
                      // when the next start of cluster is detected. 
                      if (currentGlyphIx < earliestGlyphRef)
                      { 
                          earliestGlyphRef = currentGlyphIx;    // save this earlier glyph reference
                      }

 
                     if ((CurrentShape & (CharShapeInfo.IsStartOfCluster)) != 0)
                     { 
 
                         // starting a new cluster...
 
                        if (currentGlyphIx == earliestGlyphRef)
                         {
                             // we will normally be here for the first glyph, but otherwise
                             // this seems an unlikely case; if here then this is not actually 
                             // the end of one cluster and the beginning of another, but rather
                             // a concatenation of two clusters. 
                         } 
                         else
                         { 
                             // this glyph starts a new cluster so go back over the glyphs in the preceding
                             // cluster to verify that all is well.  It may be that we have discovered new
                             // information (ie, membership in cluster includes earlier glyphs or characters)
                             // since the first char in the last cluster. 
                             if (earliestGlyphRef < firstGlyphInCluster || earliestCharRef < firstCharInCluster)
                             { 
                                 // we need to change the last cluster's extent and/or its value! 
                                 firstGlyphInCluster = earliestGlyphRef;
                                 firstCharInCluster = earliestCharRef; 
                                 for (int i = firstCharInCluster; i < currentCharIx; ++i)
                                 {
                                     clusterMap[i] = (ushort)firstGlyphInCluster;
                                 } 

                             } 
 

                             // As long as this char (the first in a new cluster) is after the current cluster's 
                             // first char, set up the counters for this new cluster.  Otherwise, since this
                             // character is before the current cluster's first character (must have been
                             // updated in the if block just above) don't change the current cluster.
                             if (firstCharInCluster < currentCharIx) 
                             {
 
                                 // keep track of the first char in cluster 
                                 firstCharInCluster = currentCharIx;
                                 firstGlyphInCluster = currentGlyphIx; 

                                 if (currentGlyphFirstChar < currentCharIx)
                                 {
                                    earliestCharRef = currentGlyphFirstChar; 
                                    earliestGlyphRef = clusterMap[earliestCharRef];
                                 } 
                                 else 
                                 {
                                    earliestCharRef = currentCharIx; 
                                    earliestGlyphRef = currentGlyphIx;
                                 }
                             }
                         } 

                     } 
 

                     clusterMap[currentCharIx] = (ushort)firstGlyphInCluster;        // save this char's cluster info 
                  }


                  // If the last character is the last character in the last cluster (ie, if 
                  // it doesn't have the StartOfCluster flag ), then need to check
                  // update the cluster info.  Check "earliestCharRef" to determine this; normally, 
                  // if the last character has its StartOfCluster flag set, "earliestCharRef" will 
                  // be the index of the last character.
                  if (earliestCharRef + 1 < CharsCount) 
                  {
                     // check if final cluster adjustment is needed
                      if (earliestGlyphRef < firstGlyphInCluster || earliestCharRef < firstCharInCluster)
                      { 
                          // we need to change the last cluster's extent and/or its value!
                          for (int i = earliestCharRef; i < CharsCount; ++i) 
                          { 
                              clusterMap[i] = (ushort)(earliestGlyphRef);
                          } 

                      }
                  }
 
                  Invariant.Assert( clusterMap[0] == 0, "first cluster map entry is not zero");
 
             } 
             /// 
             /// PreviousChar - returns previous char 
             /// 
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array
             ///  
             unsafe public char                        PreviousChar
             { 
                 [SecurityCritical] 
                 get { return _pChars[ PreviousCharIx ]; }
             } 

             /// 
             /// PreviousCharIx - returns previous char index
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array 
             ///  
             unsafe public ushort                     PreviousCharIx
             { 
                 get {
                        return (_inited ? _nextCharIx : (_nextCharIx == 0 ? (ushort) 0 :
                                ( _nextCharIx >= _charsCount ? (ushort)(_charsCount- 1) : (ushort)(_nextCharIx - 1))));
                     } 
             }
 
             ///  
             /// PreviousGlyph - sets/gets previous glyph
             ///  
             public ushort                             PreviousGlyph
             {
                 get {  return _inited ? (ushort) 0 : _glyphInfoList.Glyphs[ PreviousGlyphIx ]; }
                 set {  _glyphInfoList.Glyphs[ PreviousGlyphIx ] = value; } 
             }
 
 
             /// 
             /// PreviousGlyphIx - gets previous glyph index 
             /// 
             public ushort                            PreviousGlyphIx
             {
                 get { return   _inited ? (ushort) _nextGlyphIx : _charMap[ PreviousCharIx ]; } 
             }
 
             ///  
             /// PreviousShape - gets previous char shape
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array
             /// 
             unsafe public CharShapeInfo               PreviousShape 
             {
                 [SecurityCritical] 
                 get { return PreviousCharIx == CurrentCharIx ? CharShapeInfo.NoFlagsSet : _pShapes[ PreviousCharIx ]; } 
             }
 
             /// 
             /// ForceSerializedCluster -
             /// 
             public bool                            IsForceSerializedClusterOn 
             {
                 set { _isSerializedClusterEntriesRequired = value; } 
             } 

 
             /// 
             /// ShapingWorkspace.Reset - used to re-initial the MoveToNextChar mechanism
             ///        (our iterator function, if you please!).  This flavor of the
             ///        reset function just resets the iteration booleans without moving 
             ///        the next character index
             ///  
             public bool Reset(  ) 
             {
                 _inited = true; 
                 _finishedShaping = (_nextCharIx > _lastCharIx);

                 return !_finishedShaping;
             } 

             ///  
             /// ShapingWorkspace.Reset - used to re-initial the MoveToNextChar mechanism 
             ///        (our iterator function, if you please!).
             ///  
             public bool Reset(  ushort nextCharIx,
                                   ushort nextGlyphIx,
                                   ushort charCount )
             { 
                 _nextCharIx = nextCharIx;
                 _nextGlyphIx = nextGlyphIx; 
                 _inited = true; 
                 _finishedShaping = false;
 
                 _lastCharIx = (ushort)(nextCharIx + charCount - 1);
                if (_lastCharIx >= _charsCount)
                {
                    _lastCharIx = (ushort)(_charsCount - 1); 
                }
 
                 // we allow nextGlyphIx == GlyphsCount because of the case where 
                 // we're adding glyphs syllable by syllable (so we will allocate
                 // the next syllable's glyphs later) 
                 Invariant.Assert(_nextCharIx < _charsCount);
                 Invariant.Assert(_nextGlyphIx <= GlyphsCount);

                 return !_finishedShaping; 
             }
 
 
            /// 
            /// SetGlyphPropertiesUsingShapeInfo - This is the default call to set up the 
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character.
            /// 
            ///  
            /// Critical - The method reads/write unsafe pointers
            ///  
            [SecurityCritical] 
            unsafe public void SetGlyphPropertiesUsingShapeInfo ( CharShapeInfo currShape )
            { 
                char currChar = _pChars[_nextCharIx];
                ushort glyph = CharConverter.ToGlyph(currChar);

                _pShapes[_nextCharIx] = currShape; 
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 
            } 

            ///  
            /// SetGlyphPropertiesUsingChar - This sets up the
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character using the passed in character.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetGlyphPropertiesUsingChar ( CharShapeInfo currShape, char currChar) 
            {
                ushort glyph = CharConverter.ToGlyph(currChar);

                _pShapes[_nextCharIx] = currShape; 
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 
            } 

            ///  
            /// SetGlyphPropertiesUsingGlyph - This sets up the
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character using the passed in glyph.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetGlyphPropertiesUsingGlyph ( CharShapeInfo currShape, ushort glyph ) 
            {
                _pShapes[_nextCharIx] = currShape;
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 

            } 
 
            /// 
            /// SetGlyphProperties - This sets up the glyphInfoList 
            /// for the current glyph position and it increments
            ///  _nextGlyphIx.  If the script is not supported by this
            /// font (ie, the font has no OT tables for this script),
            /// then the cluster map is updated, too. If the font does have 
            /// support for script, then shaping info is valid in _pShapes;
            /// so if this character's shape indicates that we desire 
            /// a dotted circle glyph inserted then this is done. 
            /// 
            ///  
            /// Critical - The method reads/write unsafe pointers
            /// 
            [SecurityCritical]
            unsafe public void SetGlyphProperties ( ushort glyph ) 
            {
                // Be aware of the side effect of GlyphsCount; it is necessary 
                // that the comparison below be done if there're added glyphs 
                // to be considered.
                Invariant.Assert(_nextGlyphIx < GlyphsCount, "SetGlyphProperties called with invalid glyphIx"); 

                // fill this character's glyph info list entries
                _glyphInfoList.Glyphs[_nextGlyphIx] = glyph;
                _glyphInfoList.FirstChars[_nextGlyphIx] = (ushort)_nextCharIx; 
                _glyphInfoList.LigatureCounts[_nextGlyphIx] = 1;
                _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsNone; 
                if (glyph == 0) 
                {
                     _glyphInfoList.GlyphFlags[_nextGlyphIx] |= (ushort)GlyphFlags.Missing; 
                }

                // check the shape flags and take appropriate action
                CharShapeInfo currentShape = _pShapes[_nextCharIx]; 

                // if this shape indicates that here is an inserted base insertion 
                // point, insert the dotted circle. 
                if ((currentShape & CharShapeInfo.RequiresInsertedBase) == CharShapeInfo.RequiresInsertedBase)
                { 
                    ushort dottedCircleGlyph = FontClient.DottedCircleGlyph;
                    if (dottedCircleGlyph != 0)
                    {
                        InsertGlyphs(_nextGlyphIx,1);   // this will increment _nextGlyphIx 
                        Invariant.Assert(_nextGlyphIx < GlyphsCount,
                                         "Invalid glyph ix for insertion of invalid base"); 
 
                        _glyphInfoList.Glyphs[_nextGlyphIx - 1] = dottedCircleGlyph;
                        _glyphInfoList.GlyphFlags[_nextGlyphIx - 1] = (ushort)GlyphFlags.InvalidBase; 
                    }

                }
                else if( (currentShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) 
                {
 
                    // This is a Unicode control glyph.  Let font client know 
                    // so it can save glyph id if it wants to (may be used to
                    // suppress visible Unicode control characters later) 
                    FontClient.SetUnicodeControlGlyph(CurrentChar, glyph);

                    _controlCharsSeen = true;
                    _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsZeroWidth; 
                }
 
                // If font doesn't have feature support, just set up the 
                // cluster info directly
                if ( !FontClient.IsFeatureTypeSupportedByFont ) 
                {
                    SetCurrentClusterInfo(currentShape, glyph);
                }
 
                // set next glyph (allow to go one beyond the last to detect the last glyph
                // being written 
                if ((ushort)( _nextGlyphIx + 1) <= GlyphsCount) 
                {
                    _nextGlyphIx = (ushort)( _nextGlyphIx + 1); 
                }
            }

            ///  
            /// SetCurrentClusterInfo - This sets up the glyphInfoList
            /// for the current glyph position and it increments 
            ///  _nextGlyphIx.  If the script is not supported by this 
            /// font (ie, the font has no OT tables for this script),
            /// then the cluster map is updated, too. If the font does have 
            /// support for script, then shaping info is valid in _pShapes;
            /// so if this character's shape indicates that we desire
            /// a dotted circle glyph inserted then this is done.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetCurrentClusterInfo ( CharShapeInfo currentShape, ushort glyph ) 
            {
                bool startOfCluster = (currentShape & CharShapeInfo.IsStartOfCluster) != 0;

                // font doesn't have feature support, so just set up the 
                // cluster info directly
                if( (currentShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) 
                { 
                    // For fonts that don't have feature support for this
                    // script -  if the user doesn't want to actually see 
                    // the control characters, replace them with a blank glyph.
                    // (For fonts with support, we do this later after feature
                    // application)
                    if (_forceControlCharsInvisible) 
                    {
                        _glyphInfoList.Glyphs[_nextGlyphIx] = FontClient.SpaceGlyph; 
                    } 
                }
                else if (startOfCluster) 
                {
                    if (glyph == 0)
                    {
                        _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsBase | (ushort)GlyphFlags.Missing; 
                    }
                    else 
                    { 
                        _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsBase;
                    } 
                }
                else
                {
                    _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsDiacritic; 
                }
 
                _pClusters[_nextCharIx] = 
                    ( _nextCharIx == 0 || startOfCluster ?
                    _nextGlyphIx : _pClusters[PreviousCharIx]); 

                _charMap[_nextCharIx] = _nextGlyphIx;   // set cluster map value
            }
 
            /// 
            /// SetGlyph - 
            ///  
            public void SetGlyph (ushort glyphIx, ushort glyph)
            { 
                _glyphInfoList.Glyphs[glyphIx] = glyph;
            }

            ///  
            /// SetGlyph -
            ///  
            public void SetGlyph (ushort glyphIx, ushort glyph, ushort firstChar) 
            {
                _glyphInfoList.Glyphs[glyphIx] = glyph; 
                _glyphInfoList.FirstChars[glyphIx] = firstChar;
            }

             ///  
             /// Critical - The method reads into  an unsafe array
             ///  
             [SecurityCritical] 
             unsafe public bool SetNextGlyphProperties (out CharShapeInfo nextShape)
             { 
                if (ToNextChar())
                {
                    char nextChar = CurrentChar;
 
                    nextShape = CharConverter.ToShapeInfo(nextChar);
                    _pShapes[_nextCharIx] = nextShape; 
 
                    _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                    SetGlyphProperties( CharConverter.ToGlyph(nextChar) ); 
                }
                else
                {
                    nextShape = CharShapeInfo.NoFlagsSet; 
                }
 
                return !_finishedShaping; 
             }
 
             /// 
             /// Critical - The method reads into  an unsafe array
             /// 
             [SecurityCritical] 
             unsafe public void SetShapeInfo(ushort charIx, CharShapeInfo charShape)
             { 
                 if (charIx >= 0 && charIx < _charsCount) 
                 {
                    _pShapes[charIx] = charShape; 
                 }
             }

            ///  
            /// ToNextChar - increments index, returns false if finished
            ///  
            public bool ToNextChar() 
            {
              if (_inited) 
              {
                // if this is the first character, don't increment the
                // index (so we can use this in a while (MoveToNextChar){...}
                // loop 
                _inited = false;
 
              } 
              else if (_nextCharIx < _lastCharIx)
              { 
                ++_nextCharIx;
              }
              else
              { 
                _finishedShaping = true;
                Invariant.Assert(_nextCharIx < _charsCount); 
              } 

              return !_finishedShaping; 
            }

            /// 
            /// Critical - The method reads into  an unsafe array 
            /// 
            [SecurityCritical] 
            public void UpdateCurrentGlyphProperties (CharShapeInfo newShape) 
            {
                if ((CurrentShape & CharShapeInfo.RequiresInsertedBase) 
                                        == CharShapeInfo.RequiresInsertedBase &&
                    (newShape & CharShapeInfo.RequiresInsertedBase)
                                        != CharShapeInfo.RequiresInsertedBase )
                { 
                    AddGlyphs(-1);
                } 
 
                _nextGlyphIx = _charMap[_nextCharIx];  // set glyph ix back
                SetGlyphPropertiesUsingGlyph( newShape, CurrentGlyph ); 
            }

            /// 
            /// Critical - The method reads into  an unsafe array 
            /// 
            [SecurityCritical] 
            public void ValidateGlyphsOut (ushort[] glyphs) 
            {
                bool areAllGlyphsZero = true; 

                for (int i = 0; i < glyphs.Length; ++i)
                {
                    if (glyphs[i] != 0) areAllGlyphsZero = false; 
                }
 
                Debug.Assert(areAllGlyphsZero,"ValidateGlyphsOut found an all zero'ed glyphs"); 
            }
 

            private int                         _addedGlyphsCount;
            private ushort                      _charsCount;   // number of chars in run.
            private IScriptCharConverter        _charConverter; 
            private bool                        _controlCharsSeen;
            private bool                        _finishedShaping; 
            private ShaperFontClient            _fontClient; 
            private bool                        _forceControlCharsInvisible;
            private bool                        _forceInhibitLigature; 

            private bool                        _inited;
            private bool                        _isAutoInsert;
            private bool                        _hasLeadingJoin; 
            private bool                        _isSerializedClusterEntriesRequired;
 
            private ushort                      _nextCharIx; 
            private ushort                      _nextGlyphIx;
 

            /// 
            ///    Critical: Holds reference to an unsafe pointer
            ///  
            [SecurityCritical]
            private unsafe char*                _pChars;  // the Unicode text buffer 
            [SecurityCritical] 
            private unsafe CharacterShapingProperties* _pCharProps; // char properties buffer
            [SecurityCritical] 
            private unsafe ushort*              _pClusters; // clusterMap buffer
            [SecurityCritical]
            private unsafe CharShapeInfo*       _pShapes; // char shapes buffer
 
            private UshortList                  _charMap;
            private GlyphInfoList               _glyphInfoList; 
            private ushort                      _lastCharIx; 

 
        }

}
 

// 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, 2005
// 
//  File:      ShapingWorkspace.cs
// 
//  Contents:  support for all the shaping engines - all the local 
//             variables for GetGlyphs and helpers are wrapped and
//             all unsafe pointer manipulation 
//             is done in this class.
//
//  Created:   06-24-2005 by Nick Beal
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Security;
using System.Security.Permissions; 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization; 
using MS.Internal.FontCache;
using MS.Internal.FontFace; 
using System.Windows.Media; 
using System.Windows.Media.TextFormatting;
using MS.Internal.PresentationCore; 
using MS.Utility;

namespace MS.Internal.Shaping
{ 

 
 
        /// 
        ///     ShapingWorkspace  provides safe interactions with the various buffers 
        ///     used by GetGlyphs.
        /// 
        /// 
        ///     This struct is created every time a shaping engine's GetGlyphs() method is called. 
        ///
        ///     All interaction on the unsafe buffers used for text characters and their related 
        ///     buffers (char map, cluster map, etc) done during IShaper.GetGlyphs methods 
        ///     are done through this struct's accessors and methods.
        ///  
        internal struct ShapingWorkspace
        {

            // These are shorthand aliaes for setting flags in GetGlyphs context. 
            internal const ushort GlyphFlagsNone = (ushort)(GlyphFlags.Unresolved);
            internal const ushort GlyphFlagsBase = (ushort)(GlyphFlags.ClusterStart | GlyphFlags.Unresolved); 
            internal const ushort GlyphFlagsZeroWidth = (ushort)(GlyphFlags.ZeroWidth | GlyphFlags.Unresolved); 
            internal const ushort GlyphFlagsDiacritic = (ushort)(GlyphFlags.Diacritic | GlyphFlags.Unresolved);
 
            /// 
            /// ShapingWorkspace - initializer for GetGlyphs helper currentRun
            /// 
            ///  
            ///     This function is always called from IShaper.GetGlyphs.
            ///  
            ///  
            ///     Critical: This code accepts checked pointers and extracts
            ///         unsafe pointers. 
            /// 
            [SecurityCritical]
            unsafe public ShapingWorkspace (
                Item                                        item, 
                ShapingOptions                              shapingFlags,
 
                ShaperFontClient                            shaperFontClient, 
                ShaperBuffers                               shaperBuffers,
 
                CheckedCharPointer                          chars,
                int                                         charCount,

                CheckedCharacterShapingPropertiesPointer    charProperties, 
                CheckedUShortPointer                        charClusterMap)
            { 
 
                Invariant.Assert(charCount > 0,"ShapingWorkspace: invalid char count");
                _charsCount = (ushort)charCount; 

                // save the shaping directives from our client
                _forceControlCharsInvisible = ((shapingFlags & ShapingOptions.DisplayControlCode) == 0);
                _forceInhibitLigature = ((shapingFlags & ShapingOptions.InhibitLigature) != 0); 

                // note if we have a leading ZWJ 
                _hasLeadingJoin = ((item.Flags & ItemFlags.LeadingJoin) != 0); 

                // initialize our shaper buffers and set up our local references 
                shaperBuffers.Initialize( (ushort)charCount, (ushort)charCount);
                _charMap = shaperBuffers.CharMap;
                _glyphInfoList = shaperBuffers.GlyphInfoList;
 
                // keep track of our font client, char converter
                _fontClient = shaperFontClient; 
                _charConverter = _fontClient.CharConverter; 

                // unpack the pointer containers and initialize our pointer 
                _pChars = chars.Probe(0, charCount);
                _pCharProps = charProperties.Probe(0, charCount);
                _pClusters = charClusterMap.Probe(0, charCount);
                _pShapes = (CharShapeInfo *)_pClusters; 

                // initialize our various counts 
                _addedGlyphsCount = 0; 
                _nextCharIx = _nextGlyphIx = 0;
                _lastCharIx = (ushort)(charCount - 1); 

                // initialize our local booleans
                _inited = true;
                _isAutoInsert = _controlCharsSeen = _finishedShaping = false; 
                _isSerializedClusterEntriesRequired = true;
 
            } 

            // various accessors, function... 
            // I have laid these out alphabetically.  If a particular variable has
            // an accessor with a different name than the variable, I've added a
            // comment in the position of the variable...
 

            ///  
            /// AddGlyphs - add more glyphs to glyphinfolist 
            /// 
            ///  
            ///     This function can be used to increase or decrease the logical
            ///     size of the glyph info lists.
            ///     If increasing the size the GlyphInfoList is not actually
            ///     resized, but the _addedGlyphsCount is incremented (the actual 
            ///     resize will occur later - this is to minimize the overhead of
            ///     resizing).  The resizing will actually occur when GlyphsCount 
            ///     accessor is invoked. 
            ///     If decreasing the logical size of the glyph info lists, a check
            ///     is made so that any pending added glyphs are taken into account 
            ///     in the logical resizing and the _nextGlyphIx is adjusted if it
            ///     is affected by the reduction of the list size.
            /// 
            ///  
            /// Critical - The method calls critical code (GlyphInfoList.SetLength)
            ///  
            [SecurityCritical] 
            public int AddGlyphs(int addCount)
            { 
                if (addCount < 0)
                {
                    int glyphsCount = GlyphInfoList.Length;
 
                    // we're decreasing the extent of our glyphs list
                    // NOTE: we saved glyphsCount above because 
                    // GlyphsCount may increase the glyphInfoList 
                    // size (if there're pending "add glyphs")
                    if ((GlyphsCount + addCount) > 0) 
                    {
                        GlyphInfoList.SetLength (GlyphsCount + addCount);
                    }
 
                    if (_nextGlyphIx >= glyphsCount + addCount)
                    { 
                        _nextGlyphIx = (ushort)((int)_nextGlyphIx + addCount); 
                    }
                } 
                else
                {
                    _addedGlyphsCount += addCount;
                } 
                return addCount;
            } 
 
            /// 
            ///     AddLigatureChars - Updates the current glyph info's ligature count. 
            /// 
            /// 
            ///         This function updates the current glyph info's ligature count and
            ///         maps the charmap, cluster (or shape) values for each of the following 
            ///         chars that are part of the ligature.
            ///  
            ///  
            /// Critical - The method reads/write unsafe pointers
            ///  
            [SecurityCritical]
            unsafe public void AddLigatureChars(int baseCharOffset, ushort ligaturesCount)
            {
                if (ligaturesCount > 1) 
                {
                   Debug.Assert(baseCharOffset == -1 || baseCharOffset == 0,"AddLigaturChars: unexpected base offset"); 
                   Invariant.Assert((ushort)(_nextCharIx + baseCharOffset + ligaturesCount) <= _charsCount, 
                                    "AddLigatureChars: invalid input params");
                    _nextCharIx = (ushort)(_nextCharIx + baseCharOffset); 

                    ushort glyphIx = _charMap[_nextCharIx];
                    ushort clusterIxOrShape = FontClient.IsScriptSupportedByFont ?
                        (ushort)CharShapeInfo.NoFlagsSet : _pClusters[_nextCharIx]; 

                   _glyphInfoList.LigatureCounts[ glyphIx ] = ligaturesCount; 
                    AddGlyphs( -(ligaturesCount - 1) );  // reduce size of GlyphInfoList 

                    while (--ligaturesCount > 0) 
                    {
                        ++_nextCharIx;
                        _charMap[_nextCharIx] = glyphIx;
                        _pClusters[_nextCharIx] = clusterIxOrShape; 
                    }
                } 
            } 

            public bool                              AreLigaturesInhibited 
            {
               get { return _forceInhibitLigature; }
            }
 
            public IScriptCharConverter              CharConverter
            { 
                get { return _charConverter; } 
            }
 
            public UshortList                        CharMap // also see CurrentGlyphIx
            {
               get { return _charMap; }
            } 

            public ushort                            CharsCount 
            { 
               get { return _charsCount; }
            } 

           /// 
           ///     ShapingWorkspace.CompileShapingProperties - helper function for GetGlyphs.
           ///  
           /// 
           ///      This is the last helper function called by shaping engine's GetGlyph call. 
           ///      All the glyphs and glyph properties resulting from shaping the text is trans- 
           ///      ferred into the output arrays/lists.
           ///  
           /// 
           ///     Critical: This code is unsafe
           /// 
           [SecurityCritical] 
           unsafe public void CompileShapingProperties (
               bool                           forceDiacriticsToZeroWidth, 
               out int                        glyphCount, 
               out ushort[]                   glyphIndices,
               out GlyphShapingProperties[]   glyphProperties 
           )
           {
               Invariant.Assert(_charsCount < ushort.MaxValue, "CompileShapingProperties, too many characters");
               Invariant.Assert(_glyphInfoList.Length > 0,  "CompileShapingProperties, glyphsCount <= 0"); 

               ushort firstClusterGlyph = 0; 
               ushort firstClusterChar  = 0; 
               ushort afterClusterGlyph;
               ushort afterClusterChar; 
               ushort markFlags = (ushort)(forceDiacriticsToZeroWidth  ?
                 (GlyphFlags.Diacritic | GlyphFlags.ZeroWidth) : GlyphFlags.Diacritic);

               glyphCount = _glyphInfoList.Length ; 
               glyphIndices    = _glyphInfoList.Glyphs.GetCopy();   // create output copy of glyphs
               glyphProperties = new GlyphShapingProperties[glyphCount]; 
 

               // Go through all the characters and compile shaping properties. Mapping is local 
               // to cluster, so doing every cluster as a whole.
               for(int iChar = 1; iChar <= _charsCount; iChar++)
               {
                   if (iChar < _charsCount && _pClusters[iChar] == firstClusterGlyph) 
                   {
                       //We are still inside same cluster 
                       continue; 
                   }
 
                   // New cluster found. Get boundaries
                   afterClusterChar  = (ushort)iChar;
                   afterClusterGlyph = (iChar < _charsCount) ? _pClusters[iChar] : (ushort)glyphCount;
 
                   //Cluster map should come valid from shaping engine
                   Debug.Assert(firstClusterGlyph < afterClusterGlyph); 
 
                   int localMap = 0;
                   for(int iClusterChar = firstClusterChar; iClusterChar < afterClusterChar; iClusterChar++) 
                   {
                       // Clusters should be independent, otherwise they should be merged by shaping engine
                       Debug.Assert(_charMap[iClusterChar] >= firstClusterGlyph);
                       Debug.Assert(_charMap[iClusterChar] < afterClusterGlyph); 

                       if (_isSerializedClusterEntriesRequired && iClusterChar > firstClusterChar) 
                       { 
                            // Its possible that the clusters have mappings that will make line services
                            // uphappy.  An example is "Ra+halant+Ra+halant+Ra+halant+Ra+halant+Ra+halant" 
                            // The first "Ra+halant" will be a reph, repositioned to the end of the cluster.
                            // The font may have formed a glyph from the base
                            // "Ra" and the final "halant", so that the glyphs' first character values will be
                            // (relative to the start of the cluster) 0,1,3,6 and the ligature counts will 
                            // be 2,2,2,2.  The character map will be 0,1,1,3,3,0,4,4 (ie, the cluster's 1st
                            // and 6th character map to the 1st glyph). We'll discover that here if the 
                            // current char is mapped to an earlier glyph. 
                           int prevCharIx = iClusterChar - 1;
                           if (_charMap[iClusterChar] < _charMap[prevCharIx]) 
                           {
                                // this cluster has "interesting" mapping.  LS (Line Services)
                                // doesn't like interesting mapping so lets remap cluster so that
                                // all the entries in the map are sequential. 
                               ushort glyphIx = _charMap[iClusterChar];
                               _charMap[iClusterChar] = _charMap[prevCharIx]; 
                               while (prevCharIx > firstClusterChar && _charMap[prevCharIx] != glyphIx) 
                               {
                                    _charMap[prevCharIx] = _charMap[prevCharIx - 1]; 
                                    _pCharProps[prevCharIx].EngineReserved =
                                        (byte)(_charMap[prevCharIx] - firstClusterGlyph);

                                    --prevCharIx; 
                               }
 
                               ushort newGlyphIx = _charMap[iClusterChar]; 
                               while (++glyphIx <= newGlyphIx)
                               { 
                                   _glyphInfoList.FirstChars[glyphIx] += 1;
                               }

 
                           }
 
 
                       }
 
                       localMap = _charMap[iClusterChar] - firstClusterGlyph;

                       // Shaping porperties do not support more than 255 glyph/chars in single cluster.
                       // if cluster is longer than 255 glyphs, make everything beyond that map to glyph 255 
                       if (localMap > 255)
                       { 
                           localMap = 255; 
                       }
 
                       // Only set canGlyphAlone on space when it is 1:1 mapping with the glyph.
                       bool canGlyphAlone = (Classification.CharAttributeOf((int)Classification.GetUnicodeClassUTF16(_pChars[iClusterChar])).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0
                                          && afterClusterChar  - firstClusterChar == 1     // cluster is 1 char long
                                          && afterClusterGlyph - firstClusterGlyph == 1;   // cluster is 1 glyph long 

                       _pCharProps[iClusterChar].CanGlyphAlone = canGlyphAlone; 
                       _pCharProps[iClusterChar].EngineReserved= (byte)localMap; 
                   }
 
                   // make sure the start of the cluster is marked...
                   // set the cluster start flag for the last cluster
                   _glyphInfoList.GlyphFlags[firstClusterGlyph] |= (ushort)GlyphFlags.ClusterStart;
 
                   // go through all the glyphs of the cluster
                   for(int iClusterGlyph = firstClusterGlyph; iClusterGlyph < afterClusterGlyph; iClusterGlyph++) 
                   { 
                       ushort firstChar = _glyphInfoList.FirstChars[iClusterGlyph];
                       ushort ligaCount = _glyphInfoList.LigatureCounts[iClusterGlyph]; 
                       ushort glyphFlags = _glyphInfoList.GlyphFlags[iClusterGlyph];

                       // check for any adjustments that need to be made in the glyph
                       // flags 

                       // First, validate the glyph id 
                       if (glyphIndices[iClusterGlyph] > FontClient.GetMaxGlyphId) 
                       {
                            // invalid glyph index (too big to be valid), so just hide it. 
                            glyphFlags  = GlyphFlagsZeroWidth;
                            glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph;
                       }
 
                       // If the glyph's missing...
                       if ((glyphFlags & (ushort)GlyphFlags.Missing) != 0) 
                       { 
                           // for missing glyphs, check if we know something about it...
 
                           // (check if its a unicode control character)
                           if ((glyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0)
                           {
                               glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph; 
                               glyphFlags  = GlyphFlagsZeroWidth;
                           } 
                       } 
                        // if its a mark glyph ...
                       else if ( ((glyphFlags & (ushort)GlyphFlags.GlyphTypeMask) == 
                                            (ushort)GlyphFlags.Mark)  ||
                                   (iClusterGlyph != firstClusterGlyph &&
                                   (glyphFlags & (ushort)GlyphFlags.GlyphTypeMask) ==
                                            (ushort)GlyphFlags.Unresolved) 
                                 )
                       { 
                           // set our diacritic glyph flags. 
                           glyphFlags = (ushort)(glyphFlags | markFlags);
                       } 
                       // check if this is a unicode control char (ZWJ, etc) and we want to hide
                       // such...
                       else if ((glyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 &&
                                _forceControlCharsInvisible && _controlCharsSeen && 
                                FontClient.IsUnicodeControlGlyph(glyphIndices[iClusterGlyph]))
                       { 
                            glyphIndices[iClusterGlyph] = FontClient.SpaceGlyph; 
                            glyphFlags = GlyphFlagsZeroWidth;
                       } 

                       // Clusters should be independent, otherwise they should be merged by shaping engine
                       Debug.Assert(firstChar >= firstClusterChar);
                       Debug.Assert(firstChar < afterClusterChar); 

                       localMap = firstChar - firstClusterChar; 
 
                       // Shaping porperties do not support more than 255 glyph/chars in single cluster.
                       // if cluster is longer than 255 glyphs, make everything beyond that map to glyph 255 
                       if (localMap >= 255)
                       {
                           localMap = 255;
                       } 

                       if (ligaCount > 255) 
                       { 
                           ligaCount = 255;
                       } 

                       glyphProperties[iClusterGlyph] =
                            new GlyphShapingProperties(glyphFlags,
                                                       (ushort)((ligaCount << 8) | localMap) ); 
                   }
 
                   firstClusterChar  = afterClusterChar; 
                   firstClusterGlyph = afterClusterGlyph;
               } 
           }

          // the "Current???" accessors are used in the various engines shaping loops
 
          /// 
          /// CurrentChar - returns current char 
          ///  
          /// 
          /// Critical - The method reads into  an unvalidated unsafe array 
          /// 
          unsafe public char                        CurrentChar
          {
              [SecurityCritical] 
              get { return _pChars[_nextCharIx]; }
          } 
 
          /// 
          /// CurrentCharIx - returns current char index 
          /// 
          public ushort                             CurrentCharIx
          {
              get { return (ushort)_nextCharIx; } 
          }
 
 
          /// 
          /// CurrentGlyph - sets/gets current glyph 
          /// 
          public ushort                             CurrentGlyph
          {
              get { return _glyphInfoList.Glyphs[ _charMap[_nextCharIx] ]; } 
              set { _glyphInfoList.Glyphs[ _charMap[_nextCharIx] ] = value; }
          } 
 
          /// 
          /// CurrentShape - returns/sets current char shape info 
          /// 
          /// 
          /// Critical - The method reads into  an unvalidated unsafe array
          ///  
          unsafe public CharShapeInfo               CurrentShape
          { 
              [SecurityCritical] 
              get { return _pShapes[_nextCharIx]; }
              [SecurityCritical] 
              set { _pShapes[_nextCharIx] = value; }
          }

          public ShaperFontClient                   FontClient 
          {
              get { return _fontClient; } 
          } 

          ///  
          /// Critical - The method reads into  an unsafe array
          /// 
          [SecurityCritical]
          unsafe public char GetChar(ushort charIx) 
          {
            return (charIx < _charsCount) ? _pChars[charIx] : '\u0000'; 
          } 

          public ushort GetGlyph(ushort glyphIx) 
          {
             return _glyphInfoList.Glyphs[glyphIx];
          }
 
          public ushort GetGlyphIx(ushort charIx)
          { 
             return _charMap[charIx]; 
          }
 
         /// 
         /// Critical - The method reads into  an unsafe array
         /// 
         [SecurityCritical] 
         public bool GetNextCharProperties (out char nextChar, out ushort nextGlyph, out CharShapeInfo nextShape)
         { 
            ToNextChar(); 

            nextChar = CurrentChar; 
            nextGlyph = CharConverter.ToGlyph(nextChar);
            nextShape = CharConverter.ToShapeInfo(nextChar);

            return !_finishedShaping; 
         }
 
         ///  
         /// Critical - The method reads into  an unsafe array
         ///  
         [SecurityCritical]
         public bool GetNextChar(out char nextChar)
         {
            ToNextChar(); 

           nextChar = CurrentChar; 
           return !_finishedShaping; 
         }
 
         /// 
         /// Critical - The method reads into  an unsafe array
         /// 
         [SecurityCritical] 
         public bool GetNextShape(out CharShapeInfo nextShape)
         { 
            ToNextChar(); 

           nextShape = CharConverter.ToShapeInfo(CurrentChar); 
           return !_finishedShaping;
         }

             ///  
             /// Critical - The method reads into  an unsafe array
             ///  
             [SecurityCritical] 
             unsafe public CharShapeInfo GetShapeInfo(int charIx)
             { 
                 return (CharShapeInfo)((charIx >= 0 && charIx < _charsCount) ? _pShapes[charIx] : CharShapeInfo.NoFlagsSet);
             }

 

             ///  
             /// GlyphsCount - returns glyphs count 
             /// 
             public int                                 GlyphsCount 
             {
                get {   if (_nextGlyphIx == GlyphInfoList.Length && _addedGlyphsCount > 0)
                        {
                            // if we are at the end of the glyph list and there're deferred 
                            // glyph additions, add the deferred glyphs now.
                            _isAutoInsert = true; // inhibit updating "inserted" glyphs 
                            InsertGlyphs((ushort)GlyphInfoList.Length,(ushort)_addedGlyphsCount); 
                            _addedGlyphsCount = 0;
                        } 

                        return GlyphInfoList.Length;
                    }
 
             }
 
 
             public GlyphInfoList                      GlyphInfoList
             { 
                 get { return _glyphInfoList; }
             }

             public bool                               HasLeadingJoin 
             {
                 get { return _hasLeadingJoin; } 
             } 

             public bool                               HideControlChars 
             {
                 get { return _forceControlCharsInvisible && _controlCharsSeen; }
             }
 

             public bool                               IsFinished 
             { 
                 get { return _finishedShaping; }
             } 

             /// 
             /// InsertGlyphs - insert more glyphs into glyphinfolist
             ///  
             public int InsertGlyphs(ushort insertionPoint,
                                       ushort insertCount) 
             { 
                int insertedCount = 0;
                int glyphsCount = GlyphInfoList.Length; 

                 if ( insertionPoint < glyphsCount )
                 {
                     GlyphInfoList.Insert(insertionPoint, insertCount); 
                     if (GlyphInfoList.Length > glyphsCount)
                     { 
                        insertedCount = GlyphInfoList.Length - glyphsCount; 
                     }
 
                 }
                 else if ( insertionPoint == glyphsCount )
                 {
                     if (_inited) 
                         GlyphInfoList.Insert( 0, insertCount > CharsCount ? insertCount : CharsCount);
                     else 
                         GlyphInfoList.Insert(glyphsCount, insertCount); 

                     if (GlyphInfoList.Length > glyphsCount) 
                     {
                        insertedCount = GlyphInfoList.Length - glyphsCount;
                     }
 
                 }
 
                 // if we have inserted glyphs in front of the current glyph index, 
                 // increment the glyph index.  The assumption is made that the
                 // inserted glyph(s) should be mapped to the same character as the 
                 // first glyph that's being displaced (so we don't adjust the
                 // charmap entry that points to this glyph position)
                 if (!_inited && !_isAutoInsert && insertionPoint <= _nextGlyphIx && _nextGlyphIx <= glyphsCount)
                 { 
                    for (int i = 0; i <= _nextCharIx; ++i)
                    { 
                        if (_charMap[i] > insertionPoint) 
                        {
                           _charMap[i] += (ushort)insertedCount; 
                        }
                    }

                    // normally, "afterInsertionGlyphIx" will be the first glyph position 
                    // after the inserted members of GlyphInfoList.  There's one exception;
                    // when the insertion point is at glyphsCount (this implies that 
                    // _nextGlyphIx also is at glyphsCount) we are "inserting" glyphs 
                    // "in front of" the last glyph but the insertion code above actually
                    // added the elements to the end of the glyphs array. So, in this end 
                    // case, the inserted elements are set up from the last entry in the glyphs
                    // array (last before we added these glyphs, of course).
                    ushort afterInsertionGlyphIx = insertionPoint < glyphsCount ?
                        (ushort)(insertionPoint + insertedCount) : (ushort)(glyphsCount - 1); 
                    Debug.Assert(afterInsertionGlyphIx < glyphsCount + insertedCount,"improper use of InsertGlyphs");
 
                    for (int i = 0; i < insertedCount; ++i) 
                    {
                        GlyphInfoList.FirstChars[insertionPoint + i] = GlyphInfoList.FirstChars[afterInsertionGlyphIx]; 
                        GlyphInfoList.LigatureCounts[insertionPoint + i] = GlyphInfoList.LigatureCounts[afterInsertionGlyphIx];
                        GlyphInfoList.GlyphFlags[insertionPoint + i] = GlyphInfoList.GlyphFlags[afterInsertionGlyphIx];
                    }
 
                    _nextGlyphIx = (ushort)(_nextGlyphIx + insertedCount);
                 } 
 
                 _isAutoInsert = false;     // always reset this
                 return insertedCount; 
             }

            public bool MoveGlyphs (ushort destGlyphIx, ushort srcGlyphIx, ushort moveCount             )
            { 
                ushort glyphsCount = (ushort)_glyphInfoList.Length;
 
                if (srcGlyphIx + moveCount <= srcGlyphIx ||     // make sure no overflow 
                    destGlyphIx + moveCount <= destGlyphIx ||   // make sure no overflow
                    (srcGlyphIx + moveCount - 1) >= glyphsCount ||    // and make sure valid move arguments 
                    (destGlyphIx + moveCount - 1) >= glyphsCount)     // and make sure valid move arguments
                {
                    return false;
                } 

                if (srcGlyphIx < destGlyphIx && srcGlyphIx + moveCount > destGlyphIx) 
                { 
                    // buffers overlap, copy from end of src buffer
                    // src:     ++++++++++++++++++++++++++++ 
                    // dest:         ++++++++++++++++++++++++++++
                    srcGlyphIx += moveCount;
                    destGlyphIx += moveCount;
                    while (moveCount-- > 0) 
                    {
                        _glyphInfoList.Glyphs[--destGlyphIx] = _glyphInfoList.Glyphs[--srcGlyphIx]; 
                    } 
                }
                else if (srcGlyphIx != destGlyphIx) 
                {
                    while (moveCount-- > 0)
                    {
                        _glyphInfoList.Glyphs[destGlyphIx++] = _glyphInfoList.Glyphs[srcGlyphIx++]; 
                    }
                } 
 
                return true;
            } 

             /// 
             /// NextChar - returns next char
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array 
             ///  
             unsafe public char                        NextChar
             { 
                 [SecurityCritical]
                 get { return
                         (_nextCharIx + 1 < _charsCount ) ?
                               _pChars[_nextCharIx + 1] : (char)0; } 
             }
 
             ///  
             /// NextGlyphIx - returns/sets next glyphIx
             ///  
             public ushort                                 NextGlyphIx
             {
                 get { return _nextGlyphIx; }
             } 

             ///  
             /// ShapingWorkspace.PopulateClusterMap - helper function for GetGlyphs. 
             /// 
             ///  
             ///     This function creates the cluster map based on shape flags.  The
             ///     shape engine will have set the IsStartOfCluster flag for all
             ///     characters that start a cluster. (CAUTION:  the cluster array
             ///     and the shape flag array are actually the same memory block 
             ///     so don't try to use a given character's shape info after
             ///     setting its cluster info. ) 
             ///  
             /// 
             /// Critical - uses pointers, unsafe code 
             /// 
             [SecurityCritical]
             unsafe public void PopulateClusterMap ()
             { 

                if (!FontClient.IsFeatureTypeSupportedByFont) return;   // nothing to do (SetCurrentClusterInfo already set the map up) 
 
                  ushort *clusterMap = _pClusters;
 
                  Invariant.Assert(_glyphInfoList.Length > 0,  "PopulateClusterMap, glyphsCount <= 0");

                  Reset(0,0,_charsCount);
 

                  // Step 1. Create the cluster map based on the shape flags... 
 

                  // this loop goes through all the shapes (one per Unicode character) and 
                  // creates the cluster map.  When each start of cluster is found the
                  // associated glyph is assumed to be the value for this new cluster unless
                  // there's reason to suspect its not.
                  int firstGlyphInCluster   =  0; 
                  int  firstCharInCluster = 0;
                  int  earliestGlyphRef = 0; 
                  int  earliestCharRef = 0; 
                  int  currentCharIx;
                  int  currentGlyphIx; 
                  int  currentGlyphFirstChar;

                  // add the glyphs to the glyph array
                  while (ToNextChar()) 
                  {
                      currentCharIx = _nextCharIx; 
                      currentGlyphIx = _charMap[_nextCharIx]; 
                      Invariant.Assert(currentGlyphIx < _glyphInfoList.Length, "illegal glyph ix in charMap");
 

                      // It is possible that this current character is part of a ligature glyph that actually spans
                      // multiple clusters (including a previous cluster, so check the glyph's FirstChar
                      // clustermap entry (it might be even earlier than currentGlyphIx) 
                      currentGlyphFirstChar = (int)_glyphInfoList.FirstChars[currentGlyphIx];
                      if (currentGlyphFirstChar < firstCharInCluster) 
                      { 
                          // Since currentGlyphFirstChar < firstCharInCluster, clusterMap[currentGlyphFirstChar]
                          // is already filled with its glyph id so we can use it and check if the glyph it 
                          // references is earlier than what we currently know about.
                          if (clusterMap[currentGlyphFirstChar] < earliestGlyphRef)
                          {
                              earliestGlyphRef = clusterMap[currentGlyphFirstChar]; 
                          }
 
                          if (currentGlyphFirstChar < earliestCharRef) 
                          {
                              earliestCharRef = currentGlyphFirstChar; 
                          }
                      }

 
                      // As each character is processed, we'll keep track of the earliest glyph referenced
                      // in the glyphs that are part of the current cluster.  This information will be used 
                      // when the next start of cluster is detected. 
                      if (currentGlyphIx < earliestGlyphRef)
                      { 
                          earliestGlyphRef = currentGlyphIx;    // save this earlier glyph reference
                      }

 
                     if ((CurrentShape & (CharShapeInfo.IsStartOfCluster)) != 0)
                     { 
 
                         // starting a new cluster...
 
                        if (currentGlyphIx == earliestGlyphRef)
                         {
                             // we will normally be here for the first glyph, but otherwise
                             // this seems an unlikely case; if here then this is not actually 
                             // the end of one cluster and the beginning of another, but rather
                             // a concatenation of two clusters. 
                         } 
                         else
                         { 
                             // this glyph starts a new cluster so go back over the glyphs in the preceding
                             // cluster to verify that all is well.  It may be that we have discovered new
                             // information (ie, membership in cluster includes earlier glyphs or characters)
                             // since the first char in the last cluster. 
                             if (earliestGlyphRef < firstGlyphInCluster || earliestCharRef < firstCharInCluster)
                             { 
                                 // we need to change the last cluster's extent and/or its value! 
                                 firstGlyphInCluster = earliestGlyphRef;
                                 firstCharInCluster = earliestCharRef; 
                                 for (int i = firstCharInCluster; i < currentCharIx; ++i)
                                 {
                                     clusterMap[i] = (ushort)firstGlyphInCluster;
                                 } 

                             } 
 

                             // As long as this char (the first in a new cluster) is after the current cluster's 
                             // first char, set up the counters for this new cluster.  Otherwise, since this
                             // character is before the current cluster's first character (must have been
                             // updated in the if block just above) don't change the current cluster.
                             if (firstCharInCluster < currentCharIx) 
                             {
 
                                 // keep track of the first char in cluster 
                                 firstCharInCluster = currentCharIx;
                                 firstGlyphInCluster = currentGlyphIx; 

                                 if (currentGlyphFirstChar < currentCharIx)
                                 {
                                    earliestCharRef = currentGlyphFirstChar; 
                                    earliestGlyphRef = clusterMap[earliestCharRef];
                                 } 
                                 else 
                                 {
                                    earliestCharRef = currentCharIx; 
                                    earliestGlyphRef = currentGlyphIx;
                                 }
                             }
                         } 

                     } 
 

                     clusterMap[currentCharIx] = (ushort)firstGlyphInCluster;        // save this char's cluster info 
                  }


                  // If the last character is the last character in the last cluster (ie, if 
                  // it doesn't have the StartOfCluster flag ), then need to check
                  // update the cluster info.  Check "earliestCharRef" to determine this; normally, 
                  // if the last character has its StartOfCluster flag set, "earliestCharRef" will 
                  // be the index of the last character.
                  if (earliestCharRef + 1 < CharsCount) 
                  {
                     // check if final cluster adjustment is needed
                      if (earliestGlyphRef < firstGlyphInCluster || earliestCharRef < firstCharInCluster)
                      { 
                          // we need to change the last cluster's extent and/or its value!
                          for (int i = earliestCharRef; i < CharsCount; ++i) 
                          { 
                              clusterMap[i] = (ushort)(earliestGlyphRef);
                          } 

                      }
                  }
 
                  Invariant.Assert( clusterMap[0] == 0, "first cluster map entry is not zero");
 
             } 
             /// 
             /// PreviousChar - returns previous char 
             /// 
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array
             ///  
             unsafe public char                        PreviousChar
             { 
                 [SecurityCritical] 
                 get { return _pChars[ PreviousCharIx ]; }
             } 

             /// 
             /// PreviousCharIx - returns previous char index
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array 
             ///  
             unsafe public ushort                     PreviousCharIx
             { 
                 get {
                        return (_inited ? _nextCharIx : (_nextCharIx == 0 ? (ushort) 0 :
                                ( _nextCharIx >= _charsCount ? (ushort)(_charsCount- 1) : (ushort)(_nextCharIx - 1))));
                     } 
             }
 
             ///  
             /// PreviousGlyph - sets/gets previous glyph
             ///  
             public ushort                             PreviousGlyph
             {
                 get {  return _inited ? (ushort) 0 : _glyphInfoList.Glyphs[ PreviousGlyphIx ]; }
                 set {  _glyphInfoList.Glyphs[ PreviousGlyphIx ] = value; } 
             }
 
 
             /// 
             /// PreviousGlyphIx - gets previous glyph index 
             /// 
             public ushort                            PreviousGlyphIx
             {
                 get { return   _inited ? (ushort) _nextGlyphIx : _charMap[ PreviousCharIx ]; } 
             }
 
             ///  
             /// PreviousShape - gets previous char shape
             ///  
             /// 
             /// Critical - The method reads into  an unvalidated unsafe array
             /// 
             unsafe public CharShapeInfo               PreviousShape 
             {
                 [SecurityCritical] 
                 get { return PreviousCharIx == CurrentCharIx ? CharShapeInfo.NoFlagsSet : _pShapes[ PreviousCharIx ]; } 
             }
 
             /// 
             /// ForceSerializedCluster -
             /// 
             public bool                            IsForceSerializedClusterOn 
             {
                 set { _isSerializedClusterEntriesRequired = value; } 
             } 

 
             /// 
             /// ShapingWorkspace.Reset - used to re-initial the MoveToNextChar mechanism
             ///        (our iterator function, if you please!).  This flavor of the
             ///        reset function just resets the iteration booleans without moving 
             ///        the next character index
             ///  
             public bool Reset(  ) 
             {
                 _inited = true; 
                 _finishedShaping = (_nextCharIx > _lastCharIx);

                 return !_finishedShaping;
             } 

             ///  
             /// ShapingWorkspace.Reset - used to re-initial the MoveToNextChar mechanism 
             ///        (our iterator function, if you please!).
             ///  
             public bool Reset(  ushort nextCharIx,
                                   ushort nextGlyphIx,
                                   ushort charCount )
             { 
                 _nextCharIx = nextCharIx;
                 _nextGlyphIx = nextGlyphIx; 
                 _inited = true; 
                 _finishedShaping = false;
 
                 _lastCharIx = (ushort)(nextCharIx + charCount - 1);
                if (_lastCharIx >= _charsCount)
                {
                    _lastCharIx = (ushort)(_charsCount - 1); 
                }
 
                 // we allow nextGlyphIx == GlyphsCount because of the case where 
                 // we're adding glyphs syllable by syllable (so we will allocate
                 // the next syllable's glyphs later) 
                 Invariant.Assert(_nextCharIx < _charsCount);
                 Invariant.Assert(_nextGlyphIx <= GlyphsCount);

                 return !_finishedShaping; 
             }
 
 
            /// 
            /// SetGlyphPropertiesUsingShapeInfo - This is the default call to set up the 
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character.
            /// 
            ///  
            /// Critical - The method reads/write unsafe pointers
            ///  
            [SecurityCritical] 
            unsafe public void SetGlyphPropertiesUsingShapeInfo ( CharShapeInfo currShape )
            { 
                char currChar = _pChars[_nextCharIx];
                ushort glyph = CharConverter.ToGlyph(currChar);

                _pShapes[_nextCharIx] = currShape; 
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 
            } 

            ///  
            /// SetGlyphPropertiesUsingChar - This sets up the
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character using the passed in character.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetGlyphPropertiesUsingChar ( CharShapeInfo currShape, char currChar) 
            {
                ushort glyph = CharConverter.ToGlyph(currChar);

                _pShapes[_nextCharIx] = currShape; 
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 
            } 

            ///  
            /// SetGlyphPropertiesUsingGlyph - This sets up the
            ///     glyphInfoList, charmap, and cluster (if script not supported)
            ///     for the current character using the passed in glyph.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetGlyphPropertiesUsingGlyph ( CharShapeInfo currShape, ushort glyph ) 
            {
                _pShapes[_nextCharIx] = currShape;
                _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                SetGlyphProperties( glyph ); 

            } 
 
            /// 
            /// SetGlyphProperties - This sets up the glyphInfoList 
            /// for the current glyph position and it increments
            ///  _nextGlyphIx.  If the script is not supported by this
            /// font (ie, the font has no OT tables for this script),
            /// then the cluster map is updated, too. If the font does have 
            /// support for script, then shaping info is valid in _pShapes;
            /// so if this character's shape indicates that we desire 
            /// a dotted circle glyph inserted then this is done. 
            /// 
            ///  
            /// Critical - The method reads/write unsafe pointers
            /// 
            [SecurityCritical]
            unsafe public void SetGlyphProperties ( ushort glyph ) 
            {
                // Be aware of the side effect of GlyphsCount; it is necessary 
                // that the comparison below be done if there're added glyphs 
                // to be considered.
                Invariant.Assert(_nextGlyphIx < GlyphsCount, "SetGlyphProperties called with invalid glyphIx"); 

                // fill this character's glyph info list entries
                _glyphInfoList.Glyphs[_nextGlyphIx] = glyph;
                _glyphInfoList.FirstChars[_nextGlyphIx] = (ushort)_nextCharIx; 
                _glyphInfoList.LigatureCounts[_nextGlyphIx] = 1;
                _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsNone; 
                if (glyph == 0) 
                {
                     _glyphInfoList.GlyphFlags[_nextGlyphIx] |= (ushort)GlyphFlags.Missing; 
                }

                // check the shape flags and take appropriate action
                CharShapeInfo currentShape = _pShapes[_nextCharIx]; 

                // if this shape indicates that here is an inserted base insertion 
                // point, insert the dotted circle. 
                if ((currentShape & CharShapeInfo.RequiresInsertedBase) == CharShapeInfo.RequiresInsertedBase)
                { 
                    ushort dottedCircleGlyph = FontClient.DottedCircleGlyph;
                    if (dottedCircleGlyph != 0)
                    {
                        InsertGlyphs(_nextGlyphIx,1);   // this will increment _nextGlyphIx 
                        Invariant.Assert(_nextGlyphIx < GlyphsCount,
                                         "Invalid glyph ix for insertion of invalid base"); 
 
                        _glyphInfoList.Glyphs[_nextGlyphIx - 1] = dottedCircleGlyph;
                        _glyphInfoList.GlyphFlags[_nextGlyphIx - 1] = (ushort)GlyphFlags.InvalidBase; 
                    }

                }
                else if( (currentShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) 
                {
 
                    // This is a Unicode control glyph.  Let font client know 
                    // so it can save glyph id if it wants to (may be used to
                    // suppress visible Unicode control characters later) 
                    FontClient.SetUnicodeControlGlyph(CurrentChar, glyph);

                    _controlCharsSeen = true;
                    _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsZeroWidth; 
                }
 
                // If font doesn't have feature support, just set up the 
                // cluster info directly
                if ( !FontClient.IsFeatureTypeSupportedByFont ) 
                {
                    SetCurrentClusterInfo(currentShape, glyph);
                }
 
                // set next glyph (allow to go one beyond the last to detect the last glyph
                // being written 
                if ((ushort)( _nextGlyphIx + 1) <= GlyphsCount) 
                {
                    _nextGlyphIx = (ushort)( _nextGlyphIx + 1); 
                }
            }

            ///  
            /// SetCurrentClusterInfo - This sets up the glyphInfoList
            /// for the current glyph position and it increments 
            ///  _nextGlyphIx.  If the script is not supported by this 
            /// font (ie, the font has no OT tables for this script),
            /// then the cluster map is updated, too. If the font does have 
            /// support for script, then shaping info is valid in _pShapes;
            /// so if this character's shape indicates that we desire
            /// a dotted circle glyph inserted then this is done.
            ///  
            /// 
            /// Critical - The method reads/write unsafe pointers 
            ///  
            [SecurityCritical]
            unsafe public void SetCurrentClusterInfo ( CharShapeInfo currentShape, ushort glyph ) 
            {
                bool startOfCluster = (currentShape & CharShapeInfo.IsStartOfCluster) != 0;

                // font doesn't have feature support, so just set up the 
                // cluster info directly
                if( (currentShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) 
                { 
                    // For fonts that don't have feature support for this
                    // script -  if the user doesn't want to actually see 
                    // the control characters, replace them with a blank glyph.
                    // (For fonts with support, we do this later after feature
                    // application)
                    if (_forceControlCharsInvisible) 
                    {
                        _glyphInfoList.Glyphs[_nextGlyphIx] = FontClient.SpaceGlyph; 
                    } 
                }
                else if (startOfCluster) 
                {
                    if (glyph == 0)
                    {
                        _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsBase | (ushort)GlyphFlags.Missing; 
                    }
                    else 
                    { 
                        _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsBase;
                    } 
                }
                else
                {
                    _glyphInfoList.GlyphFlags[_nextGlyphIx] = GlyphFlagsDiacritic; 
                }
 
                _pClusters[_nextCharIx] = 
                    ( _nextCharIx == 0 || startOfCluster ?
                    _nextGlyphIx : _pClusters[PreviousCharIx]); 

                _charMap[_nextCharIx] = _nextGlyphIx;   // set cluster map value
            }
 
            /// 
            /// SetGlyph - 
            ///  
            public void SetGlyph (ushort glyphIx, ushort glyph)
            { 
                _glyphInfoList.Glyphs[glyphIx] = glyph;
            }

            ///  
            /// SetGlyph -
            ///  
            public void SetGlyph (ushort glyphIx, ushort glyph, ushort firstChar) 
            {
                _glyphInfoList.Glyphs[glyphIx] = glyph; 
                _glyphInfoList.FirstChars[glyphIx] = firstChar;
            }

             ///  
             /// Critical - The method reads into  an unsafe array
             ///  
             [SecurityCritical] 
             unsafe public bool SetNextGlyphProperties (out CharShapeInfo nextShape)
             { 
                if (ToNextChar())
                {
                    char nextChar = CurrentChar;
 
                    nextShape = CharConverter.ToShapeInfo(nextChar);
                    _pShapes[_nextCharIx] = nextShape; 
 
                    _charMap[_nextCharIx] = _nextGlyphIx;  // set charmap
                    SetGlyphProperties( CharConverter.ToGlyph(nextChar) ); 
                }
                else
                {
                    nextShape = CharShapeInfo.NoFlagsSet; 
                }
 
                return !_finishedShaping; 
             }
 
             /// 
             /// Critical - The method reads into  an unsafe array
             /// 
             [SecurityCritical] 
             unsafe public void SetShapeInfo(ushort charIx, CharShapeInfo charShape)
             { 
                 if (charIx >= 0 && charIx < _charsCount) 
                 {
                    _pShapes[charIx] = charShape; 
                 }
             }

            ///  
            /// ToNextChar - increments index, returns false if finished
            ///  
            public bool ToNextChar() 
            {
              if (_inited) 
              {
                // if this is the first character, don't increment the
                // index (so we can use this in a while (MoveToNextChar){...}
                // loop 
                _inited = false;
 
              } 
              else if (_nextCharIx < _lastCharIx)
              { 
                ++_nextCharIx;
              }
              else
              { 
                _finishedShaping = true;
                Invariant.Assert(_nextCharIx < _charsCount); 
              } 

              return !_finishedShaping; 
            }

            /// 
            /// Critical - The method reads into  an unsafe array 
            /// 
            [SecurityCritical] 
            public void UpdateCurrentGlyphProperties (CharShapeInfo newShape) 
            {
                if ((CurrentShape & CharShapeInfo.RequiresInsertedBase) 
                                        == CharShapeInfo.RequiresInsertedBase &&
                    (newShape & CharShapeInfo.RequiresInsertedBase)
                                        != CharShapeInfo.RequiresInsertedBase )
                { 
                    AddGlyphs(-1);
                } 
 
                _nextGlyphIx = _charMap[_nextCharIx];  // set glyph ix back
                SetGlyphPropertiesUsingGlyph( newShape, CurrentGlyph ); 
            }

            /// 
            /// Critical - The method reads into  an unsafe array 
            /// 
            [SecurityCritical] 
            public void ValidateGlyphsOut (ushort[] glyphs) 
            {
                bool areAllGlyphsZero = true; 

                for (int i = 0; i < glyphs.Length; ++i)
                {
                    if (glyphs[i] != 0) areAllGlyphsZero = false; 
                }
 
                Debug.Assert(areAllGlyphsZero,"ValidateGlyphsOut found an all zero'ed glyphs"); 
            }
 

            private int                         _addedGlyphsCount;
            private ushort                      _charsCount;   // number of chars in run.
            private IScriptCharConverter        _charConverter; 
            private bool                        _controlCharsSeen;
            private bool                        _finishedShaping; 
            private ShaperFontClient            _fontClient; 
            private bool                        _forceControlCharsInvisible;
            private bool                        _forceInhibitLigature; 

            private bool                        _inited;
            private bool                        _isAutoInsert;
            private bool                        _hasLeadingJoin; 
            private bool                        _isSerializedClusterEntriesRequired;
 
            private ushort                      _nextCharIx; 
            private ushort                      _nextGlyphIx;
 

            /// 
            ///    Critical: Holds reference to an unsafe pointer
            ///  
            [SecurityCritical]
            private unsafe char*                _pChars;  // the Unicode text buffer 
            [SecurityCritical] 
            private unsafe CharacterShapingProperties* _pCharProps; // char properties buffer
            [SecurityCritical] 
            private unsafe ushort*              _pClusters; // clusterMap buffer
            [SecurityCritical]
            private unsafe CharShapeInfo*       _pShapes; // char shapes buffer
 
            private UshortList                  _charMap;
            private GlyphInfoList               _glyphInfoList; 
            private ushort                      _lastCharIx; 

 
        }

}
 

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