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.
/// 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.
///
internal struct ThaiClusterCop
{
private ThaiCharClass _baseCharClass; // base char's class info
///
/// 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. ( )
/// There are several masks that are defined here:
/// the "All..." masks are used to test the char class of a unicode char
///
[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
};
}
///
/// 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
- JsonReaderWriterFactory.cs
- FileDialogPermission.cs
- X509IssuerSerialKeyIdentifierClause.cs
- Registry.cs
- WsrmFault.cs
- Lazy.cs
- SqlRowUpdatingEvent.cs
- securitycriticaldataClass.cs
- TextureBrush.cs
- DeclarativeCatalogPart.cs
- DesignerWebPartChrome.cs
- SimpleApplicationHost.cs
- ViewGenerator.cs
- FtpCachePolicyElement.cs
- WorkflowInstanceTerminatedRecord.cs
- SR.Designer.cs
- Internal.cs
- RectangleHotSpot.cs
- NumberSubstitution.cs
- _CookieModule.cs
- SapiRecoContext.cs
- SoapMessage.cs
- sqlpipe.cs
- ParentQuery.cs
- UserControl.cs
- DragDrop.cs
- SelectManyQueryOperator.cs
- RotationValidation.cs
- RenderContext.cs
- HtmlTable.cs
- PropertyGrid.cs
- MonikerBuilder.cs
- RectangleConverter.cs
- LayoutExceptionEventArgs.cs
- HotCommands.cs
- RepeaterItemEventArgs.cs
- OpenTypeLayoutCache.cs
- OracleTransaction.cs
- XmlAttributeHolder.cs
- FileCodeGroup.cs
- CacheDict.cs
- _IPv4Address.cs
- XmlSchema.cs
- CompositeControlDesigner.cs
- TextParagraph.cs
- HtmlInputReset.cs
- BadImageFormatException.cs
- ArgIterator.cs
- LogicalExpressionTypeConverter.cs
- ContainerControl.cs
- PopupControlService.cs
- RepeaterItemCollection.cs
- XsltSettings.cs
- PolicyReader.cs
- Point3DKeyFrameCollection.cs
- ParamArrayAttribute.cs
- HttpContextBase.cs
- IdentityHolder.cs
- _ProxyChain.cs
- IndexedEnumerable.cs
- TreeNode.cs
- ComponentChangingEvent.cs
- MetadataResolver.cs
- StringValidatorAttribute.cs
- ListItemParagraph.cs
- CodeSnippetStatement.cs
- WebPartMinimizeVerb.cs
- PieceDirectory.cs
- SimpleTypeResolver.cs
- OAVariantLib.cs
- LoginUtil.cs
- ToolStripDropDownClosingEventArgs.cs
- OutputCacheSettings.cs
- DefaultProxySection.cs
- CategoryEditor.cs
- SessionStateUtil.cs
- SelectionList.cs
- HttpWebRequestElement.cs
- IISUnsafeMethods.cs
- UriSectionData.cs
- _Win32.cs
- HttpDictionary.cs
- SQLDateTime.cs
- Environment.cs
- NameObjectCollectionBase.cs
- Group.cs
- QueryActivatableWorkflowsCommand.cs
- XpsS0ValidatingLoader.cs
- SslSecurityTokenParameters.cs
- SoundPlayer.cs
- LifetimeManager.cs
- DataViewManager.cs
- MissingSatelliteAssemblyException.cs
- ImageMapEventArgs.cs
- MaskedTextBoxTextEditorDropDown.cs
- ValueConversionAttribute.cs
- Trace.cs
- SafeBitVector32.cs
- DependencyProperty.cs
- x509store.cs