latinshape.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / Shaping / latinshape.cs / 2 / latinshape.cs

                            //+------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2001
// 
//  File:      LatinShape.cs
// 
//  Contents:  Combining marks/ Latin OT shaping engine 
//
//  Contact:   [....] 
//
//  Created:   10-21-2003
//
//----------------------------------------------------------------------- 

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Globalization;
using MS.Internal;
using MS.Internal.FontCache;
using System.Security; 
using System.Security.Permissions;
 
using System.Windows.Media; 
using System.Windows.Media.TextFormatting;
 
namespace MS.Internal.Shaping
{
    /// 
    /// The Latin/Cyrillic/Greek Shaping Engine - (shapes Latin text) 
    /// 
    ///  
    /// The IShaper and IShapingEngine interfaces are implemented to 
    /// provide the shaping methods for Latin/Cyrillic/Greek Scripts.
    /// This engine incorporates combining marks shaping, which is 
    /// not dependent on the font being OpenType.
    ///
    internal class LatinShape : BaseShape
    { 

#region Data members 
        // 
        // See static LatinShape() constructor for notes and initialization.
        // 
        // Two-dimensional array [_combiningCharsIndexesTableLength][_combiningCharsIndexesTableSegmentLength]

        /// 
        /// Critical - Holds a pointer object 
        /// 
        [SecurityCritical] 
        private unsafe static readonly ushort* _combiningCharsIndexes; 
        private static readonly int _combiningCharsIndexesTableLength;
        private static readonly int _combiningCharsIndexesTableSegmentLength; 

        /// 
        /// Critical - Holds a pointer object
        ///  
        [SecurityCritical]
        private unsafe static readonly ushort* _combiningMarkIndexes; 
        private static readonly int _combiningMarkIndexesTableLength; 

 
        /// 
        /// Critical - Holds a pointer object
        /// 
        [SecurityCritical] 
        private unsafe static readonly char* _combiningChars;
        private static readonly int _combiningCharsBaseCount; 
        private static readonly int _combiningCharsMarkCount; 

        private static readonly ScriptTags[] _supportedScripts; 

        const char InvalidCombinationChar = '\u0000';
        const ushort InvalidBaseIndex = 0;
        const ushort InvalidMarkIndex = 0xffff; 

#endregion 
 
        //--------------------------------------
        // 
        //  Constructors
        //
        //--------------------------------------
#region Constructors 

        ///  
        /// Critical -This code calls into unsafe code and stores pointers 
        /// Safe    - This constructor doesn't expose any of the unsafe pointers.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        unsafe static LatinShape()
        {
            Classification.CombiningMarksClassificationData classification; 

            Classification.GetCombiningMarksClassificationData(out classification); 
 
            _combiningCharsIndexes                       = (ushort*)classification.CombiningCharsIndexes;
            _combiningCharsIndexesTableLength            = classification.CombiningCharsIndexesTableLength; 
            _combiningCharsIndexesTableSegmentLength     = classification.CombiningCharsIndexesTableSegmentLength;

            _combiningMarkIndexes                = (ushort*)classification.CombiningMarkIndexes;
            _combiningMarkIndexesTableLength     = classification.CombiningMarkIndexesTableLength; 

            _combiningChars            = (char*)classification.CombinationChars; 
            _combiningCharsBaseCount   = classification.CombinationCharsBaseCount; 
            _combiningCharsMarkCount   = classification.CombinationCharsMarkCount;
 
            _supportedScripts = new ScriptTags[]
            {
                ScriptTags.Armenian,
                ScriptTags.Bopomofo, 
                ScriptTags.Braille,
                ScriptTags.Buhid,                   // * 
                ScriptTags.CanadianSyllabics, 
                ScriptTags.Cherokee,
                ScriptTags.CJKIdeographic, 
                ScriptTags.Coptic,
                ScriptTags.Cyrillic,
                ScriptTags.Ethiopic,
                ScriptTags.Georgian, 
                ScriptTags.Glagolitic,
                ScriptTags.Greek, 
                ScriptTags.Hanunoo,                 // * 
                ScriptTags.Hiragana,
//                ScriptTags.Katakana,      // this is here for reference only - tag has same value as "Hiragana" 
                ScriptTags.Latin,
                ScriptTags.Ogham,
                ScriptTags.Runic,
                ScriptTags.Tagalog,                 // * 
                ScriptTags.Tagbanwa,                // *
                ScriptTags.TaiLe, 
                ScriptTags.Tifinagh, 
                ScriptTags.Yi
 
                // * For V2 Philippine scripts will require separate engine
                //   to handle combining marks in case of incorrect input
            };
        } 

