Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / Shaping / mongolianshape.cs / 1 / mongolianshape.cs
//---------------------------------------------------------------------- // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation, 2004 // // File: MongolianShape.cs // // Contents: Implementation of Mongolian shaping engine and its factory // // Created: 04-15-2004 Nick Beal (nbeal) // //----------------------------------------------------------------------- using System; using System.Security; using System.Security.Permissions; using System.Diagnostics; using System.Collections; using System.Globalization; using System.Windows; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.PresentationCore; namespace MS.Internal.Shaping { ////// MongolianCharClass - enumeration of Mongolian character classifications /// ////// These values are used as weights, so the order matters. Every value /// from JoiningBase up are valid for members of a cluster (ie, chars collected /// by MongolianClusterCop.AddToCluster()). /// internal enum MongolianCharClass : byte { InvalidChar, // invalid char class -- NonJoiningBase, // character does not join NNBSP, Nirugu, // U+180a (also U+1807) VowelSeparator, ZWNJ, ZWJ, Combine, // only Mongolian diacritic Variant, // Variant selector JoiningBase, // character joins on both sides NumberOfMongolianCharClasses, }; ////// MongolianShapeClass - enumeration of Mongolian shape classifications /// ////// These values are the shaping FSM shape definitions. As the text run /// is processed the shaping FSM assigns each character a shape. /// The MongolianShapeInfo.mongolianTextFeatures array maps the first several of this enum's /// values to the appropriate OT font feature to apply to the character. /// internal enum MongolianShapeClass : byte { SameShape, UninitializedState = SameShape, // used for detecting initialization of state machine NotShaped, IsolatedShape, FinalShape, LastShapeWithStateTable = FinalShape, // used for Debug.Assert check InitialShape, MedialShape, InvalidBaseShape, }; ////// The MongolianShape, class defines the Mongolian Shaping Engine. /// internal class MongolianShape : BaseShape { ////// All required shaping Features (GSUB) /// private static readonly Feature[] _requiredFeatures = { new Feature(0,ushort.MaxValue,(uint)FeatureTags.GlyphCompositionDecomposition,1), new Feature(0,ushort.MaxValue,(uint)FeatureTags.RequiredLigatures,1), new Feature(0,ushort.MaxValue,(uint)FeatureTags.ContextualAlternates,1), }; private static readonly ScriptTags[] _supportedScripts = new ScriptTags[]{ScriptTags.Mongolian}; ////// Constructor for the Mongolian Open Type Shaping Engine. /// internal MongolianShape() { } public override ScriptTags[] SupportedScripts { get { return _supportedScripts; } } ////// MongolianShape.GetCharClassifier - Base shape /// ////// This will normally be overridden by derived shapers. It is used in OnLoadFont /// protected override ShaperCharacterClassifier GetCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) { return new MongolianCharClassifier (scriptTag, fontFace); } ////// MongolianShape.GetGlyphs - Mongolian implementation of the GetGlyphs() helper function. /// /// shaping currentRun /// Text item ///number of glyphs ////// Critical - calls critical code /// [SecurityCritical] protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item ) { bool combinerCharSeen = false;; int charsCount = 0; // initialize the features array ShaperBuffers.InitializeFeatureList(0,(ushort)_requiredFeatures.Length); if (ShaperBuffers.TextFeatures.FeaturesCount == 0) { // The first time GetGlyphs is called, add the required features // (they'll always be first in the array from now on). for (int i = 0; i < _requiredFeatures.Length; ++i) { ShaperBuffers.TextFeatures.AddFeature( _requiredFeatures[i] ); } } // initialize the cluster cop/state machine MongolianShapeFSM stateMachine = new MongolianShapeFSM( ShaperBuffers.TextFeatures ); // Shape and initialize the glyph list // process the char stream, creating shape info, applying features // as necessary CharShapeInfo currShape; while ( currentRun.GetNextShape (out currShape) ) { MongolianCharClass currClass = (MongolianCharClass)(currShape & CharShapeInfo.ShaperClassMask); if (currClass == MongolianCharClass.VowelSeparator) { // if the next character is not one of the expected vowels, then // treat this instead as a NNBSP. char nextChar = currentRun.NextChar; if (nextChar != '\u1820' && nextChar != '\u1821') { currClass = MongolianCharClass.NNBSP; } } stateMachine.StepToNextState(ref currentRun, currClass); if (currClass == MongolianCharClass.Combine) { // we can only have one combining mark per cluster, and it can't be the first character. if (combinerCharSeen || charsCount == 0) // if either of these restrictions aren't true, dotted circle time { // Set the flag so that we know to insert a dotted circle... currShape = CharShapeInfo.RequiresInsertedBase; stateMachine.ForceInvalidBaseState(); } combinerCharSeen = true; } else { combinerCharSeen = false; } currentRun.SetGlyphPropertiesUsingShapeInfo(currShape); ++charsCount; } return (currentRun.GlyphsCount); // we're done } ////// MongolianShape.ApplySubstitutionFeatures - default implementation of the GetGlyphs() helper function. /// /// shaping currentRun /// Set of gsub features to be applied to the unicode run. ///result of applying features ////// Critical - this method calls unsafe methods. /// [SecurityCritical] protected override OpenTypeLayoutResult ApplySubstitutionFeatures( ref ShapingWorkspace currentRun, FeatureSet featureSet ) { // Apply the Mongolian Text Features from currentRun ShaperFontClient fontClient = currentRun.FontClient; return fontClient.SubstituteGlyphs( ref currentRun, ShaperBuffers.TextFeatures.Features, ShaperBuffers.TextFeatures.FeaturesCount ); } } ////// MongolianShapeFSM - Mongolian shaping state machine /// ////// internal struct MongolianShapeFSM { private MongolianShapeClass _currentShape; private MongolianShapeClass _previousShape; private ushort _currentStateRowIx; private ShaperFeaturesList _featuresList; ////// MongolianShapeFSM constructor /// public MongolianShapeFSM ( ShaperFeaturesList featuresList ) { _previousShape = MongolianShapeClass.UninitializedState; _currentShape = MongolianShapeClass.NotShaped; _featuresList = featuresList; // currentStartRowIx == the first entry in the active state table for the // current base char shape. _currentStateRowIx = 0; } ////// MongolianShapeFSM.ForceInvalidBaseState - force state machine to state /// ////// This is used to force the state machine to invalid base state /// (useful when a 'dotted circle' base character is inserted) /// ////// Critical - calls critical code (UpdatePendingShape) /// [SecurityCritical] internal void ForceInvalidBaseState () { _previousShape = _currentShape = MongolianShapeClass.NotShaped; // save new shape _currentStateRowIx = _rowFirstEntryIx[ (int)MongolianCharClass.InvalidChar ]; } ////// MongolianShapeFSM.StartSyllable - start of new syllable (potentially) /// ////// This routine is used at the start of each cluster. If the base + this /// first non-base char are the valid start of a new cluster, return /// ///the starting state ///new settings for current shape info ////// Critical - possibly calls critical code (ForceInvalidBaseState) /// [SecurityCritical] private void SetStartState ( ref ShapingWorkspace currentRun, MongolianCharClass firstCharClass ) { Debug.Assert (_currentShape == MongolianShapeClass.NotShaped && _currentStateRowIx == 0 , "Mongolian FSM SetStartState should not be called now."); _previousShape = _currentShape; switch (firstCharClass) { case MongolianCharClass.Combine: case MongolianCharClass.Variant: case MongolianCharClass.VowelSeparator: ForceInvalidBaseState (); break; case MongolianCharClass.JoiningBase: // Joining base chars mean that the starting shape state is not NotShaped... _currentShape = (currentRun.CurrentCharIx == 0 && currentRun.HasLeadingJoin) ? MongolianShapeClass.FinalShape : MongolianShapeClass.IsolatedShape; _currentStateRowIx = _baseTableFirstEntryIx[ (int)_currentShape ]; _featuresList.AddFeature(currentRun.CurrentCharIx, _mongolianTextFeatures[(int)_currentShape]); break; default: _currentStateRowIx = _rowFirstEntryIx[ (int)firstCharClass ]; break; } } ////// MongolianShapeFSM.StepToNextState - process the latest character. /// ////// This routine steps the state machine to its next state /// based on the current state, the last character that caused a /// state change and the next char. It may affect the previous character's /// shape if the feature id which is embedded in the shape info needs to be /// changed. /// ///new settings for current shape info ////// Critical - calls critical code, uses unsafe accessors /// [SecurityCritical] internal void StepToNextState ( ref ShapingWorkspace currentRun, MongolianCharClass nextCharClass ) { Debug.Assert ( (int)nextCharClass < NumberOfCharClasses ); if ( _currentShape != MongolianShapeClass.SameShape ) { if (_previousShape == MongolianShapeClass.UninitializedState) { SetStartState(ref currentRun, nextCharClass); return; } } // The state tables are abbreviated (only enough rows per state to cover // the events that are valid for the current state. So, first check if // we should be looking up the next state in the state table. // get the shape state table entry. byte shapeTableEntry = _mongolianShapeStateTable[ _currentStateRowIx + (int)nextCharClass ]; switch (shapeTableEntry) { case NoChange: // this means this latest character doesn't affect the current state AT ALL. break; case ToInvalidBase: ForceInvalidBaseState(); break; default: // keep track of where we're coming from. _previousShape = _currentShape; // change our state (or shape) _currentShape = (MongolianShapeClass) (shapeTableEntry & 0xf); Debug.Assert(_currentShape <= MongolianShapeClass.LastShapeWithStateTable); // adjust the state table indices.. _currentStateRowIx = (ushort)( _baseTableFirstEntryIx[ (int)_currentShape ] + _rowFirstEntryIx[ (int)nextCharClass ]); break; } UpdateShapeInfo(ref currentRun, shapeTableEntry); } ////// MongolianShapeFSM.UpdateShapeInfo - process the latest character. /// ////// This routine returns the new shape state based on the newest /// state info /// ///shape info for this character private void UpdateShapeInfo ( ref ShapingWorkspace currentRun, byte shapeTableEntry ) { // update the previous shape information. Check if the upper nibble of shapeTableEntry // holds information for updating the previous shape; if not, then we only will be // setting this char's shape. if ((shapeTableEntry >> 4) != NoChange) { _previousShape = (MongolianShapeClass) (shapeTableEntry >> 4); // update the previous shape's feature tag. If this updated feature tag matches // the latestCountedFeature, then its not a new feature. // For example, in the following sequence... // // Event Feature Tags: // 1st char processed, set to Isolated form Iso N.A N.A. N.A. // 2nd char, changes 1st form, sets own form Ini Final N.A. N.A. // 3rd char, changes 2nd form, set own Ini Mid Final N.A. // 4th char, changes 3rd form, sets own Ini Mid Mid Final // // ... we expect the "start of feature" flag to be set on the 1st, 2nd, and 4th // shapes (once we've processed all four chars) _featuresList.UpdatePreviousShapedChar(_mongolianTextFeatures[(int)_previousShape]); } _featuresList.AddFeature( currentRun.CurrentCharIx, shapeTableEntry == NoChange ? (uint)MongolianShapeClass.SameShape : _mongolianTextFeatures[(int)_currentShape] ); return; } // these const's are for making the mongolianShapeStateTable more // readable. private const byte NoChange = (byte)MongolianShapeClass.SameShape; private const byte NotShaped = (byte)MongolianShapeClass.NotShaped; private const byte Isolated = (byte) MongolianShapeClass.IsolatedShape; private const byte Final = (byte) MongolianShapeClass.FinalShape; private const byte NoChangeToPriorShape = NoChange << 4; private const byte ToNotShaped = NoChangeToPriorShape | NotShaped; private const byte ToIsolated = NoChangeToPriorShape | Isolated; private const byte ToFinal = NoChangeToPriorShape | Final; private const byte FromIsolatedShape = (byte) MongolianShapeClass.IsolatedShape << 4; private const byte IsolatedToNotShaped = FromIsolatedShape | NotShaped; private const byte IsolatedToIsolated = FromIsolatedShape | Isolated; private const byte FromInitialShape = (byte) MongolianShapeClass.InitialShape << 4; private const byte InitialToNotShaped = FromInitialShape | NotShaped; private const byte InitialToFinal = FromInitialShape | Final; private const byte FromMedialShape = (byte) MongolianShapeClass.MedialShape << 4; private const byte MedialToNotShaped = FromMedialShape | NotShaped; private const byte MedialToFinal = FromMedialShape | Final; private const byte FromFinalShape = (byte) MongolianShapeClass.FinalShape << 4; private const byte FinalToNotShaped = FromFinalShape | NotShaped; private const byte InvalidBase = (byte)MongolianShapeClass.InvalidBaseShape << 4; private const byte ToInvalidBase = InvalidBase | NotShaped; private const int NumberOfCharClasses = (int) MongolianCharClass.NumberOfMongolianCharClasses; // This is the Mongolian shape state table. private static readonly byte[] _mongolianShapeStateTable = { // Current state is NotShaped... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current NoChange, ToNotShaped, ToNotShaped, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToIsolated, // 0-INVALID BASE ToInvalidBase, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToIsolated, // 1-NONJOINING ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToFinal, // 2-NNBSP ToInvalidBase, ToNotShaped, ToNotShaped, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToFinal, // 3-NIRUGU ToInvalidBase, ToNotShaped, ToNotShaped, ToInvalidBase,ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase,ToFinal, // 4-VOWEL SEPARATOR ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase, NoChange, NoChange, ToIsolated, // 5-ZWNJ ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase, NoChange, NoChange, ToFinal, // 6-ZWJ // Current state is Isolated Shape... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current ToNotShaped, ToNotShaped, ToNotShaped, InitialToNotShaped,ToNotShaped,ToNotShaped,InitialToNotShaped,NoChange, NoChange, InitialToFinal, // JOINING // Current state is Final Shape... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current ToNotShaped, ToNotShaped, MedialToNotShaped,MedialToFinal, ToNotShaped, ToNotShaped, MedialToNotShaped,NoChange, NoChange, MedialToFinal,// JOINING ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,ToInvalidBase, ToInvalidBase,ToInvalidBase,ToInvalidBase,// NONJOINING (impossible to get here) ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,ToInvalidBase, ToInvalidBase,ToInvalidBase,ToInvalidBase,// NNBSP (impossible to get here) ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, MedialToNotShaped,ToNotShaped,ToNotShaped,MedialToFinal,// NIRUGU }; // This array has the starting offset for the 'current char class'. This // offset is relative to the first entry in the current shape state in whatever // state lookup table is active. This table is used instead of multiplying the current // row value by 9 every time we access the shape state table. This is // used when the current state is NotShaped. private static readonly ushort[] _rowFirstEntryIx = { 0, // DottedCircle 1 * (int)NumberOfCharClasses, // NonJoiningBase 2 * (int)NumberOfCharClasses, // NNBSP 3 * (int)NumberOfCharClasses, // Nirugu 4 * (int)NumberOfCharClasses, // VowelSeparator 5 * (int)NumberOfCharClasses, // ZWNJ 6 * (int)NumberOfCharClasses, // ZWJ 0 * (int)NumberOfCharClasses, // Combine 0 * (int)NumberOfCharClasses, // Variant 0 * (int)NumberOfCharClasses, // Joining }; // this array has the starting offset for the current shape state. This // offset is relative to the first entry in _baseCharShapeStateTable[]. The // numbers are 'tally of all previous shape rows X 9 entries per row'. private static readonly ushort[] _baseTableFirstEntryIx = { 0, // SameShape 0, // NotShaped 7 * (int)NumberOfCharClasses, // IsolatedShape 8 * (int)NumberOfCharClasses, // FinalShape }; private static readonly uint[] _mongolianTextFeatures = { 0, // Same (this is required by ShaperFeaturesList) 1, // NotShaped (this is required by ShaperFeaturesList) (uint)FeatureTags.IsolatedForms, // IsolatedShape (uint)FeatureTags.TerminalForms, // FinalShape (uint)FeatureTags.InitialForms, // InitialShape (uint)FeatureTags.MedialForms, // MedialShape 1, // InvalidBaseShape (this is required by ShaperFeaturesList) }; } ////// MongolianCharClassifier - /// internal class MongolianCharClassifier : ShaperCharacterClassifier { private ushort _mvsGlyph; private ushort _vs1Glyph; private ushort _vs2Glyph; private ushort _vs3Glyph; public MongolianCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) : base(scriptTag, fontFace) { _unknownClass = InvalidChar; _spaceClass = NonJoiningBase; _zwControlClass = NonJoiningBase; _zwjClass = JoiningBase; _zwnjClass = NonJoiningBase; _shyClass = InvalidChar; _firstChar = '\u1800'; // this is the first Hebrew Unicode char _lastChar = '\u18AF'; // this is the last Hebrew Unicode char _xorMask = 0x1800; // this mask is used in GetCharShapeInfo _xorRange = 0x0b0; // this is used in GetCharShapeInfo _charClassTable = _mongolianCharClasses; } ////// MongolianCharClassifier.ToShapeInfo - returns CharShapeInfo for the Unicode character /// public override CharShapeInfo ToShapeInfo (char unicodeChar ) { CharShapeInfo charShape; if (unicodeChar == UnicodeCharacter.NarrowNoBreakSpace) { charShape = (CharShapeInfo)((byte)StartOfCluster | (byte)MongolianCharClass.NNBSP); } else { charShape = base.ToShapeInfo(unicodeChar); if (unicodeChar >= '\u180b' && unicodeChar <= '\u180e') { charShape |= CharShapeInfo.IsUnicodeLayoutControl; } } return charShape; } ////// SetUnicodeControlGlyph - called to save local copy of pertinent glyph ids /// ////// This function is called by ShapingWorkspace when a Unicode control /// character is detected in the text run. This allows us to cache /// the glyph id for use in IsUnicodeControlGlyph (which may be used /// to suppress the display of Unicode control characters). This /// overrided function allows us to save the glyph id's of the /// Mongolian control characters /// public override void SetUnicodeControlGlyph (char unicodeChar, ushort glyph) { if (glyph != 0) { switch (unicodeChar) { case '\u180b': // Variant1 _vs1Glyph = glyph; break; case '\u180c': // Variant2 _vs2Glyph = glyph; break; case '\u180d': // Variant3 _vs3Glyph = glyph; break; case '\u180e': // VowelSeparator _mvsGlyph = glyph; break; default: base.SetUnicodeControlGlyph(unicodeChar, glyph); break; } } } public override bool IsUnicodeControlGlyph( ushort glyph ) { if (glyph != 0) { if (glyph == _mvsGlyph || glyph == _vs1Glyph || glyph == _vs2Glyph || glyph == _vs3Glyph) { return true; } } return base.IsUnicodeControlGlyph (glyph); } #region Classification Tables // these consts are so the tables below will be more readable private const MongolianCharClass StartOfCluster = (MongolianCharClass)CharShapeInfo.IsStartOfCluster; private const byte InvalidChar = (byte)(MongolianCharClass.InvalidChar | StartOfCluster); private const byte NonJoiningBase = (byte)(MongolianCharClass.NonJoiningBase | StartOfCluster); private const byte JoiningBase = (byte)(MongolianCharClass.JoiningBase | StartOfCluster); private const byte Combine = (byte)MongolianCharClass.Combine; private const byte Variant = (byte)MongolianCharClass.Variant; private const byte VowelSeparator = (byte)(MongolianCharClass.VowelSeparator | StartOfCluster); private const byte Nirugu = (byte)(MongolianCharClass.Nirugu | StartOfCluster); static byte[] _mongolianCharClasses = { // Mongolian //180 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, Nirugu, NonJoiningBase, NonJoiningBase, Nirugu, Variant, Variant, Variant, VowelSeparator, InvalidChar, //181 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, //182 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //183 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //184 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //185 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //186 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //187 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, //188 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //189 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //18A 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, Combine, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, }; #endregion // end of Classification Tables } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------- // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation, 2004 // // File: MongolianShape.cs // // Contents: Implementation of Mongolian shaping engine and its factory // // Created: 04-15-2004 Nick Beal (nbeal) // //----------------------------------------------------------------------- using System; using System.Security; using System.Security.Permissions; using System.Diagnostics; using System.Collections; using System.Globalization; using System.Windows; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.PresentationCore; namespace MS.Internal.Shaping { ////// MongolianCharClass - enumeration of Mongolian character classifications /// ////// These values are used as weights, so the order matters. Every value /// from JoiningBase up are valid for members of a cluster (ie, chars collected /// by MongolianClusterCop.AddToCluster()). /// internal enum MongolianCharClass : byte { InvalidChar, // invalid char class -- NonJoiningBase, // character does not join NNBSP, Nirugu, // U+180a (also U+1807) VowelSeparator, ZWNJ, ZWJ, Combine, // only Mongolian diacritic Variant, // Variant selector JoiningBase, // character joins on both sides NumberOfMongolianCharClasses, }; ////// MongolianShapeClass - enumeration of Mongolian shape classifications /// ////// These values are the shaping FSM shape definitions. As the text run /// is processed the shaping FSM assigns each character a shape. /// The MongolianShapeInfo.mongolianTextFeatures array maps the first several of this enum's /// values to the appropriate OT font feature to apply to the character. /// internal enum MongolianShapeClass : byte { SameShape, UninitializedState = SameShape, // used for detecting initialization of state machine NotShaped, IsolatedShape, FinalShape, LastShapeWithStateTable = FinalShape, // used for Debug.Assert check InitialShape, MedialShape, InvalidBaseShape, }; ////// The MongolianShape, class defines the Mongolian Shaping Engine. /// internal class MongolianShape : BaseShape { ////// All required shaping Features (GSUB) /// private static readonly Feature[] _requiredFeatures = { new Feature(0,ushort.MaxValue,(uint)FeatureTags.GlyphCompositionDecomposition,1), new Feature(0,ushort.MaxValue,(uint)FeatureTags.RequiredLigatures,1), new Feature(0,ushort.MaxValue,(uint)FeatureTags.ContextualAlternates,1), }; private static readonly ScriptTags[] _supportedScripts = new ScriptTags[]{ScriptTags.Mongolian}; ////// Constructor for the Mongolian Open Type Shaping Engine. /// internal MongolianShape() { } public override ScriptTags[] SupportedScripts { get { return _supportedScripts; } } ////// MongolianShape.GetCharClassifier - Base shape /// ////// This will normally be overridden by derived shapers. It is used in OnLoadFont /// protected override ShaperCharacterClassifier GetCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) { return new MongolianCharClassifier (scriptTag, fontFace); } ////// MongolianShape.GetGlyphs - Mongolian implementation of the GetGlyphs() helper function. /// /// shaping currentRun /// Text item ///number of glyphs ////// Critical - calls critical code /// [SecurityCritical] protected override int GetGlyphs ( ref ShapingWorkspace currentRun, Item item ) { bool combinerCharSeen = false;; int charsCount = 0; // initialize the features array ShaperBuffers.InitializeFeatureList(0,(ushort)_requiredFeatures.Length); if (ShaperBuffers.TextFeatures.FeaturesCount == 0) { // The first time GetGlyphs is called, add the required features // (they'll always be first in the array from now on). for (int i = 0; i < _requiredFeatures.Length; ++i) { ShaperBuffers.TextFeatures.AddFeature( _requiredFeatures[i] ); } } // initialize the cluster cop/state machine MongolianShapeFSM stateMachine = new MongolianShapeFSM( ShaperBuffers.TextFeatures ); // Shape and initialize the glyph list // process the char stream, creating shape info, applying features // as necessary CharShapeInfo currShape; while ( currentRun.GetNextShape (out currShape) ) { MongolianCharClass currClass = (MongolianCharClass)(currShape & CharShapeInfo.ShaperClassMask); if (currClass == MongolianCharClass.VowelSeparator) { // if the next character is not one of the expected vowels, then // treat this instead as a NNBSP. char nextChar = currentRun.NextChar; if (nextChar != '\u1820' && nextChar != '\u1821') { currClass = MongolianCharClass.NNBSP; } } stateMachine.StepToNextState(ref currentRun, currClass); if (currClass == MongolianCharClass.Combine) { // we can only have one combining mark per cluster, and it can't be the first character. if (combinerCharSeen || charsCount == 0) // if either of these restrictions aren't true, dotted circle time { // Set the flag so that we know to insert a dotted circle... currShape = CharShapeInfo.RequiresInsertedBase; stateMachine.ForceInvalidBaseState(); } combinerCharSeen = true; } else { combinerCharSeen = false; } currentRun.SetGlyphPropertiesUsingShapeInfo(currShape); ++charsCount; } return (currentRun.GlyphsCount); // we're done } ////// MongolianShape.ApplySubstitutionFeatures - default implementation of the GetGlyphs() helper function. /// /// shaping currentRun /// Set of gsub features to be applied to the unicode run. ///result of applying features ////// Critical - this method calls unsafe methods. /// [SecurityCritical] protected override OpenTypeLayoutResult ApplySubstitutionFeatures( ref ShapingWorkspace currentRun, FeatureSet featureSet ) { // Apply the Mongolian Text Features from currentRun ShaperFontClient fontClient = currentRun.FontClient; return fontClient.SubstituteGlyphs( ref currentRun, ShaperBuffers.TextFeatures.Features, ShaperBuffers.TextFeatures.FeaturesCount ); } } ////// MongolianShapeFSM - Mongolian shaping state machine /// ////// internal struct MongolianShapeFSM { private MongolianShapeClass _currentShape; private MongolianShapeClass _previousShape; private ushort _currentStateRowIx; private ShaperFeaturesList _featuresList; ////// MongolianShapeFSM constructor /// public MongolianShapeFSM ( ShaperFeaturesList featuresList ) { _previousShape = MongolianShapeClass.UninitializedState; _currentShape = MongolianShapeClass.NotShaped; _featuresList = featuresList; // currentStartRowIx == the first entry in the active state table for the // current base char shape. _currentStateRowIx = 0; } ////// MongolianShapeFSM.ForceInvalidBaseState - force state machine to state /// ////// This is used to force the state machine to invalid base state /// (useful when a 'dotted circle' base character is inserted) /// ////// Critical - calls critical code (UpdatePendingShape) /// [SecurityCritical] internal void ForceInvalidBaseState () { _previousShape = _currentShape = MongolianShapeClass.NotShaped; // save new shape _currentStateRowIx = _rowFirstEntryIx[ (int)MongolianCharClass.InvalidChar ]; } ////// MongolianShapeFSM.StartSyllable - start of new syllable (potentially) /// ////// This routine is used at the start of each cluster. If the base + this /// first non-base char are the valid start of a new cluster, return /// ///the starting state ///new settings for current shape info ////// Critical - possibly calls critical code (ForceInvalidBaseState) /// [SecurityCritical] private void SetStartState ( ref ShapingWorkspace currentRun, MongolianCharClass firstCharClass ) { Debug.Assert (_currentShape == MongolianShapeClass.NotShaped && _currentStateRowIx == 0 , "Mongolian FSM SetStartState should not be called now."); _previousShape = _currentShape; switch (firstCharClass) { case MongolianCharClass.Combine: case MongolianCharClass.Variant: case MongolianCharClass.VowelSeparator: ForceInvalidBaseState (); break; case MongolianCharClass.JoiningBase: // Joining base chars mean that the starting shape state is not NotShaped... _currentShape = (currentRun.CurrentCharIx == 0 && currentRun.HasLeadingJoin) ? MongolianShapeClass.FinalShape : MongolianShapeClass.IsolatedShape; _currentStateRowIx = _baseTableFirstEntryIx[ (int)_currentShape ]; _featuresList.AddFeature(currentRun.CurrentCharIx, _mongolianTextFeatures[(int)_currentShape]); break; default: _currentStateRowIx = _rowFirstEntryIx[ (int)firstCharClass ]; break; } } ////// MongolianShapeFSM.StepToNextState - process the latest character. /// ////// This routine steps the state machine to its next state /// based on the current state, the last character that caused a /// state change and the next char. It may affect the previous character's /// shape if the feature id which is embedded in the shape info needs to be /// changed. /// ///new settings for current shape info ////// Critical - calls critical code, uses unsafe accessors /// [SecurityCritical] internal void StepToNextState ( ref ShapingWorkspace currentRun, MongolianCharClass nextCharClass ) { Debug.Assert ( (int)nextCharClass < NumberOfCharClasses ); if ( _currentShape != MongolianShapeClass.SameShape ) { if (_previousShape == MongolianShapeClass.UninitializedState) { SetStartState(ref currentRun, nextCharClass); return; } } // The state tables are abbreviated (only enough rows per state to cover // the events that are valid for the current state. So, first check if // we should be looking up the next state in the state table. // get the shape state table entry. byte shapeTableEntry = _mongolianShapeStateTable[ _currentStateRowIx + (int)nextCharClass ]; switch (shapeTableEntry) { case NoChange: // this means this latest character doesn't affect the current state AT ALL. break; case ToInvalidBase: ForceInvalidBaseState(); break; default: // keep track of where we're coming from. _previousShape = _currentShape; // change our state (or shape) _currentShape = (MongolianShapeClass) (shapeTableEntry & 0xf); Debug.Assert(_currentShape <= MongolianShapeClass.LastShapeWithStateTable); // adjust the state table indices.. _currentStateRowIx = (ushort)( _baseTableFirstEntryIx[ (int)_currentShape ] + _rowFirstEntryIx[ (int)nextCharClass ]); break; } UpdateShapeInfo(ref currentRun, shapeTableEntry); } ////// MongolianShapeFSM.UpdateShapeInfo - process the latest character. /// ////// This routine returns the new shape state based on the newest /// state info /// ///shape info for this character private void UpdateShapeInfo ( ref ShapingWorkspace currentRun, byte shapeTableEntry ) { // update the previous shape information. Check if the upper nibble of shapeTableEntry // holds information for updating the previous shape; if not, then we only will be // setting this char's shape. if ((shapeTableEntry >> 4) != NoChange) { _previousShape = (MongolianShapeClass) (shapeTableEntry >> 4); // update the previous shape's feature tag. If this updated feature tag matches // the latestCountedFeature, then its not a new feature. // For example, in the following sequence... // // Event Feature Tags: // 1st char processed, set to Isolated form Iso N.A N.A. N.A. // 2nd char, changes 1st form, sets own form Ini Final N.A. N.A. // 3rd char, changes 2nd form, set own Ini Mid Final N.A. // 4th char, changes 3rd form, sets own Ini Mid Mid Final // // ... we expect the "start of feature" flag to be set on the 1st, 2nd, and 4th // shapes (once we've processed all four chars) _featuresList.UpdatePreviousShapedChar(_mongolianTextFeatures[(int)_previousShape]); } _featuresList.AddFeature( currentRun.CurrentCharIx, shapeTableEntry == NoChange ? (uint)MongolianShapeClass.SameShape : _mongolianTextFeatures[(int)_currentShape] ); return; } // these const's are for making the mongolianShapeStateTable more // readable. private const byte NoChange = (byte)MongolianShapeClass.SameShape; private const byte NotShaped = (byte)MongolianShapeClass.NotShaped; private const byte Isolated = (byte) MongolianShapeClass.IsolatedShape; private const byte Final = (byte) MongolianShapeClass.FinalShape; private const byte NoChangeToPriorShape = NoChange << 4; private const byte ToNotShaped = NoChangeToPriorShape | NotShaped; private const byte ToIsolated = NoChangeToPriorShape | Isolated; private const byte ToFinal = NoChangeToPriorShape | Final; private const byte FromIsolatedShape = (byte) MongolianShapeClass.IsolatedShape << 4; private const byte IsolatedToNotShaped = FromIsolatedShape | NotShaped; private const byte IsolatedToIsolated = FromIsolatedShape | Isolated; private const byte FromInitialShape = (byte) MongolianShapeClass.InitialShape << 4; private const byte InitialToNotShaped = FromInitialShape | NotShaped; private const byte InitialToFinal = FromInitialShape | Final; private const byte FromMedialShape = (byte) MongolianShapeClass.MedialShape << 4; private const byte MedialToNotShaped = FromMedialShape | NotShaped; private const byte MedialToFinal = FromMedialShape | Final; private const byte FromFinalShape = (byte) MongolianShapeClass.FinalShape << 4; private const byte FinalToNotShaped = FromFinalShape | NotShaped; private const byte InvalidBase = (byte)MongolianShapeClass.InvalidBaseShape << 4; private const byte ToInvalidBase = InvalidBase | NotShaped; private const int NumberOfCharClasses = (int) MongolianCharClass.NumberOfMongolianCharClasses; // This is the Mongolian shape state table. private static readonly byte[] _mongolianShapeStateTable = { // Current state is NotShaped... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current NoChange, ToNotShaped, ToNotShaped, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToIsolated, // 0-INVALID BASE ToInvalidBase, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToIsolated, // 1-NONJOINING ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToFinal, // 2-NNBSP ToInvalidBase, ToNotShaped, ToNotShaped, NoChange, ToNotShaped, ToNotShaped, ToNotShaped, NoChange, NoChange, ToFinal, // 3-NIRUGU ToInvalidBase, ToNotShaped, ToNotShaped, ToInvalidBase,ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase,ToFinal, // 4-VOWEL SEPARATOR ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase, NoChange, NoChange, ToIsolated, // 5-ZWNJ ToInvalidBase, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToInvalidBase,ToInvalidBase, NoChange, NoChange, ToFinal, // 6-ZWJ // Current state is Isolated Shape... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current ToNotShaped, ToNotShaped, ToNotShaped, InitialToNotShaped,ToNotShaped,ToNotShaped,InitialToNotShaped,NoChange, NoChange, InitialToFinal, // JOINING // Current state is Final Shape... // 0 (Invalid) 1 (NonJoining) 2 (NNBSP) 3 (Nirugu) 4 (VS) 5 (ZWNJ) 6 (ZWJ) 7 (Combine) 8 (Variant) 9 (Joining) Next/ Current ToNotShaped, ToNotShaped, MedialToNotShaped,MedialToFinal, ToNotShaped, ToNotShaped, MedialToNotShaped,NoChange, NoChange, MedialToFinal,// JOINING ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,ToInvalidBase, ToInvalidBase,ToInvalidBase,ToInvalidBase,// NONJOINING (impossible to get here) ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase, ToInvalidBase,ToInvalidBase, ToInvalidBase,ToInvalidBase,ToInvalidBase,// NNBSP (impossible to get here) ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, ToNotShaped, MedialToNotShaped,ToNotShaped,ToNotShaped,MedialToFinal,// NIRUGU }; // This array has the starting offset for the 'current char class'. This // offset is relative to the first entry in the current shape state in whatever // state lookup table is active. This table is used instead of multiplying the current // row value by 9 every time we access the shape state table. This is // used when the current state is NotShaped. private static readonly ushort[] _rowFirstEntryIx = { 0, // DottedCircle 1 * (int)NumberOfCharClasses, // NonJoiningBase 2 * (int)NumberOfCharClasses, // NNBSP 3 * (int)NumberOfCharClasses, // Nirugu 4 * (int)NumberOfCharClasses, // VowelSeparator 5 * (int)NumberOfCharClasses, // ZWNJ 6 * (int)NumberOfCharClasses, // ZWJ 0 * (int)NumberOfCharClasses, // Combine 0 * (int)NumberOfCharClasses, // Variant 0 * (int)NumberOfCharClasses, // Joining }; // this array has the starting offset for the current shape state. This // offset is relative to the first entry in _baseCharShapeStateTable[]. The // numbers are 'tally of all previous shape rows X 9 entries per row'. private static readonly ushort[] _baseTableFirstEntryIx = { 0, // SameShape 0, // NotShaped 7 * (int)NumberOfCharClasses, // IsolatedShape 8 * (int)NumberOfCharClasses, // FinalShape }; private static readonly uint[] _mongolianTextFeatures = { 0, // Same (this is required by ShaperFeaturesList) 1, // NotShaped (this is required by ShaperFeaturesList) (uint)FeatureTags.IsolatedForms, // IsolatedShape (uint)FeatureTags.TerminalForms, // FinalShape (uint)FeatureTags.InitialForms, // InitialShape (uint)FeatureTags.MedialForms, // MedialShape 1, // InvalidBaseShape (this is required by ShaperFeaturesList) }; } ////// MongolianCharClassifier - /// internal class MongolianCharClassifier : ShaperCharacterClassifier { private ushort _mvsGlyph; private ushort _vs1Glyph; private ushort _vs2Glyph; private ushort _vs3Glyph; public MongolianCharClassifier(ScriptTags scriptTag, GlyphTypeface fontFace) : base(scriptTag, fontFace) { _unknownClass = InvalidChar; _spaceClass = NonJoiningBase; _zwControlClass = NonJoiningBase; _zwjClass = JoiningBase; _zwnjClass = NonJoiningBase; _shyClass = InvalidChar; _firstChar = '\u1800'; // this is the first Hebrew Unicode char _lastChar = '\u18AF'; // this is the last Hebrew Unicode char _xorMask = 0x1800; // this mask is used in GetCharShapeInfo _xorRange = 0x0b0; // this is used in GetCharShapeInfo _charClassTable = _mongolianCharClasses; } ////// MongolianCharClassifier.ToShapeInfo - returns CharShapeInfo for the Unicode character /// public override CharShapeInfo ToShapeInfo (char unicodeChar ) { CharShapeInfo charShape; if (unicodeChar == UnicodeCharacter.NarrowNoBreakSpace) { charShape = (CharShapeInfo)((byte)StartOfCluster | (byte)MongolianCharClass.NNBSP); } else { charShape = base.ToShapeInfo(unicodeChar); if (unicodeChar >= '\u180b' && unicodeChar <= '\u180e') { charShape |= CharShapeInfo.IsUnicodeLayoutControl; } } return charShape; } ////// SetUnicodeControlGlyph - called to save local copy of pertinent glyph ids /// ////// This function is called by ShapingWorkspace when a Unicode control /// character is detected in the text run. This allows us to cache /// the glyph id for use in IsUnicodeControlGlyph (which may be used /// to suppress the display of Unicode control characters). This /// overrided function allows us to save the glyph id's of the /// Mongolian control characters /// public override void SetUnicodeControlGlyph (char unicodeChar, ushort glyph) { if (glyph != 0) { switch (unicodeChar) { case '\u180b': // Variant1 _vs1Glyph = glyph; break; case '\u180c': // Variant2 _vs2Glyph = glyph; break; case '\u180d': // Variant3 _vs3Glyph = glyph; break; case '\u180e': // VowelSeparator _mvsGlyph = glyph; break; default: base.SetUnicodeControlGlyph(unicodeChar, glyph); break; } } } public override bool IsUnicodeControlGlyph( ushort glyph ) { if (glyph != 0) { if (glyph == _mvsGlyph || glyph == _vs1Glyph || glyph == _vs2Glyph || glyph == _vs3Glyph) { return true; } } return base.IsUnicodeControlGlyph (glyph); } #region Classification Tables // these consts are so the tables below will be more readable private const MongolianCharClass StartOfCluster = (MongolianCharClass)CharShapeInfo.IsStartOfCluster; private const byte InvalidChar = (byte)(MongolianCharClass.InvalidChar | StartOfCluster); private const byte NonJoiningBase = (byte)(MongolianCharClass.NonJoiningBase | StartOfCluster); private const byte JoiningBase = (byte)(MongolianCharClass.JoiningBase | StartOfCluster); private const byte Combine = (byte)MongolianCharClass.Combine; private const byte Variant = (byte)MongolianCharClass.Variant; private const byte VowelSeparator = (byte)(MongolianCharClass.VowelSeparator | StartOfCluster); private const byte Nirugu = (byte)(MongolianCharClass.Nirugu | StartOfCluster); static byte[] _mongolianCharClasses = { // Mongolian //180 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, Nirugu, NonJoiningBase, NonJoiningBase, Nirugu, Variant, Variant, Variant, VowelSeparator, InvalidChar, //181 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, //182 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //183 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //184 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //185 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //186 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //187 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, //188 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, NonJoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //189 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, //18A 0, 4, 8, C 1, 5, 9, D 2, 6, A, E 3, 7, B, F JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, JoiningBase, Combine, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, InvalidChar, }; #endregion // end of Classification Tables } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FrameworkElementFactory.cs
- ElementProxy.cs
- SerialErrors.cs
- TransformConverter.cs
- DataAdapter.cs
- PtsCache.cs
- XmlQueryCardinality.cs
- AmbiguousMatchException.cs
- odbcmetadatacolumnnames.cs
- RichTextBox.cs
- VariantWrapper.cs
- HtmlButton.cs
- BufferedGraphicsContext.cs
- Drawing.cs
- WebPartManagerInternals.cs
- StrongName.cs
- AssemblyHash.cs
- loginstatus.cs
- ComboBoxItem.cs
- SchemaElementDecl.cs
- DataStorage.cs
- ResetableIterator.cs
- SqlColumnizer.cs
- RegexStringValidatorAttribute.cs
- StaticResourceExtension.cs
- Setter.cs
- Rotation3DAnimation.cs
- SqlDataSource.cs
- CollectionEditor.cs
- FactoryMaker.cs
- XmlReflectionImporter.cs
- PointCollectionConverter.cs
- UpdatePanelTrigger.cs
- Size3DValueSerializer.cs
- RawKeyboardInputReport.cs
- TabItemAutomationPeer.cs
- RegexMatchCollection.cs
- SpellCheck.cs
- VersionedStream.cs
- ActivitiesCollection.cs
- PeerObject.cs
- SocketElement.cs
- ClassicBorderDecorator.cs
- Control.cs
- SurrogateChar.cs
- ThemeableAttribute.cs
- MenuScrollingVisibilityConverter.cs
- StorageModelBuildProvider.cs
- SingleQueryOperator.cs
- Switch.cs
- CodeAttributeDeclarationCollection.cs
- DesignerActionKeyboardBehavior.cs
- BaseParser.cs
- MatrixAnimationUsingKeyFrames.cs
- StorageRoot.cs
- CfgArc.cs
- XmlSerializerAssemblyAttribute.cs
- ArrayList.cs
- RuntimeConfigLKG.cs
- AbstractSvcMapFileLoader.cs
- CurrentChangingEventArgs.cs
- SizeChangedInfo.cs
- XmlAnyElementAttributes.cs
- ObjectListCommand.cs
- Int16.cs
- CharEntityEncoderFallback.cs
- CodeMemberEvent.cs
- LinqDataSourceView.cs
- DatePickerDateValidationErrorEventArgs.cs
- FixedSOMContainer.cs
- SqlDataAdapter.cs
- Pool.cs
- WindowsTab.cs
- Operand.cs
- OutKeywords.cs
- ThemeableAttribute.cs
- ResourceSetExpression.cs
- TextContainerHelper.cs
- ThreadPool.cs
- TableRowGroup.cs
- FontCacheUtil.cs
- OdbcInfoMessageEvent.cs
- HttpContext.cs
- EmptyStringExpandableObjectConverter.cs
- SQLByteStorage.cs
- PreloadedPackages.cs
- CompilerInfo.cs
- IisHelper.cs
- IPPacketInformation.cs
- WebHeaderCollection.cs
- DataProviderNameConverter.cs
- UnaryNode.cs
- Byte.cs
- SqlDataSourceEnumerator.cs
- IntSecurity.cs
- BookmarkList.cs
- XmlQueryCardinality.cs
- DataGridItem.cs
- MetadataPropertyAttribute.cs
- ProfileParameter.cs