Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / Shaping / thaishape.cs / 2 / thaishape.cs
//---------------------------------------------------------------------- // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation, 2003 // // File: ThaiShape.cs // // Contents: Implementation of Thai shaping engine and its factory // // Created: 08-05-2003 [....] ([....]) // //----------------------------------------------------------------------- // #define VALIDATE_CLUSTER_PARAMETERS using System; using System.Security; using System.Security.Permissions; using System.Diagnostics; using System.Collections; using System.Globalization; using System.Windows; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.PresentationCore; namespace MS.Internal.Shaping { ////// ThaiCharClass - enumeration of Thai classification flags /// ordinal position /// internal enum ThaiCharClass : byte { UnknownCharClass, // Unknown class -- can take any diacritic AcceptsNoMark, // AcceptsNoMark -- cannot take diacritics LaoAmChar, // The Am character ThaiAmChar, // The Am character BaseAcceptsLower, // No upper diacritic is allowed. below is okay BaseAcceptsMarks, // Base glyph can have diacritics SpaceChar, // space may be base of mark (only one) FirstBaseChar = BaseAcceptsLower, LastBaseChar = SpaceChar, AboveMarkClosest, // Above mark closest to base AboveMarkClose, // Second level above mark AboveMarkFurther, // Third level above mark AboveMarkFurthest, // Fourth level above mark BelowMarkClosest, // Below mark closest to base BelowMarkFurthest, // Second level below mark LastDiacritic = BelowMarkFurthest, UnicodeLayoutControl, NumberOfThaiCharClasses, }; ////// The Thai Shaping Engine - (shapes Thai text) /// ////// The IShaper and IShapingEngine interfaces are implemented to /// provide the shaping methods for Thai Scripts. /// There are four Thai private types defined/used in this class: /// 1.) ThaiShapeInfo - this class manages the shape information /// 2.) ThaiClusterCop - this class manages the canonical ordering /// 3.) ThaiFontInfo - this class manages the font interface /// 4.) ThaiCharClassInfo - contains the char classification tables /// internal sealed class ThaiShape : BaseShape { private static readonly ScriptTags[] _supportedScripts = new ScriptTags[] {ScriptTags.Thai,ScriptTags.Lao}; //-------------------------------------- // // Constructors // //-------------------------------------- #region Constructors ////// Constructor for the Thai Open Type Shaping Engine. /// internal ThaiShape() { // At least one of the Thai fonts (Angsana UPC) calls sara aa // a mark (but its not a zero width mark). _forceDiacriticsToZeroWidth = false; } #endregion //-------------------------------------- // // Internal Methods // //-------------------------------------- #region Internal methods ////// ThaiShape.GetCharClassifier - Base shape /// ////// This will normally be overridden by derived shapers. It is used in OnLoadFont /// protected override ShaperCharacterClassifier GetCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) { return new ThaiCharClassifier (scriptTag, fontFace); } ////// ThaiShape.GetGlyphs - Thai override of the GetGlyphs() helper function. /// /// shaping currentRun /// Text item ///number of glyphs ////// Critical - calls critical code /// [SecurityCritical] unsafe protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item ) { // Create support for diacritic reordering. "clusterControl" is // on the stack; fast to alloc, easy to throw away. ushort *clusterGlyphs = stackalloc ushort [ ThaiClusterCop.ReorderingArraySize ]; ThaiClusterCop clusterCop = new ThaiClusterCop( clusterGlyphs ); bool isClusterInProgress = false; // get shape info for every character CharShapeInfo currShape; while ( currentRun.GetNextShape (out currShape) ) { if ( (currShape & CharShapeInfo.IsStartOfCluster) != 0 ) { // If there is a just completed cluster which // needs reordering, nows the time to change the glyphs. if (isClusterInProgress) { // get reordered glyphs clusterCop.GetReorderedGlyphs( ref currentRun ); isClusterInProgress = false; } currentRun.SetGlyphPropertiesUsingShapeInfo(currShape); } else { isClusterInProgress = clusterCop.AddCluster( ref currentRun, currShape ); } } if (isClusterInProgress) { // get reordered glyphs clusterCop.GetReorderedGlyphs( ref currentRun ); } return currentRun.GlyphsCount; } ////// ThaiShape.SupportedScripts - /// IShapingEngine member override /// ///Our supported scripts (Thai, Lao). public override ScriptTags[] SupportedScripts { get { return _supportedScripts; } } #endregion } ////// Class ThaiClusterCop: /// Manages the diacritic ordering requirement /// ////// This class is used to provide diacritic ordering and invalid /// diacritic enforcement for the diacritics and cantillation marks /// found in the unicode stream. /// Diacritic ordering is done by maintaining an array whose extent /// is ThaiCharClassifier.NumberOfClasses. /// internal struct ThaiClusterCop { private ThaiCharClass _baseCharClass; // base char's class info ///for comments about the /// char class enum. /// For each base character in the unicode run, the diacritics and /// other marks are added to the arrays at the index corresponding /// to the ThaiCharClass value. Only one mark per ThaiCharClass /// value is allowed per base character. Once the extent of the valid /// diacritics and marks has been determined (ie, when an /// illegal mark is found, when a new base is found, or at the end of /// the unicode run) the array used to reorder the glyphs collected in /// the GlyphList object if reordering is needed (only lower marks are /// reordered - out-of-order upper marks results in a dotted circle base /// being inserted). /// The diacritics reordering done here is not consistent with Unicode /// canonical ordering, but is instead consistent with the needs of /// current Thai OpenType fonts. /// /// Critical - unsafe pointers /// [SecurityCritical] unsafe private ushort* _clusterGlyphs; // our temporary array for reordering private bool _clusterIsInvalid; // private byte _clusterSize; // number of diacritics currently in cluster private ThaiClusterState _clusterState; // current reordering state private bool _clusterRequiresReordering; private bool _clusterHasSaraAm; private ushort _nextReorderedGlyphIx; // for returning reordered glyphs (0 if no reordering) private ushort _lastReorderedGlyphIx; // for returning reordered glyphs (0 if no reordering) private bool _reorderingIsSuppressed; // private bool _textHasUnicodeControlChars; // true if control chars are found to exist in text private ushort _nikhahitGlyph; private ushort _aaGlyph; private ushort _firstCharIx; ////// ThaiClusterCop constructor /// ////// Critical - This method reads into unsafe buffer /// [SecurityCritical] unsafe public ThaiClusterCop ( ushort *clusterGlyphs ) { // create support for diacritic reordering. Add one extra position // for use in storing 'Aa' when decomposing an 'Am' char. _clusterGlyphs = clusterGlyphs; _clusterState = ThaiClusterState.BaseChar; _baseCharClass = ThaiCharClass.UnknownCharClass; _lastReorderedGlyphIx = _nextReorderedGlyphIx = 0; _clusterIsInvalid = _reorderingIsSuppressed = _clusterHasSaraAm =_clusterRequiresReordering = _textHasUnicodeControlChars = false; // initialize the diacritics class array (its on the stack) // initialize the glyph array (its on the stack) int i = ThaiClusterCop.ReorderingArraySize; while (i-- > 0) { _clusterGlyphs[i] = 0; } _clusterSize = 0; _nikhahitGlyph = _aaGlyph = 0; _firstCharIx = 0; } ////// ThaiClusterCop.AddCluster - adds as many characters as possible to the /// current cluster /// ////// This routine is used to create a diacritics cluster on the current /// base char. It continues to add characters till it notes a non-legal /// character. Enforces member count restrictions for the various diacritic /// classes and keeps track of reordering needs. /// ////// true if cluster remains valid /// ////// Critical - calls critical code, uses unsafe accessors /// [SecurityCritical] unsafe internal bool AddCluster ( ref ShapingWorkspace currentRun, CharShapeInfo currShape ) { bool isClusterInProgress = StartCluster( ref currentRun, currShape ); char currChar = currentRun.CurrentChar; ushort currGlyph = currentRun.CharConverter.ToGlyph(currChar); do { ThaiCharClass currClass = (ThaiCharClass)(currShape & CharShapeInfo.ShaperClassMask); // add this character's glyph to the cluster if ( _clusterIsInvalid) { _reorderingIsSuppressed = true; currShape |= CharShapeInfo.RequiresInsertedBase; isClusterInProgress = false; if ( (currShape & CharShapeInfo.RequiresSpecialHandling) != 0 && IsSaraAmDecomposable(ref currentRun, currClass) ) { // decompose this into 2 glyphs (after inserting // the dotted circle glyph). currentRun.AddGlyphs( 1 ); currentRun.SetGlyphPropertiesUsingGlyph( currShape, _nikhahitGlyph ); currShape ^= CharShapeInfo.RequiresInsertedBase; currShape |= CharShapeInfo.IsStartOfCluster; currentRun.CurrentShape = currShape; currentRun.SetGlyphProperties(_aaGlyph); continue; } } else { // step 1. get the reordering position ThaiClusterState clusterIx = ThaiClusterCop.clusterStateMap[ (int)currClass ]; // step 2. validate this character switch (clusterIx) { case ThaiClusterState.BaseChar: // This marks the end of the cluster. We'll have to re-process this character currentRun.Reset(); return (_clusterRequiresReordering || _clusterHasSaraAm); // leave now. case ThaiClusterState.UnicodeLayoutControlPresent: _clusterRequiresReordering = false; _textHasUnicodeControlChars = true; _reorderingIsSuppressed = true; // we don't want to confuse things by reordering currShape |= CharShapeInfo.IsUnicodeLayoutControl; break; default: // - don't allow two characters of the same // class in a cluster if ( _clusterHasSaraAm || (_clusterGlyphs[ (int) clusterIx] != 0) || IsIllegalPair(_baseCharClass,currClass) ) { _clusterIsInvalid = _reorderingIsSuppressed = true; // for consistency with unmanaged Uniscribe // add a dotted circle (except if the preceding character or this character is a ZWJ) if (!_textHasUnicodeControlChars || (currentRun.PreviousChar != UnicodeCharacter.ZWJ)) { // no valid base char precedes this char, then we must // insert a dotted circle in the shaping info currShape |= CharShapeInfo.RequiresInsertedBase; if ( (currShape & (CharShapeInfo)ThaiCharClassifier.IsAmChar) != 0 && IsSaraAmDecomposable(ref currentRun, currClass) ) { // decompose this into 2 glyphs currentRun.AddGlyphs( 1 ); currentRun.SetGlyphPropertiesUsingGlyph( currShape, _nikhahitGlyph ); currShape = CharShapeInfo.NoFlagsSet; currGlyph =_aaGlyph; } } isClusterInProgress = false; } else { // if this is a sara am, decompose it if possible if ((currShape & CharShapeInfo.RequiresSpecialHandling) != 0) { _clusterHasSaraAm = true; if (IsSaraAmDecomposable(ref currentRun, currClass)) { currGlyph = _nikhahitGlyph; } } // All's well! // step 3. As long as reordering isn't suppressed, save the current glyph in the // reordering array. (We may not need to reorder, but we might) if (currGlyph == 0) { _reorderingIsSuppressed = true; // this isn't expected, but reordering array } else { _clusterGlyphs[ (ushort)clusterIx ] = currGlyph; _clusterSize++; // step 4. update the reordering state if ( _lastReorderedGlyphIx < (ushort)clusterIx ) { // Keep _lastReorderedGlyphIx at the "highest" member of the // reordering array _lastReorderedGlyphIx = (ushort)clusterIx; } if (clusterIx >= _clusterState) { // no reordering needed thus far... // keep track of the "highest" cluster member _clusterState = clusterIx; } else if ( !_reorderingIsSuppressed ) { // this current char is "lower" than a previous character // in the cluster so we're gonna need to reorder this cluster _clusterRequiresReordering = true; } if (_clusterHasSaraAm && IsSaraAmDecomposable(ref currentRun, currClass)) { currGlyph = _aaGlyph; } } } break; } } // Add this glyph and shape to the glyphlist currentRun.SetGlyphPropertiesUsingGlyph(currShape,currGlyph); } while ( isClusterInProgress && currentRun.GetNextCharProperties (out currChar, out currGlyph, out currShape) ); return (_clusterRequiresReordering || _clusterHasSaraAm); } ////// ThaiClusterCop.IsSaraAmDecomposable - get the reordered glyph /// ////// ///true if sara am is decomposed ////// Critical - calls critical code, uses pointers /// [SecurityCritical] unsafe private bool IsSaraAmDecomposable(ref ShapingWorkspace currentRun, ThaiCharClass currClass) { bool isDecomposed = (_nikhahitGlyph != 0 && _aaGlyph != 0); if (!isDecomposed) { IScriptCharConverter charConverter = currentRun.CharConverter; char nikhahit; char aa; if (currClass == ThaiCharClass.ThaiAmChar) { nikhahit = '\u0e4d'; aa = '\u0e32'; } else { nikhahit = '\u0ecd'; aa = '\u0eb2'; } _nikhahitGlyph = charConverter.ToGlyph(nikhahit); _aaGlyph = charConverter.ToGlyph(aa); isDecomposed = (_nikhahitGlyph != 0 && _aaGlyph != 0); } return isDecomposed; } ////// ThaiClusterCop.GetNextGlyph - get the reordered glyph /// ////// This function is called to fetch each member of a reordered cluster. /// It clears the array position as it fetchs each char. /// This function will return '\u0000' if there are no valid chars /// to return. /// ///next reordered character ////// Critical - calls critical code, uses pointers /// [SecurityCritical] unsafe private ushort GetNextGlyph() { ushort nextGlyph = 0; if ( _lastReorderedGlyphIx != 0 && _clusterSize != 0 && _lastReorderedGlyphIx < (ushort) ReorderingArraySize ) { ushort lastGlyphIx = _lastReorderedGlyphIx; ushort nextGlyphIx = _nextReorderedGlyphIx; while (nextGlyph == 0) { if (++nextGlyphIx > lastGlyphIx) { _clusterSize = 0; return nextGlyph; } nextGlyph = _clusterGlyphs[ nextGlyphIx ]; } _nextReorderedGlyphIx = nextGlyphIx; --_clusterSize; } else { _clusterSize = 0; } return nextGlyph; } ////// Critical - calls critical code, uses pointers /// [SecurityCritical] unsafe internal int GetReorderedGlyphs( ref ShapingWorkspace currentRun ) { ushort reorderedCount = ReorderedCount; if (reorderedCount > 0) { Debug.Assert (_firstCharIx + _clusterSize - (currentRun.IsFinished?1:0) <= currentRun.CurrentCharIx); ushort nextGlyphIx = currentRun.GetGlyphIx( _firstCharIx); if(_clusterHasSaraAm) { // Insert a glyph to account for the decomposed sara am. Currently, // the list of diacritic glyphs includes the decomposed sara aa, but // the reordering array includes the decomposed nikhahit. "reorderedCount" // does not take account of the needed extra glyph. We insert // the extra glyph just before the sara aa glyph; normally the decomposed sara // aa will be the last glyph added till now. Then in the loop below // we will replace the glyphs for all the diacritics in their right // order. currentRun.InsertGlyphs( (ushort)(nextGlyphIx + reorderedCount - 1),(ushort)1 ); } // replace the reordered glyphs while ( _clusterSize > 0 ) { currentRun.SetGlyph(nextGlyphIx++, GetNextGlyph()); } _clusterRequiresReordering = false; } return reorderedCount; } ////// ThaiCharClassifier.IsIllegalPair - Validates a base/mark combo /// ////// Uniscribe does not verify that a given mark is legal on /// a given base. Thus, our behavior is different than legacy /// implementation. Note that a space character is a valid /// base, but we return "false" so that space char base can /// be differentiated in the ClusterControl.AddToCluster() /// /// current base char /// class of diacritic ///false if diacritic can't be attached to base private static bool IsIllegalPair (ThaiCharClass baseClass, ThaiCharClass markClass) { return ( (CharClassToFlag[(int)baseClass] & ThaiCharClassFlags.AllLegalBaseChars) == 0 || (CharClassToFlag[(int)markClass] & BaseDiacriticValidationTable[(int)baseClass] ) == 0); } ////// ThaiClusterCop.ReorderedCount - get size of cluster /// ////// this number doesn't include the base character. /// internal ushort ReorderedCount { get { return _clusterRequiresReordering || _clusterHasSaraAm ? (ushort)_clusterSize : (ushort)0; } } ////// Critical - This method reads into unsafe buffer /// [SecurityCritical] unsafe private void ResetClusterCop () { // If last processed cluster did not require reordering, then // clusterSize will be non-zero and we need to re-initialize the // reordering array. Otherwise, its already init'ed. int i = ThaiClusterCop.ReorderingArraySize; while (i-- > 0) { _clusterGlyphs[i] = 0; } _clusterSize = 0; _clusterState = ThaiClusterState.BaseChar; _clusterIsInvalid = _reorderingIsSuppressed = _clusterHasSaraAm = _clusterRequiresReordering = false; _lastReorderedGlyphIx = _nextReorderedGlyphIx = 0; } ////// ThaiClusterCop.StartCluster - start new cluster (potentially) /// ////// This routine is called with the first non-base member of a new /// cluster. If the base + this first non-base char are the valid /// start of a new cluster, the ClusterCop is initialized in preparation /// for the rest of the cluster. The character is shaped and its glyph /// is added to the glyphs list, regardless of whether this is a "valid" /// cluster or not. /// ///true if more characters can be added to this cluster ////// Critical - calls critical code, uses unsafe accessors /// [SecurityCritical] unsafe private bool StartCluster( ref ShapingWorkspace currentRun, CharShapeInfo currShape) { ResetClusterCop(); CharShapeInfo baseShape = currentRun.PreviousShape; // default base shape // Keep track of our current character index for checking // reordering later (when next base is detected) _firstCharIx = currentRun.CurrentCharIx; _textHasUnicodeControlChars = ((currShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) || ((baseShape & CharShapeInfo.IsUnicodeLayoutControl) != 0) ; // note any ZWNJ/ZWJ chars if ( _textHasUnicodeControlChars ) { // if this is a ZW joiner just allow whatever follows _reorderingIsSuppressed = true; } else { _baseCharClass = (ThaiCharClass)(baseShape & CharShapeInfo.ShaperClassMask); _clusterIsInvalid = IsIllegalPair(_baseCharClass,(ThaiCharClass)(currShape & CharShapeInfo.ShaperClassMask)); if (_clusterIsInvalid) { if (currentRun.PreviousChar == UnicodeCharacter.NoBreakSpace) { // if the base is a NBSP, this diacritic is acceptable (and we're done). _clusterIsInvalid = false; return false; } else { currShape |= CharShapeInfo.IsStartOfCluster; } } else { // the base class is good, we can start to process a cluster - so prepare. } } return !_clusterIsInvalid; } ////// ThaiClusterCop.ThaiClusterState: state definitions /// private enum ThaiClusterState : byte { BaseChar, AboveMarkClosestPresent, // Above mark closest to base AboveMarkClosePresent, // Second level above mark AboveMarkFurtherPresent, // Third level above mark AboveMarkFurthestPresent, // Fourth level above mark BelowMarkClosestPresent, // Below mark closest to base BelowMarkFurthestPresent, // Second level below mark UnicodeLayoutControlPresent, SaraAmPresent, NumberOfClusterStates } public static readonly int ReorderingArraySize = (int)ThaiClusterState.NumberOfClusterStates; // this table is used to determine if reordering will be required. private static readonly ThaiClusterState[] clusterStateMap = { // This maps all the Thai char classes to the corresponding cluster // state. ThaiClusterState.BaseChar, // Unknown class -- can take any diacritic ThaiClusterState.BaseChar, // AcceptsNoMark -- cannot take diacritics ThaiClusterState.AboveMarkClosestPresent, // The Am character ThaiClusterState.AboveMarkClosestPresent, // The Am character ThaiClusterState.BaseChar, // No upper diacritic is allowed. below is okay ThaiClusterState.BaseChar, // Base glyph can have diacritics ThaiClusterState.BaseChar, // space may be base of mark (only one) ThaiClusterState.AboveMarkClosestPresent, // Above mark closest to base ThaiClusterState.AboveMarkClosePresent, // Second level above mark ThaiClusterState.AboveMarkFurtherPresent, // Third level above mark ThaiClusterState.AboveMarkFurthestPresent, // Fourth level above mark ThaiClusterState.BelowMarkClosestPresent, // Below mark closest to base ThaiClusterState.BelowMarkFurthestPresent, // Second level below mark ThaiClusterState.UnicodeLayoutControlPresent, // NumberOfThaiCharClasses }; // BaseDiacriticValidationTable - table used for validating a given base/mark pair // Used to quickly determine whether a given diacritic/mark are // legal to add to a particular base type. private static ThaiCharClassFlags[] BaseDiacriticValidationTable = { 0, // unknown chars accept no marks 0, // punctuation marks accept no marks 0, // Lao am accepts no marks 0, // Thai am accepts no marks ThaiCharClassFlags.AllLowerMarks, // base accepts lower marks only ThaiCharClassFlags.AllLowerMarks | ThaiCharClassFlags.AllUpperMarks | ThaiCharClassFlags.AmChars, 0, // space char }; internal static ThaiCharClassFlags[] CharClassToFlag = { ThaiCharClassFlags.UnknownCharClass, ThaiCharClassFlags.AcceptsNoMark, ThaiCharClassFlags.LaoAmChar, // The AM character ThaiCharClassFlags.ThaiAmChar, // The AM character ThaiCharClassFlags.AcceptsLower, // No upper diacritic is allowed. below is okay ThaiCharClassFlags.AcceptsMarks, // Base glyph can have diacritics ThaiCharClassFlags.SpaceChar, // Space char may take one mark ThaiCharClassFlags.AboveMarkClosest, // Above mark closest to base ThaiCharClassFlags.AboveMarkClose, // Second level above base ThaiCharClassFlags.AboveMarkFurther, // Third level above base ThaiCharClassFlags.AboveMarkFurthest,// Fourth level above base ThaiCharClassFlags.BelowMarkClosest, // Below mark closest to base ThaiCharClassFlags.BelowMarkFurthest,// Below mark furthest from base ThaiCharClassFlags.UnicodeLayoutControl,// Unicode control chars (ZWJ, ZWNJ) }; ////// ThaiCharClassFlags - enumeration of Thai character classification flags /// ////// This enum is linked to the list of char classes in the ThaiCharClass /// enum; keep them in sync. ( [Flags()] internal enum ThaiCharClassFlags: uint { UnknownCharClass, AcceptsNoMark = 0x0001, LaoAmChar = 0x0002, // The AM character ThaiAmChar = 0x0004, // The AM character AmChars = 0x0006, // mask for am characters AcceptsLower = 0x0008, // No upper diacritic is allowed. below is okay AcceptsMarks = 0x0010, // Base glyph can have diacritics SpaceChar = 0x0020, // Space char may take one mark AllLegalBaseChars = 0x0018, // mask for all possible bases (not spaces) AllBaseChars = 0x0019, // mask for all possible bases (not spaces) AboveMarkClosest = 0x0040, // Above mark closest to base AboveMarkClose = 0x0080, // Second level above base AboveMarkFurther = 0x0100, // Third level above base AboveMarkFurthest = 0x0200, // Fourth level above base BelowMarkClosest = 0x0400, // Below mark closest to base BelowMarkFurthest = 0x0800, // Below mark furthest from base UnicodeLayoutControl = 0x1000, AllDiacritics = 0x0fc0, // mask for all diacritics AllLowerMarks = 0x0c00, // mask for lower marks AllUpperMarks = 0x03c0, // mask for upper marks }; } ///) /// There are several masks that are defined here: /// the "All..." masks are used to test the char class of a unicode char /// /// ThaiCharClassifier - The char converter for Thai/Lao. /// internal class ThaiCharClassifier : ShaperCharacterClassifier { public ThaiCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) : base(scriptTag, fontFace) { _unknownClass = UnknownCharClass; _spaceClass = (byte)ThaiCharClass.SpaceChar; _zwControlClass = (byte)ThaiCharClass.UnicodeLayoutControl; _zwjClass = (byte)ThaiCharClass.UnicodeLayoutControl; _zwnjClass = (byte)ThaiCharClass.UnicodeLayoutControl; _shyClass = UnknownCharClass; if (scriptTag == ScriptTags.Thai) { _firstChar = '\u0E00'; // this is the first Hebrew Unicode char _lastChar = '\u0E7F'; // this is the last Hebrew Unicode char _xorMask = 0xE00; // this mask is used in GetCharShapeInfo _xorRange = 0x080; // this is used in GetCharShapeInfo _charClassTable = _thaiCharClasses; } else if (scriptTag == ScriptTags.Lao) { _firstChar = '\u0E80'; _lastChar = '\u0EFF'; _xorMask = 0xE80; _xorRange = 0x080; _charClassTable = _laoCharClasses; } } ////// ShaperCharClassifier.this[] - returns CharShapeInfo for the Unicode character /// public override CharShapeInfo ToShapeInfo(char unicodeChar ) { CharShapeInfo charShape = base.ToShapeInfo(unicodeChar); return charShape; } #region Classification Tables // these consts are so the tables below will be more readable public const ThaiCharClass IsAmChar = (ThaiCharClass)CharShapeInfo.RequiresSpecialHandling; private const ThaiCharClass IsStartOfCluster = (ThaiCharClass)CharShapeInfo.IsStartOfCluster; private const byte UnknownCharClass = (byte)(ThaiCharClass.UnknownCharClass | IsStartOfCluster); private const byte AcceptsNoMark = (byte)(ThaiCharClass.AcceptsNoMark | IsStartOfCluster); private const byte BaseAcceptsLower = (byte)(ThaiCharClass.BaseAcceptsLower | IsStartOfCluster); private const byte BaseAcceptsMarks = (byte)(ThaiCharClass.BaseAcceptsMarks | IsStartOfCluster); private const byte AboveMarkClosest = (byte)ThaiCharClass.AboveMarkClosest; private const byte AboveMarkClose = (byte)ThaiCharClass.AboveMarkClose; private const byte AboveMarkFurther = (byte)ThaiCharClass.AboveMarkFurther; private const byte AboveMarkFurthest = (byte)ThaiCharClass.AboveMarkFurthest; private const byte BelowMarkClosest = (byte)ThaiCharClass.BelowMarkClosest; private const byte BelowMarkFurthest = (byte)ThaiCharClass.BelowMarkFurthest; private const byte ThaiAmChar = (byte)(ThaiCharClass.ThaiAmChar | IsAmChar); private const byte LaoAmChar = (byte)(ThaiCharClass.LaoAmChar | IsAmChar); // All the Thai Unicode chars (U+E00 - U+E7F) classified private static readonly byte[] _thaiCharClasses = //new ThaiLaoCharClass[] { // U+E00 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, // U+E10 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, // U+E20 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, AcceptsNoMark, // U+E30 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F BaseAcceptsLower, AboveMarkClosest, BaseAcceptsLower, ThaiAmChar, AboveMarkClosest, AboveMarkClosest, AboveMarkClosest, AboveMarkClosest, BelowMarkClosest, BelowMarkClosest, BelowMarkFurthest,UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, AcceptsNoMark, // U+E40 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F BaseAcceptsLower, BaseAcceptsLower, BaseAcceptsLower, BaseAcceptsLower, BaseAcceptsLower, BaseAcceptsLower, BaseAcceptsLower, AboveMarkClose, AboveMarkFurther, AboveMarkFurther, AboveMarkFurther, AboveMarkFurther, AboveMarkFurthest,AboveMarkClose, AboveMarkFurthest,AcceptsNoMark, // U+E50 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, // U+E60 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, // U+E70 (Thai Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, }; // All the Lao Unicode chars (U+E00 - U+E7F) classified private static readonly byte[] _laoCharClasses = //new ThaiLaoCharClass[] { // All the Lao Unicode chars (U+E80 - U+8FF) classifications // U+E80 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, UnknownCharClass, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, UnknownCharClass, UnknownCharClass, BaseAcceptsMarks, UnknownCharClass, UnknownCharClass, // U+E90 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, // U+EA0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, UnknownCharClass, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, AcceptsNoMark, // U+EB0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F AcceptsNoMark, AboveMarkClosest, AcceptsNoMark, LaoAmChar, AboveMarkClosest, AboveMarkClosest, AboveMarkClosest, AboveMarkClosest, BelowMarkFurthest,BelowMarkFurthest,UnknownCharClass, AboveMarkClosest, BelowMarkClosest, AcceptsNoMark, UnknownCharClass, UnknownCharClass, // U+EC0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, UnknownCharClass, AcceptsNoMark, UnknownCharClass, //0xEC0 AboveMarkClose, AboveMarkClose, AboveMarkClose, AboveMarkClose, AboveMarkClose, AboveMarkClosest, UnknownCharClass, UnknownCharClass, // U+ED0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, AcceptsNoMark, UnknownCharClass, UnknownCharClass, BaseAcceptsMarks, BaseAcceptsMarks, UnknownCharClass, UnknownCharClass, // U+EE0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, // U+EF0 (Lao Unicode) // 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, UnknownCharClass, }; #endregion // end of Classification Tables } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PerformanceCounterLib.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- AttachedPropertyBrowsableAttribute.cs
- OpenTypeLayoutCache.cs
- ControlTemplate.cs
- Clause.cs
- FontInfo.cs
- BindingOperations.cs
- BinaryObjectInfo.cs
- ImageFormat.cs
- XmlnsCache.cs
- ScrollItemProviderWrapper.cs
- DataGridViewDesigner.cs
- AttachmentService.cs
- InternalMappingException.cs
- HelpInfo.cs
- ISAPIRuntime.cs
- RSAPKCS1KeyExchangeFormatter.cs
- ConfigPathUtility.cs
- ObjectStorage.cs
- XmlValueConverter.cs
- TreeViewImageKeyConverter.cs
- WebEventTraceProvider.cs
- OrCondition.cs
- XmlDataSourceNodeDescriptor.cs
- SchemaEntity.cs
- VisualBasicSettingsHandler.cs
- MiniModule.cs
- FormViewPagerRow.cs
- DataGridViewCellCollection.cs
- TextReturnReader.cs
- NonParentingControl.cs
- OdbcInfoMessageEvent.cs
- HtmlTernaryTree.cs
- ToolStripDesignerUtils.cs
- CacheOutputQuery.cs
- NativeMethods.cs
- InvalidPropValue.cs
- ControlPaint.cs
- Table.cs
- ObjectListCommand.cs
- PartialClassGenerationTaskInternal.cs
- FilterException.cs
- BaseTemplateCodeDomTreeGenerator.cs
- UpdatePanel.cs
- ApplicationInterop.cs
- RoleGroupCollection.cs
- AsyncResult.cs
- Model3DGroup.cs
- ExtendedProtectionPolicy.cs
- HttpListenerException.cs
- DesignTimeValidationFeature.cs
- SBCSCodePageEncoding.cs
- PageCodeDomTreeGenerator.cs
- DataGridCellItemAutomationPeer.cs
- ProfileService.cs
- FramingDecoders.cs
- _FtpDataStream.cs
- EnumDataContract.cs
- URI.cs
- Vector3DAnimationBase.cs
- NavigationEventArgs.cs
- IgnoreSectionHandler.cs
- XslTransform.cs
- VisualTreeUtils.cs
- AutomationElementCollection.cs
- XmlSchemaAll.cs
- TranslateTransform.cs
- SizeIndependentAnimationStorage.cs
- SystemDiagnosticsSection.cs
- XPathItem.cs
- ToolboxComponentsCreatedEventArgs.cs
- CryptoApi.cs
- TemplateManager.cs
- ToolStripItemRenderEventArgs.cs
- PathParser.cs
- ScrollChrome.cs
- TreeNodeEventArgs.cs
- GroupedContextMenuStrip.cs
- Localizer.cs
- CheckedPointers.cs
- Vector3D.cs
- ResolveNameEventArgs.cs
- HwndMouseInputProvider.cs
- EventRoute.cs
- DbConnectionStringCommon.cs
- ToolConsole.cs
- SafeCloseHandleCritical.cs
- LayoutUtils.cs
- FunctionDetailsReader.cs
- OutputWindow.cs
- XmlSortKey.cs
- AddInSegmentDirectoryNotFoundException.cs
- PolicyUnit.cs
- PeerTransportElement.cs
- BindingExpressionUncommonField.cs
- ThumbAutomationPeer.cs
- Deserializer.cs
- Exceptions.cs
- UpnEndpointIdentityExtension.cs