PlacementWorkspace.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 / PlacementWorkspace.cs / 1 / PlacementWorkspace.cs

                            //---------------------------------------------------------------------- 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2005
// 
//  File:      PlacementWorkspace.cs
// 
//  Contents:  support for all the shaping engines - all the local variable 
//             for IShaper.GetGlyphPlacements and helpers are wrapped and
//             all unsafe pointer manipulation is done in this class. 
//
//  Created:   08-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
{
 

        ///  
        ///     PlacementWorkspace  provides safe interactions with the various buffers 
        ///     used by GetGlyphPlacement.
        ///  
        /// 
        ///     This struct is created every time a shaping engine's
        ///     GetGlyphPlacement() 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.GetGlyphPlacement 
        ///     are done through this struct's accessors and methods. 
        /// 
        internal struct PlacementWorkspace 
        {

            /// 
            /// PlacementWorkspace - initializer for GetGlyphPlacements currentRun 
            /// 
            ///  
            ///     This function is always called from IShaper.GetGlyphPlacements. 
            /// 
            ///  
            ///     Critical: This code accepts checked pointers and extracts
            ///         unsafe pointers.
            /// 
             [SecurityCritical] 
             unsafe public PlacementWorkspace (
                ShapingOptions                              shapingFlags, 
 
                ShaperFontClient                            shaperFontClient,
                ShaperBuffers                               shaperBuffers, 

                CheckedCharacterShapingPropertiesPointer    charProperties,
                CheckedUShortPointer                        charClusterMap,
                int                                         charCount, 

                CheckedUShortPointer                        glyphIndices, 
                CheckedGlyphShapingPropertiesPointer        glyphProperties, 
                int                                         glyphCount,
                CheckedIntPointer                           glyphAdvances, 
                CheckedGlyphOffsetPointer                   glyphOffsets,
                bool                                        fontHasScriptGposFeatures,
                TextFlowDirection                           textFlowDirection)
            { 

                Invariant.Assert(charCount > 0,"PlacementWorkspace: invalid char count"); 
 
                // initialize our shaper buffers and set up our local references
                shaperBuffers.Initialize( (ushort)charCount, (ushort) glyphCount ); 
                _charMap = shaperBuffers.CharMap;
                _glyphInfoList = shaperBuffers.GlyphInfoList;

                // keep track of our font client 
                _fontClient = shaperFontClient;
 
                 // positioning-specific members 
                _pGlyphAdvances = glyphAdvances.Probe(0, glyphCount);
                _pGlyphOffsets = glyphOffsets.Probe(0, glyphCount); 


                // initialize our various counts
                _nextGlyphIx = 0; 
                _glyphCount = (ushort)glyphCount;
 
                // initialize our local booleans 
                _inited = true;
                _finished = false; 

                _fontHasScriptGposFeatures = fontHasScriptGposFeatures;
                _textFlowIsRTL = (textFlowDirection == TextFlowDirection.RTL);
 
                // unload the properties to our local representation
                DecompileShapingProperties( charProperties, 
                                            charClusterMap, 
                                            charCount,
 
                                            glyphIndices,
                                            glyphProperties,
                                            glyphCount );
 
             }
 
           public UshortList                        CharMap 
           {
               get { return _charMap; } 
           }

            /// 
            /// CurrentGlyph - sets/gets current glyph 
            /// 
            public ushort                             CurrentGlyph 
            { 
                get { return _glyphInfoList.Glyphs[ _nextGlyphIx ]; }
                set { _glyphInfoList.Glyphs[ _nextGlyphIx ] = value; } 
            }

            /// 
            /// CurrentGlyphAdvance - sets/gets current glyph advance 
            /// 
            ///  
            /// Critical - The method reads into  an unvalidated unsafe array 
            /// 
            unsafe public int                       CurrentGlyphAdvance 
            {
                [SecurityCritical]
                get { return _pGlyphAdvances[ _nextGlyphIx ]; }
                [SecurityCritical] 
                set { _pGlyphAdvances [ _nextGlyphIx ] = value; }
            } 
 
            /// 
            /// CurrentGlyphFlags - sets/gets current glyph flags 
            /// 
            public ushort                             CurrentGlyphFlags
            {
                get { return _glyphInfoList.GlyphFlags[ _nextGlyphIx ]; } 
            }
 
            ///  
            /// CurrentGlyphIx - returns current glyphIx
            ///  
            public ushort                             CurrentGlyphIx
            {
                get { return _nextGlyphIx; }
            } 

            ///  
            /// CurrentGlyphOffsetDu - sets/gets current glyph offset.du 
            /// 
            ///  
            /// Critical - The method reads into  an unvalidated unsafe array
            /// 
            unsafe public int                       CurrentGlyphOffsetDu
            { 
                [SecurityCritical]
                get { return _pGlyphOffsets[ _nextGlyphIx ].du; } 
                [SecurityCritical] 
                set { _pGlyphOffsets [ _nextGlyphIx ].du = value; }
            } 

            /// 
            /// CurrentGlyphOffsetDv - sets/gets current glyph offset.du
            ///  
            /// 
            /// Critical - The method reads into  an unvalidated unsafe array 
            ///  
            unsafe public int                       CurrentGlyphOffsetDv
            { 
                [SecurityCritical]
                get { return _pGlyphOffsets[ _nextGlyphIx ].dv; }
                [SecurityCritical]
                set { _pGlyphOffsets [ _nextGlyphIx ].dv = value; } 
            }
 
 
             /// 
             ///     Critical: This code is unsafe 
             /// 
             [SecurityCritical]
             unsafe private void DecompileShapingProperties (
                CheckedCharacterShapingPropertiesPointer    charProperties, 
                CheckedUShortPointer                        charClusterMap,
                int                                         charCount, 
 
                CheckedUShortPointer                        glyphIndices,
                CheckedGlyphShapingPropertiesPointer        glyphProperties, 
                int                                         glyphCount )
             {
                 Debug.Assert(charCount < ushort.MaxValue);
                 Debug.Assert(glyphCount < ushort.MaxValue); 

 
                 ushort*                     pClusterMap = charClusterMap.Probe(0, charCount); 
                 CharacterShapingProperties* pCharProps  = charProperties.Probe(0, charCount);
                 ushort*                     pGlyphs     = glyphIndices.Probe(0, glyphCount); 
                 GlyphShapingProperties*     pGlyphProps = glyphProperties.Probe(0, glyphCount);

                 ushort firstClusterGlyph = 0;
                 ushort firstClusterChar  = 0; 
                 ushort afterClusterGlyph;
                 ushort afterClusterChar; 
 
                 // Fill glyphs array
                 for(int i= 0; i < _glyphInfoList.Length; i++) 
                 {
                     _glyphInfoList.Glyphs[i] = pGlyphs[i];
                 }
 
                 // Compile shaping properties. Mapping is local to cluster, so doing every cluster as a whole
                 for(int iChar = 1; iChar <= charCount; iChar++) 
                 { 
                     if (iChar < charCount && pClusterMap[iChar] == firstClusterGlyph)
                     { 
                         //We are still inside same cluster
                         continue;
                     }
 
                     // New cluster found. Get boundaries
                     afterClusterChar  = (ushort)iChar; 
                     afterClusterGlyph = (iChar < charCount) ? pClusterMap[iChar] : (ushort)glyphCount; 

                     //Cluster map should come valid from shaping engine 
                     Debug.Assert(firstClusterGlyph < afterClusterGlyph);

                     for(int iClusterChar = firstClusterChar; iClusterChar < afterClusterChar; iClusterChar++)
                     { 
                         byte localMap = pCharProps[iClusterChar].EngineReserved;
 
                         // Clusters should be independent, otherwise they should be merged by shaping engine 
//                         Debug.Assert(localMap < (afterClusterGlyph - firstClusterGlyph));
 
                         CharMap[iClusterChar] = (ushort)(firstClusterGlyph + localMap);
                     }

                     for(int iClusterGlyph = firstClusterGlyph; iClusterGlyph < afterClusterGlyph; iClusterGlyph++) 
                     {
                         ushort mappingStorage = pGlyphProps[iClusterGlyph].EngineReserved; 
                         int firstChar = mappingStorage & 0xFF; 
                         int ligaCount = mappingStorage >> 8;
 
                         // Clusters should be independent, otherwise they should be merged by shaping engine
//                         Debug.Assert(firstChar < (afterClusterChar - firstClusterChar));

                         _glyphInfoList.Glyphs[iClusterGlyph]     = pGlyphs[iClusterGlyph]; 
                         _glyphInfoList.GlyphFlags[iClusterGlyph] = pGlyphProps[iClusterGlyph].GlyphFlags;
                         _glyphInfoList.FirstChars[iClusterGlyph] = (ushort)(firstClusterChar + firstChar); 
                         _glyphInfoList.LigatureCounts[iClusterGlyph] = (ushort)ligaCount; 
                     }
 
                     firstClusterChar  = afterClusterChar;
                     firstClusterGlyph = afterClusterGlyph;
                 }
             } 

 
              public ShaperFontClient                   FontClient 
              {
                  get { return _fontClient; } 
              }


 
         /// 
         /// GlyphAdvances - returns glyph advance pointer 
         ///  
         /// 
         /// Critical - The method reads into  an unvalidated unsafe array 
         /// 
         [SecurityCritical]
         unsafe public int *                       GlyphAdvances
         { 
            [SecurityCritical]
            get { return _pGlyphAdvances; } 
         } 

 
         public GlyphInfoList                      GlyphInfoList
         {
             get { return _glyphInfoList; }
         } 

         ///  
         /// GlyphOffsets - returns glyph offsets pointer 
         /// 
         ///  
         /// Critical - The method reads into  an unvalidated unsafe array
         /// 
         unsafe public GlyphOffset *               GlyphOffsets
         { 
            [SecurityCritical]
            get { return _pGlyphOffsets; } 
         } 

 
              /// 
             /// PlacementWorkspace.InitializeGlyphInfoWidths - helper function for GetGlyphsPlacement.
             /// 
             ///  
             ///     This function populates the glyph run's advance and offset values
             ///     with each glyph's default value (offsets always start zero'ed and 
             ///     the advance value comes from the font). 
             ///     Shapers that are using GPOS features in the font will call this method
             ///     with scalingFactor set to zero which is interpretted as meaning, 
             ///     "no scaling now" (ie, font supports this script, so we're going to let
             ///     the font set the advance).  Such shaping engines will apply scaling after
             ///     the after all the features have been applied by calling ScaleGlyphInfoWidths().
             ///     If a shaping engine has no GPOS features, then the caller (ie, 
             ///     GetGlyphsPlacement()) can pass in the appropriate scaling factor.
             ///  
             ///  
             ///     Critical: This code accesses critical methods.
             ///  
              [SecurityCritical]
             public void InitializeGlyphInfoWidths ()
             {
                 Invariant.Assert (_glyphCount == _glyphInfoList.Length); 

                 GlyphTypeface fontFace = FontClient.FontFace; 
 
                 // Init the advance width for all the glyphs.
                 while ( ToNextGlyph() ) 
                 {
                    int glyphAdvance = 0; // All diacritics get a zero'ed advance width

                    // All non-diacritics get advance width from the font 
                    if ((CurrentGlyphFlags & (ushort)GlyphFlags.ZeroWidth) == 0)
                    { 
                        glyphAdvance = (int)Math.Round(fontFace.GetAdvanceWidthInDesignUnits(CurrentGlyph)); 
                    }
 
                    // set the initial start values
                    CurrentGlyphAdvance = glyphAdvance;
                    CurrentGlyphOffsetDu = 0;
                    CurrentGlyphOffsetDv = 0; 
                 }
 
            } 

            ///  
            /// ToNextGlyph - increments index, returns false if finished
            /// 
            public bool ToNextGlyph()
            { 
              if (_inited)
              { 
                // if this is the first character, don't increment the 
                // index (so we can use this in a while (ToNextGlyph){...}
                // loop 
                _inited = false;
              }
              else if (_nextGlyphIx + 1 < _glyphCount)
              { 
                  ++_nextGlyphIx;
              } 
              else 
              {
                _finished = true; 
              }

              return !_finished;
            } 

 
            ///  
            /// PlacementWorkspace.Reset - used to re-initial the ToNextGlyph mechanism
            ///        (our iterator function, if you please!) 
            /// 
            public void Reset(  )
            {
               _nextGlyphIx = 0; 

               _inited = true; 
               _finished = false; 
            }
 
            /// 
            /// PlacementWorkspace.ScaleGlyphInfoWidths - helper function for GetGlyphsPlacement.
            /// 
            ///  
            ///     This function scales the glyph run's advance and offset values.
            ///     Shapers that are using GPOS features in the font will call this method 
            ///     after applying the font's GPOS feaures. 
            /// 
            ///  
            ///     Critical: This code accesses critical methods.
            /// 
            [SecurityCritical]
            public void ScaleGlyphInfoWidths( double scalingFactor ) 
            {
                // Some fonts have assigned an advance value for the dicritic glyphs. 
                // We have to zero the advance width on any diacritic, and add the value 
                // to the du width.
                int cumulativeAdvance = 0; 

                // go through all the glyphs and adjust any diacritics so that their advance
                // widths are zero'ed and the advance width is included in the offset du value.
                Reset(); 
                while ( ToNextGlyph() )
                { 
                    ushort currentGlyphFlags = CurrentGlyphFlags; 
                    int currentAdvanceWidth = CurrentGlyphAdvance;
                    int currentOffsetDu = CurrentGlyphOffsetDu; 


                    // This is used for Arabic/Hebrew fonts that don't have GPOS support...
                    if ( !_fontHasScriptGposFeatures ) 
                    {
                       // for fonts without script GPOS support, if this is a suppressed ZWJ/ZWNJ 
                       // remove its advance width. 
                       if (( currentGlyphFlags & (ushort)GlyphFlags.ClusterStart ) != 0 )
                       { 
                           // for ZWJ/ZWNJ
                           if ( FontClient.IsUnicodeSpaceGlyph(CurrentGlyph) &&
                            ( currentGlyphFlags & (ushort)GlyphFlags.ZeroWidth ) != 0)
                           { 
                                // treat zwj as zero-width base
                                if (_textFlowIsRTL) 
                                { 
                                    // this adjustment is to "undo" the
                                    // adjustment made below for all RTL scripts. 
                                    currentOffsetDu -= currentAdvanceWidth;
                                }
                                currentAdvanceWidth = 0;
                                currentGlyphFlags = (ushort)GlyphFlags.ClusterStart; 
                           }
                       } 
                    } 

                    if ( (currentGlyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 ) 
                    {
                        // For zero-width glyphs, move any advance width to the offset
                        // du value before clearing the advance width (we want to leave
                        // zero-width glyphs with zero advance).  Also keep track of 
                        // cumulative advance for adjacent diacritics, adding the
                        // updated advance to the offset du for each diacritic. 
                        if (_textFlowIsRTL) 
                        {
                            cumulativeAdvance += currentAdvanceWidth; 
                            currentOffsetDu -= cumulativeAdvance;
                        }
                        else
                        { 
                            currentOffsetDu += cumulativeAdvance;
                            cumulativeAdvance += currentAdvanceWidth; 
                        } 

                        currentAdvanceWidth = 0; 
                    }
                    else
                    {
                        cumulativeAdvance = 0; 
                    }
 
                    // update the current glyph's advance/offset... 

                    // Make sure there is no negative advance width after applying positioning. 
                    CurrentGlyphAdvance = Math.Max(0, currentAdvanceWidth);
                    CurrentGlyphOffsetDu = currentOffsetDu;
                }
 
                // For RTL scripts, go through all the glyphs and adjust thd du value so that it
                // takes into account any change in the glyph's advance width due to feature application. 
                // This adjustment is necessary for fixed pitch fonts (like Courier New) which has 
                // a fixed advance width for ALL glyphs (including zero-width diacritics) and this
                // adjustment is necessary when kerning has been applied. 
                // NOTE: This adjustment is unique to Avalon - the unmanaged code (Uniscribe) doesn't
                // need this adjustment.
                if (_textFlowIsRTL)
                { 
                    // go through all the glyphs and adjust any diacritics so that their advance
                    // widths are zero'ed and the advance width is included in the offset du value. 
                    Reset(); 
                    while ( ToNextGlyph() )
                    { 
                        int originalAdvanceWidth =
                                (int)Math.Round(FontClient.FontFace.GetAdvanceWidthInDesignUnits(CurrentGlyph));
                        int offsetAdjustment = CurrentGlyphAdvance - originalAdvanceWidth;
                        if (offsetAdjustment != 0)   // if du is zero, nothing to do 
                        {
                            CurrentGlyphOffsetDu -= offsetAdjustment; 
                        } 
                    }
                } 

                // Finally, go through all the glyphs and scale them.
                if (scalingFactor != 0)
                { 
                    Reset();
                    while ( ToNextGlyph() ) 
                    { 
                        CurrentGlyphAdvance = (int)Math.Round((CurrentGlyphAdvance * scalingFactor));
 
                        int currentOffsetDu = CurrentGlyphOffsetDu;
                        CurrentGlyphOffsetDu =
                            (int)Math.Round((_textFlowIsRTL ? -currentOffsetDu : currentOffsetDu)*scalingFactor);
 
                        CurrentGlyphOffsetDv = (int)Math.Round(CurrentGlyphOffsetDv*scalingFactor);
                    } 
                } 

            } 



            private UshortList                  _charMap; 
            private bool                        _finished;
            private ShaperFontClient            _fontClient; 
            private ushort                      _glyphCount; 
            private GlyphInfoList               _glyphInfoList;
            private bool                        _inited; 
            private ushort                      _nextGlyphIx;
            private bool                        _fontHasScriptGposFeatures;
            private bool                        _textFlowIsRTL;
 
            [SecurityCritical]
            private unsafe int*                 _pGlyphAdvances; 
            [SecurityCritical] 
            private unsafe GlyphOffset *        _pGlyphOffsets;
 
    //        private ShaperBuffers   _shaperWorkspace;

        }
 
}

// 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:      PlacementWorkspace.cs
// 
//  Contents:  support for all the shaping engines - all the local variable 
//             for IShaper.GetGlyphPlacements and helpers are wrapped and
//             all unsafe pointer manipulation is done in this class. 
//
//  Created:   08-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
{
 

        ///  
        ///     PlacementWorkspace  provides safe interactions with the various buffers 
        ///     used by GetGlyphPlacement.
        ///  
        /// 
        ///     This struct is created every time a shaping engine's
        ///     GetGlyphPlacement() 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.GetGlyphPlacement 
        ///     are done through this struct's accessors and methods. 
        /// 
        internal struct PlacementWorkspace 
        {

            /// 
            /// PlacementWorkspace - initializer for GetGlyphPlacements currentRun 
            /// 
            ///  
            ///     This function is always called from IShaper.GetGlyphPlacements. 
            /// 
            ///  
            ///     Critical: This code accepts checked pointers and extracts
            ///         unsafe pointers.
            /// 
             [SecurityCritical] 
             unsafe public PlacementWorkspace (
                ShapingOptions                              shapingFlags, 
 
                ShaperFontClient                            shaperFontClient,
                ShaperBuffers                               shaperBuffers, 

                CheckedCharacterShapingPropertiesPointer    charProperties,
                CheckedUShortPointer                        charClusterMap,
                int                                         charCount, 

                CheckedUShortPointer                        glyphIndices, 
                CheckedGlyphShapingPropertiesPointer        glyphProperties, 
                int                                         glyphCount,
                CheckedIntPointer                           glyphAdvances, 
                CheckedGlyphOffsetPointer                   glyphOffsets,
                bool                                        fontHasScriptGposFeatures,
                TextFlowDirection                           textFlowDirection)
            { 

                Invariant.Assert(charCount > 0,"PlacementWorkspace: invalid char count"); 
 
                // initialize our shaper buffers and set up our local references
                shaperBuffers.Initialize( (ushort)charCount, (ushort) glyphCount ); 
                _charMap = shaperBuffers.CharMap;
                _glyphInfoList = shaperBuffers.GlyphInfoList;

                // keep track of our font client 
                _fontClient = shaperFontClient;
 
                 // positioning-specific members 
                _pGlyphAdvances = glyphAdvances.Probe(0, glyphCount);
                _pGlyphOffsets = glyphOffsets.Probe(0, glyphCount); 


                // initialize our various counts
                _nextGlyphIx = 0; 
                _glyphCount = (ushort)glyphCount;
 
                // initialize our local booleans 
                _inited = true;
                _finished = false; 

                _fontHasScriptGposFeatures = fontHasScriptGposFeatures;
                _textFlowIsRTL = (textFlowDirection == TextFlowDirection.RTL);
 
                // unload the properties to our local representation
                DecompileShapingProperties( charProperties, 
                                            charClusterMap, 
                                            charCount,
 
                                            glyphIndices,
                                            glyphProperties,
                                            glyphCount );
 
             }
 
           public UshortList                        CharMap 
           {
               get { return _charMap; } 
           }

            /// 
            /// CurrentGlyph - sets/gets current glyph 
            /// 
            public ushort                             CurrentGlyph 
            { 
                get { return _glyphInfoList.Glyphs[ _nextGlyphIx ]; }
                set { _glyphInfoList.Glyphs[ _nextGlyphIx ] = value; } 
            }

            /// 
            /// CurrentGlyphAdvance - sets/gets current glyph advance 
            /// 
            ///  
            /// Critical - The method reads into  an unvalidated unsafe array 
            /// 
            unsafe public int                       CurrentGlyphAdvance 
            {
                [SecurityCritical]
                get { return _pGlyphAdvances[ _nextGlyphIx ]; }
                [SecurityCritical] 
                set { _pGlyphAdvances [ _nextGlyphIx ] = value; }
            } 
 
            /// 
            /// CurrentGlyphFlags - sets/gets current glyph flags 
            /// 
            public ushort                             CurrentGlyphFlags
            {
                get { return _glyphInfoList.GlyphFlags[ _nextGlyphIx ]; } 
            }
 
            ///  
            /// CurrentGlyphIx - returns current glyphIx
            ///  
            public ushort                             CurrentGlyphIx
            {
                get { return _nextGlyphIx; }
            } 

            ///  
            /// CurrentGlyphOffsetDu - sets/gets current glyph offset.du 
            /// 
            ///  
            /// Critical - The method reads into  an unvalidated unsafe array
            /// 
            unsafe public int                       CurrentGlyphOffsetDu
            { 
                [SecurityCritical]
                get { return _pGlyphOffsets[ _nextGlyphIx ].du; } 
                [SecurityCritical] 
                set { _pGlyphOffsets [ _nextGlyphIx ].du = value; }
            } 

            /// 
            /// CurrentGlyphOffsetDv - sets/gets current glyph offset.du
            ///  
            /// 
            /// Critical - The method reads into  an unvalidated unsafe array 
            ///  
            unsafe public int                       CurrentGlyphOffsetDv
            { 
                [SecurityCritical]
                get { return _pGlyphOffsets[ _nextGlyphIx ].dv; }
                [SecurityCritical]
                set { _pGlyphOffsets [ _nextGlyphIx ].dv = value; } 
            }
 
 
             /// 
             ///     Critical: This code is unsafe 
             /// 
             [SecurityCritical]
             unsafe private void DecompileShapingProperties (
                CheckedCharacterShapingPropertiesPointer    charProperties, 
                CheckedUShortPointer                        charClusterMap,
                int                                         charCount, 
 
                CheckedUShortPointer                        glyphIndices,
                CheckedGlyphShapingPropertiesPointer        glyphProperties, 
                int                                         glyphCount )
             {
                 Debug.Assert(charCount < ushort.MaxValue);
                 Debug.Assert(glyphCount < ushort.MaxValue); 

 
                 ushort*                     pClusterMap = charClusterMap.Probe(0, charCount); 
                 CharacterShapingProperties* pCharProps  = charProperties.Probe(0, charCount);
                 ushort*                     pGlyphs     = glyphIndices.Probe(0, glyphCount); 
                 GlyphShapingProperties*     pGlyphProps = glyphProperties.Probe(0, glyphCount);

                 ushort firstClusterGlyph = 0;
                 ushort firstClusterChar  = 0; 
                 ushort afterClusterGlyph;
                 ushort afterClusterChar; 
 
                 // Fill glyphs array
                 for(int i= 0; i < _glyphInfoList.Length; i++) 
                 {
                     _glyphInfoList.Glyphs[i] = pGlyphs[i];
                 }
 
                 // Compile shaping properties. Mapping is local to cluster, so doing every cluster as a whole
                 for(int iChar = 1; iChar <= charCount; iChar++) 
                 { 
                     if (iChar < charCount && pClusterMap[iChar] == firstClusterGlyph)
                     { 
                         //We are still inside same cluster
                         continue;
                     }
 
                     // New cluster found. Get boundaries
                     afterClusterChar  = (ushort)iChar; 
                     afterClusterGlyph = (iChar < charCount) ? pClusterMap[iChar] : (ushort)glyphCount; 

                     //Cluster map should come valid from shaping engine 
                     Debug.Assert(firstClusterGlyph < afterClusterGlyph);

                     for(int iClusterChar = firstClusterChar; iClusterChar < afterClusterChar; iClusterChar++)
                     { 
                         byte localMap = pCharProps[iClusterChar].EngineReserved;
 
                         // Clusters should be independent, otherwise they should be merged by shaping engine 
//                         Debug.Assert(localMap < (afterClusterGlyph - firstClusterGlyph));
 
                         CharMap[iClusterChar] = (ushort)(firstClusterGlyph + localMap);
                     }

                     for(int iClusterGlyph = firstClusterGlyph; iClusterGlyph < afterClusterGlyph; iClusterGlyph++) 
                     {
                         ushort mappingStorage = pGlyphProps[iClusterGlyph].EngineReserved; 
                         int firstChar = mappingStorage & 0xFF; 
                         int ligaCount = mappingStorage >> 8;
 
                         // Clusters should be independent, otherwise they should be merged by shaping engine
//                         Debug.Assert(firstChar < (afterClusterChar - firstClusterChar));

                         _glyphInfoList.Glyphs[iClusterGlyph]     = pGlyphs[iClusterGlyph]; 
                         _glyphInfoList.GlyphFlags[iClusterGlyph] = pGlyphProps[iClusterGlyph].GlyphFlags;
                         _glyphInfoList.FirstChars[iClusterGlyph] = (ushort)(firstClusterChar + firstChar); 
                         _glyphInfoList.LigatureCounts[iClusterGlyph] = (ushort)ligaCount; 
                     }
 
                     firstClusterChar  = afterClusterChar;
                     firstClusterGlyph = afterClusterGlyph;
                 }
             } 

 
              public ShaperFontClient                   FontClient 
              {
                  get { return _fontClient; } 
              }


 
         /// 
         /// GlyphAdvances - returns glyph advance pointer 
         ///  
         /// 
         /// Critical - The method reads into  an unvalidated unsafe array 
         /// 
         [SecurityCritical]
         unsafe public int *                       GlyphAdvances
         { 
            [SecurityCritical]
            get { return _pGlyphAdvances; } 
         } 

 
         public GlyphInfoList                      GlyphInfoList
         {
             get { return _glyphInfoList; }
         } 

         ///  
         /// GlyphOffsets - returns glyph offsets pointer 
         /// 
         ///  
         /// Critical - The method reads into  an unvalidated unsafe array
         /// 
         unsafe public GlyphOffset *               GlyphOffsets
         { 
            [SecurityCritical]
            get { return _pGlyphOffsets; } 
         } 

 
              /// 
             /// PlacementWorkspace.InitializeGlyphInfoWidths - helper function for GetGlyphsPlacement.
             /// 
             ///  
             ///     This function populates the glyph run's advance and offset values
             ///     with each glyph's default value (offsets always start zero'ed and 
             ///     the advance value comes from the font). 
             ///     Shapers that are using GPOS features in the font will call this method
             ///     with scalingFactor set to zero which is interpretted as meaning, 
             ///     "no scaling now" (ie, font supports this script, so we're going to let
             ///     the font set the advance).  Such shaping engines will apply scaling after
             ///     the after all the features have been applied by calling ScaleGlyphInfoWidths().
             ///     If a shaping engine has no GPOS features, then the caller (ie, 
             ///     GetGlyphsPlacement()) can pass in the appropriate scaling factor.
             ///  
             ///  
             ///     Critical: This code accesses critical methods.
             ///  
              [SecurityCritical]
             public void InitializeGlyphInfoWidths ()
             {
                 Invariant.Assert (_glyphCount == _glyphInfoList.Length); 

                 GlyphTypeface fontFace = FontClient.FontFace; 
 
                 // Init the advance width for all the glyphs.
                 while ( ToNextGlyph() ) 
                 {
                    int glyphAdvance = 0; // All diacritics get a zero'ed advance width

                    // All non-diacritics get advance width from the font 
                    if ((CurrentGlyphFlags & (ushort)GlyphFlags.ZeroWidth) == 0)
                    { 
                        glyphAdvance = (int)Math.Round(fontFace.GetAdvanceWidthInDesignUnits(CurrentGlyph)); 
                    }
 
                    // set the initial start values
                    CurrentGlyphAdvance = glyphAdvance;
                    CurrentGlyphOffsetDu = 0;
                    CurrentGlyphOffsetDv = 0; 
                 }
 
            } 

            ///  
            /// ToNextGlyph - increments index, returns false if finished
            /// 
            public bool ToNextGlyph()
            { 
              if (_inited)
              { 
                // if this is the first character, don't increment the 
                // index (so we can use this in a while (ToNextGlyph){...}
                // loop 
                _inited = false;
              }
              else if (_nextGlyphIx + 1 < _glyphCount)
              { 
                  ++_nextGlyphIx;
              } 
              else 
              {
                _finished = true; 
              }

              return !_finished;
            } 

 
            ///  
            /// PlacementWorkspace.Reset - used to re-initial the ToNextGlyph mechanism
            ///        (our iterator function, if you please!) 
            /// 
            public void Reset(  )
            {
               _nextGlyphIx = 0; 

               _inited = true; 
               _finished = false; 
            }
 
            /// 
            /// PlacementWorkspace.ScaleGlyphInfoWidths - helper function for GetGlyphsPlacement.
            /// 
            ///  
            ///     This function scales the glyph run's advance and offset values.
            ///     Shapers that are using GPOS features in the font will call this method 
            ///     after applying the font's GPOS feaures. 
            /// 
            ///  
            ///     Critical: This code accesses critical methods.
            /// 
            [SecurityCritical]
            public void ScaleGlyphInfoWidths( double scalingFactor ) 
            {
                // Some fonts have assigned an advance value for the dicritic glyphs. 
                // We have to zero the advance width on any diacritic, and add the value 
                // to the du width.
                int cumulativeAdvance = 0; 

                // go through all the glyphs and adjust any diacritics so that their advance
                // widths are zero'ed and the advance width is included in the offset du value.
                Reset(); 
                while ( ToNextGlyph() )
                { 
                    ushort currentGlyphFlags = CurrentGlyphFlags; 
                    int currentAdvanceWidth = CurrentGlyphAdvance;
                    int currentOffsetDu = CurrentGlyphOffsetDu; 


                    // This is used for Arabic/Hebrew fonts that don't have GPOS support...
                    if ( !_fontHasScriptGposFeatures ) 
                    {
                       // for fonts without script GPOS support, if this is a suppressed ZWJ/ZWNJ 
                       // remove its advance width. 
                       if (( currentGlyphFlags & (ushort)GlyphFlags.ClusterStart ) != 0 )
                       { 
                           // for ZWJ/ZWNJ
                           if ( FontClient.IsUnicodeSpaceGlyph(CurrentGlyph) &&
                            ( currentGlyphFlags & (ushort)GlyphFlags.ZeroWidth ) != 0)
                           { 
                                // treat zwj as zero-width base
                                if (_textFlowIsRTL) 
                                { 
                                    // this adjustment is to "undo" the
                                    // adjustment made below for all RTL scripts. 
                                    currentOffsetDu -= currentAdvanceWidth;
                                }
                                currentAdvanceWidth = 0;
                                currentGlyphFlags = (ushort)GlyphFlags.ClusterStart; 
                           }
                       } 
                    } 

                    if ( (currentGlyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 ) 
                    {
                        // For zero-width glyphs, move any advance width to the offset
                        // du value before clearing the advance width (we want to leave
                        // zero-width glyphs with zero advance).  Also keep track of 
                        // cumulative advance for adjacent diacritics, adding the
                        // updated advance to the offset du for each diacritic. 
                        if (_textFlowIsRTL) 
                        {
                            cumulativeAdvance += currentAdvanceWidth; 
                            currentOffsetDu -= cumulativeAdvance;
                        }
                        else
                        { 
                            currentOffsetDu += cumulativeAdvance;
                            cumulativeAdvance += currentAdvanceWidth; 
                        } 

                        currentAdvanceWidth = 0; 
                    }
                    else
                    {
                        cumulativeAdvance = 0; 
                    }
 
                    // update the current glyph's advance/offset... 

                    // Make sure there is no negative advance width after applying positioning. 
                    CurrentGlyphAdvance = Math.Max(0, currentAdvanceWidth);
                    CurrentGlyphOffsetDu = currentOffsetDu;
                }
 
                // For RTL scripts, go through all the glyphs and adjust thd du value so that it
                // takes into account any change in the glyph's advance width due to feature application. 
                // This adjustment is necessary for fixed pitch fonts (like Courier New) which has 
                // a fixed advance width for ALL glyphs (including zero-width diacritics) and this
                // adjustment is necessary when kerning has been applied. 
                // NOTE: This adjustment is unique to Avalon - the unmanaged code (Uniscribe) doesn't
                // need this adjustment.
                if (_textFlowIsRTL)
                { 
                    // go through all the glyphs and adjust any diacritics so that their advance
                    // widths are zero'ed and the advance width is included in the offset du value. 
                    Reset(); 
                    while ( ToNextGlyph() )
                    { 
                        int originalAdvanceWidth =
                                (int)Math.Round(FontClient.FontFace.GetAdvanceWidthInDesignUnits(CurrentGlyph));
                        int offsetAdjustment = CurrentGlyphAdvance - originalAdvanceWidth;
                        if (offsetAdjustment != 0)   // if du is zero, nothing to do 
                        {
                            CurrentGlyphOffsetDu -= offsetAdjustment; 
                        } 
                    }
                } 

                // Finally, go through all the glyphs and scale them.
                if (scalingFactor != 0)
                { 
                    Reset();
                    while ( ToNextGlyph() ) 
                    { 
                        CurrentGlyphAdvance = (int)Math.Round((CurrentGlyphAdvance * scalingFactor));
 
                        int currentOffsetDu = CurrentGlyphOffsetDu;
                        CurrentGlyphOffsetDu =
                            (int)Math.Round((_textFlowIsRTL ? -currentOffsetDu : currentOffsetDu)*scalingFactor);
 
                        CurrentGlyphOffsetDv = (int)Math.Round(CurrentGlyphOffsetDv*scalingFactor);
                    } 
                } 

            } 



            private UshortList                  _charMap; 
            private bool                        _finished;
            private ShaperFontClient            _fontClient; 
            private ushort                      _glyphCount; 
            private GlyphInfoList               _glyphInfoList;
            private bool                        _inited; 
            private ushort                      _nextGlyphIx;
            private bool                        _fontHasScriptGposFeatures;
            private bool                        _textFlowIsRTL;
 
            [SecurityCritical]
            private unsafe int*                 _pGlyphAdvances; 
            [SecurityCritical] 
            private unsafe GlyphOffset *        _pGlyphOffsets;
 
    //        private ShaperBuffers   _shaperWorkspace;

        }
 
}

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