        ///  
        /// Constructor for the Latin Open Type Shaping Engine. 
        /// 
        internal LatinShape() 
        {
        }

#endregion 

        //-------------------------------------- 
        // 
        //  Internal Methods
        // 
        //--------------------------------------
#region Internal methods

        ///  
        /// HebrewShape.SupportedScripts -
        ///  IShapingEngine member override 
        ///  
        /// Our supported scripts (Hebrew, Thaana).
        public override ScriptTags[] SupportedScripts 
        {
            get { return _supportedScripts; }
        }
 
        /// 
        /// LatinShape.OnLoadFont - IShapingEngine method override. 
        ///  
        /// 
        ///     We override the base implementation because this shaper 
        ///     has work to do even if the font doesn't support our
        ///     script.  (Combining marks support is not OpenType feature
        ///     dependent)
        ///  
        /// Script of interest.
        /// Font face being loaded 
        /// font specific info for the shaper 
        /// True if font supports script.
        ///  
        /// Critical - This method reads into raw font table bits.
        /// Safe     - This method doesn't expose any critical data.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override bool OnLoadFont(
            ScriptTags          scriptTag, 
            GlyphTypeface       fontFace, 
            out object          shapeFontFaceInfo
            ) 
        {
            // Create a font client for this script.  (LatinShape doesn't have
            // its own CharClassifier and will support fonts that have no OpenType
            // script support, so use the "no OT support" constructor... 
            ShaperFontClient fontClient = new ShaperFontClient(fontFace);
 
            // Now check if script support does exist in font 
            if (OpenTypeLayout.FindScript(fontClient,(uint)scriptTag) != TagInfoFlags.None)
            { 
                fontClient.IsScriptSupportedByFont = true;
            }

            // we don't care if script support is in font cause we support 
            // combining marks even if the font doesn't support our script,
            // so we always return "true" 
            shapeFontFaceInfo = fontClient; 
            return true;
        } 


        /// 
        ///     LatinShape.GetGlyphs - Latin implementation of the GetGlyphs() helper function. 
        /// 
        /// shaping currentRun 
        /// Text item 
        /// number of glyphs
        ///  
        /// Critical - calls critical code, unsafe code
        /// 
        [SecurityCritical]
        unsafe protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item ) 
        {
 
            // no pre-substitution shaping, just cmap lookup. 
            ushort currGlyph;
            CharShapeInfo currShape; 
            ushort marksCount;
            while ( GetNextGlyph (ref currentRun, out currGlyph, out currShape, out marksCount) )
            {
 
                if (marksCount < 2)
                { 
                    currentRun.SetGlyphPropertiesUsingGlyph(currShape, currGlyph); 
                }
                else 
                {
                    // we need to replace the base glyph (already added) with
                    // this new composite glyph
                    currentRun.PreviousGlyph = currGlyph; 
                    currentRun.AddLigatureChars(-1,marksCount);
                } 
 
            }
 
            return currentRun.GlyphsCount;
        }

#endregion 

    //-------------------------------------- 
    // 
    //  Private Methods
    // 
    //--------------------------------------
#region Combining mark methods

    ///  
    /// Index of the mark char in the combination lookup table
    ///  
    ///  
    /// Critical - Dereferences a pointer which is stored without any validation
    /// Safe     - This method returns classification data which is safe. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe]
    private unsafe ushort GetMarkIndex(char markChar)
    { 
        int markCharCode = markChar-0x300;
 
        if (markCharCode<0 || markCharCode>=_combiningMarkIndexesTableLength) return InvalidMarkIndex; 
        return _combiningMarkIndexes[markCharCode];
    } 

    /// 
    /// Critical - Dereferences a pointer which is stored without any validation
    /// Safe     - This method returns classification data which is safe. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe] 
    private unsafe ushort GetBaseIndex(char baseChar) 
    {
        ushort baseCharCode = (ushort)baseChar; 

        ushort secondLevelIndex = _combiningCharsIndexes[ //0 * _combiningCharsIndexesTableLength +  :first segment
                                                         baseCharCode/_combiningCharsIndexesTableSegmentLength];
        Invariant.Assert(secondLevelIndex < _combiningCharsIndexesTableLength); 

        return _combiningCharsIndexes[secondLevelIndex*_combiningCharsIndexesTableSegmentLength + 
                                            baseCharCode%_combiningCharsIndexesTableSegmentLength]; 
    }
 
    /// 
    /// Get combination character from combination lookup table
    /// 
    ///  
    /// Critical - Dereferences a pointer which is stored without any validation
    /// Safe     - This method returns classification data which is safe. 
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    private unsafe char GetCombinationChar(ushort baseCharCode, ushort markCharCode) 
    {
        Invariant.Assert(baseCharCode < _combiningCharsBaseCount && markCharCode < _combiningCharsMarkCount);
        return _combiningChars[baseCharCode*_combiningCharsMarkCount + markCharCode];
    } 

    ///  
    /// Critical - Uses unsafe accessors/functions 
    /// 
    [SecurityCritical] 
    private unsafe bool GetNextGlyph(   ref ShapingWorkspace        currentRun,
                                            out ushort                  currGlyph,
                                            out CharShapeInfo           currShape,
                                            out ushort                  marksCount ) 
    {
 
        // assume this isn't a combining mark (good assumption) 
        marksCount = 0;
 
        char currChar;
        bool isNextValid = currentRun.GetNextCharProperties (out currChar, out currGlyph, out currShape);
        if ( isNextValid )
        { 
            ushort markIndex = GetMarkIndex( currChar );
            if ( markIndex != InvalidMarkIndex && (currShape & CharShapeInfo.IsUnicodeLayoutControl) == 0) 
            { 
                marksCount=1;    // this is a valid mark (it may form a combination)
                currShape = CharShapeInfo.NoFlagsSet;   // this is a combining mark 

                ushort baseIndex = GetBaseIndex(currentRun.PreviousChar);
                if (baseIndex != InvalidBaseIndex)
                { 

                    // base is a base, so check for combination char 
                    char baseAndMarkOneChar=GetCombinationChar(baseIndex,markIndex); 
                    ushort baseAndMarkOneGlyph = currentRun.CharConverter.ToGlyph(baseAndMarkOneChar);
                    if ( baseAndMarkOneGlyph != 0 ) 
                    {

                        // base + mark form a combination char.  Let's see if we're
                        // lucky (can we use the next char(s) to form a combination 
                        // char?)
                        ushort markTwoIndex = GetMarkIndex(currentRun.GetChar((ushort)(currentRun.CurrentCharIx + 1))); 
                        if (markTwoIndex == InvalidMarkIndex) 
                        {
                            // nope, the next char isn't a mark, so we're done (we found a 
                            // glyph for this combination char)
                            marksCount = 2;
                            currShape |= CharShapeInfo.IsStartOfCluster;
                            currGlyph = baseAndMarkOneGlyph; 
                        }
                        else 
                        { 
                            // next char is a mark, does it form a combination?
 
                            ushort baseAndMarkOneIndex = GetBaseIndex(baseAndMarkOneChar);
                            char baseAndBothMarksChar = GetCombinationChar(baseAndMarkOneIndex, markTwoIndex);
                            if (baseAndBothMarksChar != InvalidCombinationChar)
                            { 
                                // base + both marks does form a combination char.  Does
                                // font have the right glyph? 
                                ushort baseAndBothMarksGlyph = currentRun.CharConverter.ToGlyph(baseAndBothMarksChar); 
                                if (baseAndBothMarksGlyph != 0)
                                { 
                                    // we have a winner!  ("base + 2 marks" has a glyph)  If there's not yet
                                    // another mark in the character stream, send the combo glyph back.  If
                                    // there is another mark, don't send combo glyph.
                                    ushort markThreeIndex = GetMarkIndex(currentRun.GetChar((ushort)(currentRun.CurrentCharIx + 2))); 
                                    if (markThreeIndex == InvalidMarkIndex)
                                    { 
                                        marksCount = 3; 
                                        currShape |= CharShapeInfo.IsStartOfCluster;
                                        currGlyph = baseAndBothMarksGlyph; 
                                    }
                                }
                            }
                        } 
                    }
                } 
            } 
        }
 
        return isNextValid;
    }

 
#endregion
 
    } 
}

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