Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / Shaping / DefaultShape.cs / 1 / DefaultShape.cs
//---------------------------------------------------------------------- // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation, 2001 // // File: DefaultShape.cs // // Contents: Implementation of default shaping engine and its factory // // Created: 12-25-2001 Worachai Chaoweeraprasit (wchao) // //----------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.TextFormatting; using System.Security; using System.Security.Permissions; using MS.Internal.PresentationCore; using System.Windows.Media; using System.Windows.Media.TextFormatting; namespace MS.Internal.Shaping { ////// Default shaping engine implementation /// ////// This engine does not utilize OpenType information. It provides the baseline /// behavior of the shaping process. Most operations are based on font's CMAP, /// HMTX and VMTX table. /// internal class DefaultShape : IShapingEngine { internal DefaultShape() {} public ScriptTags[] SupportedScripts { get { return Script.AllTags; } } public bool OnLoadFont( ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState ) { shapeState = null; return true; } public IShaper this[ItemFlags flags] { get { if((flags & ItemFlags.GlyphVariant) != 0) { return DefaultShape.DefaultVariantShaper[(int)(flags & ItemFlags.GlyphVariant)]; } return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : DefaultShape.DefaultShaper as IShaper; } } // font independent static shapers, created once per process static public readonly IShaper DefaultShaper = new CmapShaper(); static public readonly IShaper SurrogateShaper = new DefaultSurrogateShaper(); static public readonly IShaper[] DefaultVariantShaper = new IShaper[] { DefaultShaper, DefaultShaper, //new DefaultVerticalShaper(), DefaultShaper, }; // // Associated shapers // ////// Base implementation of IShaper /// internal class CmapShaper : IShaper { internal CmapShaper() { } ////// CmapShaper.GetGlyphs - default implementation of the IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// Most shape engines will not override this method, but rather its helper /// function, GetGlyphsList. This base implementation will call GetGlyphsList /// if the font supports OpenType GSUB features. /// The shapers in DefaultShape.cs do implement override for this function. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical, SecurityTreatAsSafe] public unsafe virtual bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(pChars[charIx])).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort currGlyph; currGlyph = fontFace.CharacterToGlyphMap.TryGetValue(pChars[charIx], out currGlyph) ? currGlyph : (ushort)0; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } ////// DefaultShaper.GetGlyphPlacements - default implementation of the IShaper method. /// This method goes through a list of glyphs and adds placement information. /// ////// Most shape engines will not override this method, but instead its helper function - /// GetGlyphPositions. This base implementation will call GetGlyphsList /// if the font supports OpenType GPOS features. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// properties of text /// Character to glyph map /// text length /// Result glyph info array /// glyph properties array /// number of glyphs produced /// scale factor from font design unit /// List of glyph advance width /// List of glyph positioning offset ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe bool GetGlyphPlacements( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, int charCount, CheckedUShortPointer glyphIndices, CheckedGlyphShapingPropertiesPointer glyphProperties, int glyphCount, double scaleFactor, CheckedIntPointer glyphAdvances, CheckedGlyphOffsetPointer glyphOffsets ) { // get pointers to outputs ushort *pGlyphs = glyphIndices.Probe(0, glyphCount); int *pGlyphAdvances = glyphAdvances.Probe(0, glyphCount); GlyphOffset *pGlyphOffsets = glyphOffsets.Probe(0, glyphCount); GlyphShapingProperties* pGlyphProps = glyphProperties.Probe(0, glyphCount); for (ushort glyphIx = 0; glyphIx < glyphCount; ++glyphIx) { pGlyphOffsets[glyphIx].du = pGlyphOffsets[glyphIx].dv = 0; pGlyphAdvances[glyphIx] = (pGlyphProps[glyphIx].GlyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 ? 0 : (int)Math.Round( fontFace.GetAdvanceWidthInDesignUnits(pGlyphs[glyphIx]) * scaleFactor); } return true; } } ////// Default shaper for surrogate characters /// internal class DefaultSurrogateShaper : CmapShaper { internal DefaultSurrogateShaper() { } ////// DefaultSurrogateShaper.GetGlyphs - default implementation of the IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// This differs from the base CmapShaper method in that it /// detects and processed surrogate characters in the stream. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { int pairs = 0; ushort currGlyph; ushort invalidGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.DottedCircle, out currGlyph) ? currGlyph : (ushort)0; // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // run through the text quickly, looking for surrogate pairs. // (Count them) for(int charIx = 0; charIx < charCount; charIx++) { // the glyphs and their properties char currChar = pChars[charIx]; bool isLowSurrogate; int scalar; // check for surrogate pairs (looks for the second member in a pair before // looking at the preceding char). If a pair is found the glyph for // the preceding character is updated, otherwise the character is treated // as a standalone. if( (isLowSurrogate = IsLowSurrogate((int)currChar)) && charIx > 0 && IsHighSurrogate((int)pChars[charIx - 1]) && (scalar = MakeUnicodeScalar((int)pChars[charIx - 1], (int)currChar)) != 0) { // we've found a surrogate pair (yeah!!) pClusters[charIx] = pClusters[charIx - 1]; // this is ligated with the previous character pCharProps[charIx].CanGlyphAlone = false; pCharProps[charIx].EngineReserved= 1; // update the previous char's glyph int glyphIx = (charIx - 1) - pairs; fontFace.CharacterToGlyphMap.TryGetValue(scalar, out currGlyph); glyphIndices[glyphIx] = (currGlyph < fontFace.GlyphCount) ? currGlyph : (ushort)0; glyphProperties[glyphIx].EngineReserved = 2; ++pairs; } else { // this is a stand-alone character (1:1 char:glyph mapping) int glyphIx = charIx - pairs; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; glyphIndices[glyphIx] = isLowSurrogate ? invalidGlyph : fontFace.CharacterToGlyphMap.TryGetValue(currChar, out currGlyph) ? currGlyph : (ushort)0; // make sure glyph id is valid if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; currChar = UnicodeCharacter.Space; } // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map and glyph properties; pClusters[charIx] = (ushort)glyphIx; glyphProperties[glyphIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } } glyphCount = charCount - pairs; if (glyphCount < charCount) { // need to redimension glyphProperties and glyphIndices... // (though I'm not sure I have to...maybe glyphCount is always // used to limit access to glyphProperties, glyphIndices) ushort []redimGlyphIndices = new ushort[glyphCount]; GlyphShapingProperties[] redimGlyphProperties = new GlyphShapingProperties[glyphCount]; Array.Copy(glyphIndices, redimGlyphIndices, glyphCount); Array.Copy(glyphProperties, redimGlyphProperties, glyphCount); glyphIndices = redimGlyphIndices; glyphProperties = redimGlyphProperties; } return true; } internal static bool IsHighSurrogate(int ch) { return ch >= 0xd800 && ch < 0xdc00; } internal static bool IsLowSurrogate(int ch) { return ch >= 0xdc00 && ch < 0xe000; } internal static bool IsSurrogate(int ch) { return IsHighSurrogate(ch) || IsLowSurrogate(ch); } internal static int MakeUnicodeScalar(int hi, int lo) { return ((hi & 0x03ff) << 10 | (lo & 0x03ff)) + 0x10000; } } } ////// shaping engine for mirrored glyph form /// internal class MirroringShape : DefaultShape.CmapShaper, IShapingEngine { internal MirroringShape() { } public ScriptTags[] SupportedScripts { get { return new ScriptTags[]{ Script.TagMirror }; } } public IShaper this[ItemFlags flags] { get { return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : this; } } ////// MirroringShape.OnLoadFont - IShapingEngine method override. /// ///True if font supports script. public bool OnLoadFont(ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState) { shapeState = null; return true; } ////// MirroringShape.GetGlyphs - Mirroring IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// This differs from the default CmapShaper method by looking up the /// mirrored codepoint for each character and uses that codepoint to /// get the appropriate glyph. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { char currChar = pChars[charIx]; char mirroredChar = (char)Classification.GetMirroredCharacterUTF16(currChar); // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort currGlyph; currGlyph = fontFace.CharacterToGlyphMap.TryGetValue(mirroredChar, out currGlyph) ? currGlyph : (ushort)0; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } } ////// Default implementation of control code shape /// internal class ControlShape : DefaultShape.CmapShaper, IShapingEngine { internal ControlShape() { } public ScriptTags[] SupportedScripts { get { return new ScriptTags[]{ Script.TagControl }; } } public IShaper this[ItemFlags flags] { get { return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : this; } } ////// ControlShape.OnLoadFont - IShapingEngine method override. /// ///True if font supports script. public bool OnLoadFont(ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState) { shapeState = null; return true; } ////// ControlShape.GetGlyphs - Mirroring IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { bool displayControlChars = ((shapingFlags & ShapingOptions.DisplayControlCode) != 0); // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // these glyphs are used alot ushort currGlyph; ushort blankGlyph; ushort zwnjGlyph; blankGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.Space, out currGlyph) ? currGlyph : (ushort) 0; zwnjGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.ZWNJ, out currGlyph) ? currGlyph : (ushort) 0; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { char currChar = pChars[charIx]; // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort glyphFlags = (ushort)ShapingWorkspace.GlyphFlagsBase; if( IsC0( (int)currChar ) || displayControlChars ) { // check for missing glyph if (!fontFace.CharacterToGlyphMap.TryGetValue(currChar,out currGlyph)) { // IsDefaultHidden is true for some core control code that never // display. For other missing control codes, display with the // ZWNJ glyph. currGlyph = IsDefaultHidden( (int)currChar ) ? blankGlyph : zwnjGlyph; glyphFlags |= (ushort)GlyphFlags.ZeroWidth; } } else { currGlyph = blankGlyph; // default is to hide control chars glyphFlags = (ushort)ShapingWorkspace.GlyphFlagsZeroWidth; } if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = blankGlyph; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } private const int ZWNJ = 0x200c; private bool IsC0(int ch) { return ch < 0x0020; } private bool IsDefaultHidden(int ch) { // For 0x001c...0x001f (FS, GS, RS, US), TAB, CR and LF, // we'll never display them as missing glyph return IsC0(ch) && (ch >= 0x001c || ch == 9 || ch == 10 || ch == 13); } } } // 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, 2001 // // File: DefaultShape.cs // // Contents: Implementation of default shaping engine and its factory // // Created: 12-25-2001 Worachai Chaoweeraprasit (wchao) // //----------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.TextFormatting; using System.Security; using System.Security.Permissions; using MS.Internal.PresentationCore; using System.Windows.Media; using System.Windows.Media.TextFormatting; namespace MS.Internal.Shaping { ////// Default shaping engine implementation /// ////// This engine does not utilize OpenType information. It provides the baseline /// behavior of the shaping process. Most operations are based on font's CMAP, /// HMTX and VMTX table. /// internal class DefaultShape : IShapingEngine { internal DefaultShape() {} public ScriptTags[] SupportedScripts { get { return Script.AllTags; } } public bool OnLoadFont( ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState ) { shapeState = null; return true; } public IShaper this[ItemFlags flags] { get { if((flags & ItemFlags.GlyphVariant) != 0) { return DefaultShape.DefaultVariantShaper[(int)(flags & ItemFlags.GlyphVariant)]; } return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : DefaultShape.DefaultShaper as IShaper; } } // font independent static shapers, created once per process static public readonly IShaper DefaultShaper = new CmapShaper(); static public readonly IShaper SurrogateShaper = new DefaultSurrogateShaper(); static public readonly IShaper[] DefaultVariantShaper = new IShaper[] { DefaultShaper, DefaultShaper, //new DefaultVerticalShaper(), DefaultShaper, }; // // Associated shapers // ////// Base implementation of IShaper /// internal class CmapShaper : IShaper { internal CmapShaper() { } ////// CmapShaper.GetGlyphs - default implementation of the IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// Most shape engines will not override this method, but rather its helper /// function, GetGlyphsList. This base implementation will call GetGlyphsList /// if the font supports OpenType GSUB features. /// The shapers in DefaultShape.cs do implement override for this function. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical, SecurityTreatAsSafe] public unsafe virtual bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(pChars[charIx])).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort currGlyph; currGlyph = fontFace.CharacterToGlyphMap.TryGetValue(pChars[charIx], out currGlyph) ? currGlyph : (ushort)0; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } ////// DefaultShaper.GetGlyphPlacements - default implementation of the IShaper method. /// This method goes through a list of glyphs and adds placement information. /// ////// Most shape engines will not override this method, but instead its helper function - /// GetGlyphPositions. This base implementation will call GetGlyphsList /// if the font supports OpenType GPOS features. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// properties of text /// Character to glyph map /// text length /// Result glyph info array /// glyph properties array /// number of glyphs produced /// scale factor from font design unit /// List of glyph advance width /// List of glyph positioning offset ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe bool GetGlyphPlacements( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, int charCount, CheckedUShortPointer glyphIndices, CheckedGlyphShapingPropertiesPointer glyphProperties, int glyphCount, double scaleFactor, CheckedIntPointer glyphAdvances, CheckedGlyphOffsetPointer glyphOffsets ) { // get pointers to outputs ushort *pGlyphs = glyphIndices.Probe(0, glyphCount); int *pGlyphAdvances = glyphAdvances.Probe(0, glyphCount); GlyphOffset *pGlyphOffsets = glyphOffsets.Probe(0, glyphCount); GlyphShapingProperties* pGlyphProps = glyphProperties.Probe(0, glyphCount); for (ushort glyphIx = 0; glyphIx < glyphCount; ++glyphIx) { pGlyphOffsets[glyphIx].du = pGlyphOffsets[glyphIx].dv = 0; pGlyphAdvances[glyphIx] = (pGlyphProps[glyphIx].GlyphFlags & (ushort)GlyphFlags.ZeroWidth) != 0 ? 0 : (int)Math.Round( fontFace.GetAdvanceWidthInDesignUnits(pGlyphs[glyphIx]) * scaleFactor); } return true; } } ////// Default shaper for surrogate characters /// internal class DefaultSurrogateShaper : CmapShaper { internal DefaultSurrogateShaper() { } ////// DefaultSurrogateShaper.GetGlyphs - default implementation of the IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// This differs from the base CmapShaper method in that it /// detects and processed surrogate characters in the stream. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { int pairs = 0; ushort currGlyph; ushort invalidGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.DottedCircle, out currGlyph) ? currGlyph : (ushort)0; // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // run through the text quickly, looking for surrogate pairs. // (Count them) for(int charIx = 0; charIx < charCount; charIx++) { // the glyphs and their properties char currChar = pChars[charIx]; bool isLowSurrogate; int scalar; // check for surrogate pairs (looks for the second member in a pair before // looking at the preceding char). If a pair is found the glyph for // the preceding character is updated, otherwise the character is treated // as a standalone. if( (isLowSurrogate = IsLowSurrogate((int)currChar)) && charIx > 0 && IsHighSurrogate((int)pChars[charIx - 1]) && (scalar = MakeUnicodeScalar((int)pChars[charIx - 1], (int)currChar)) != 0) { // we've found a surrogate pair (yeah!!) pClusters[charIx] = pClusters[charIx - 1]; // this is ligated with the previous character pCharProps[charIx].CanGlyphAlone = false; pCharProps[charIx].EngineReserved= 1; // update the previous char's glyph int glyphIx = (charIx - 1) - pairs; fontFace.CharacterToGlyphMap.TryGetValue(scalar, out currGlyph); glyphIndices[glyphIx] = (currGlyph < fontFace.GlyphCount) ? currGlyph : (ushort)0; glyphProperties[glyphIx].EngineReserved = 2; ++pairs; } else { // this is a stand-alone character (1:1 char:glyph mapping) int glyphIx = charIx - pairs; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; glyphIndices[glyphIx] = isLowSurrogate ? invalidGlyph : fontFace.CharacterToGlyphMap.TryGetValue(currChar, out currGlyph) ? currGlyph : (ushort)0; // make sure glyph id is valid if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; currChar = UnicodeCharacter.Space; } // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map and glyph properties; pClusters[charIx] = (ushort)glyphIx; glyphProperties[glyphIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } } glyphCount = charCount - pairs; if (glyphCount < charCount) { // need to redimension glyphProperties and glyphIndices... // (though I'm not sure I have to...maybe glyphCount is always // used to limit access to glyphProperties, glyphIndices) ushort []redimGlyphIndices = new ushort[glyphCount]; GlyphShapingProperties[] redimGlyphProperties = new GlyphShapingProperties[glyphCount]; Array.Copy(glyphIndices, redimGlyphIndices, glyphCount); Array.Copy(glyphProperties, redimGlyphProperties, glyphCount); glyphIndices = redimGlyphIndices; glyphProperties = redimGlyphProperties; } return true; } internal static bool IsHighSurrogate(int ch) { return ch >= 0xd800 && ch < 0xdc00; } internal static bool IsLowSurrogate(int ch) { return ch >= 0xdc00 && ch < 0xe000; } internal static bool IsSurrogate(int ch) { return IsHighSurrogate(ch) || IsLowSurrogate(ch); } internal static int MakeUnicodeScalar(int hi, int lo) { return ((hi & 0x03ff) << 10 | (lo & 0x03ff)) + 0x10000; } } } ////// shaping engine for mirrored glyph form /// internal class MirroringShape : DefaultShape.CmapShaper, IShapingEngine { internal MirroringShape() { } public ScriptTags[] SupportedScripts { get { return new ScriptTags[]{ Script.TagMirror }; } } public IShaper this[ItemFlags flags] { get { return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : this; } } ////// MirroringShape.OnLoadFont - IShapingEngine method override. /// ///True if font supports script. public bool OnLoadFont(ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState) { shapeState = null; return true; } ////// MirroringShape.GetGlyphs - Mirroring IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// This differs from the default CmapShaper method by looking up the /// mirrored codepoint for each character and uses that codepoint to /// get the appropriate glyph. /// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { char currChar = pChars[charIx]; char mirroredChar = (char)Classification.GetMirroredCharacterUTF16(currChar); // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort currGlyph; currGlyph = fontFace.CharacterToGlyphMap.TryGetValue(mirroredChar, out currGlyph) ? currGlyph : (ushort)0; ushort glyphFlags = ShapingWorkspace.GlyphFlagsBase; if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = fontFace.BlankGlyphIndex; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } } ////// Default implementation of control code shape /// internal class ControlShape : DefaultShape.CmapShaper, IShapingEngine { internal ControlShape() { } public ScriptTags[] SupportedScripts { get { return new ScriptTags[]{ Script.TagControl }; } } public IShaper this[ItemFlags flags] { get { return (flags & ItemFlags.HasExtendedCharacter) != 0 ? DefaultShape.SurrogateShaper as IShaper : this; } } ////// ControlShape.OnLoadFont - IShapingEngine method override. /// ///True if font supports script. public bool OnLoadFont(ScriptTags scriptTag, GlyphTypeface fontFace, out object shapeState) { shapeState = null; return true; } ////// ControlShape.GetGlyphs - Mirroring IShaper method. /// This method returns a list of glyphs, a character-to-glyph map, and /// a cluster map. /// ////// /// Text item /// text culture info /// font face layout info /// OpenType features /// Controlling flags /// Shaping engine font specific data /// Incoming text /// text length /// properties of text /// Character to glyph map /// Result glyph info array /// glyph properties array /// number of glyphs produced ///true if succeeds ////// Critical - this method calls unsafe methods. /// Safe - this method returns glyph indices and shaping properties which are safe. /// [SecurityCritical] public unsafe override bool GetGlyphs( Item item, CultureInfo culture, GlyphTypeface fontFace, FeatureSet featureSet, ShapingOptions shapingFlags, object shapeFontInfo, CheckedCharPointer chars, int charCount, CheckedCharacterShapingPropertiesPointer charProperties, CheckedUShortPointer charClusterMap, out ushort[] glyphIndices, out GlyphShapingProperties[] glyphProperties, out int glyphCount ) { bool displayControlChars = ((shapingFlags & ShapingOptions.DisplayControlCode) != 0); // unpack the pointer containers and keep track of our pointer char *pChars = chars.Probe(0, charCount); CharacterShapingProperties *pCharProps = charProperties.Probe(0, charCount); ushort *pClusters = charClusterMap.Probe(0, charCount); // create output arrays glyphIndices = new ushort[charCount]; glyphProperties = new GlyphShapingProperties[charCount]; // these glyphs are used alot ushort currGlyph; ushort blankGlyph; ushort zwnjGlyph; blankGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.Space, out currGlyph) ? currGlyph : (ushort) 0; zwnjGlyph = fontFace.CharacterToGlyphMap.TryGetValue(UnicodeCharacter.ZWNJ, out currGlyph) ? currGlyph : (ushort) 0; // fill the arrays for(ushort charIx = 0; charIx < charCount; charIx++) { char currChar = pChars[charIx]; // the character properties bool canGlyphAlone = (Classification.CharAttributeOf( (int)Classification.GetUnicodeClassUTF16(currChar)).Flags & (ushort)CharacterAttributeFlags.CharacterSpace) != 0; pCharProps[charIx].CanGlyphAlone = canGlyphAlone; pCharProps[charIx].EngineReserved= 0; // the cluster map (all clusters are one character) pClusters[charIx] = charIx; // the glyphs and their properties ushort glyphFlags = (ushort)ShapingWorkspace.GlyphFlagsBase; if( IsC0( (int)currChar ) || displayControlChars ) { // check for missing glyph if (!fontFace.CharacterToGlyphMap.TryGetValue(currChar,out currGlyph)) { // IsDefaultHidden is true for some core control code that never // display. For other missing control codes, display with the // ZWNJ glyph. currGlyph = IsDefaultHidden( (int)currChar ) ? blankGlyph : zwnjGlyph; glyphFlags |= (ushort)GlyphFlags.ZeroWidth; } } else { currGlyph = blankGlyph; // default is to hide control chars glyphFlags = (ushort)ShapingWorkspace.GlyphFlagsZeroWidth; } if (currGlyph >= fontFace.GlyphCount) { // invalid glyph index (too big to be valid), so just hide it. glyphFlags |= (ushort)GlyphFlags.ZeroWidth; currGlyph = blankGlyph; } glyphIndices[charIx] = currGlyph; glyphProperties[charIx] = new GlyphShapingProperties( glyphFlags, (ushort)(1 << 8)); } glyphCount = charCount ; return true; } private const int ZWNJ = 0x200c; private bool IsC0(int ch) { return ch < 0x0020; } private bool IsDefaultHidden(int ch) { // For 0x001c...0x001f (FS, GS, RS, US), TAB, CR and LF, // we'll never display them as missing glyph return IsC0(ch) && (ch >= 0x001c || ch == 9 || ch == 10 || ch == 13); } } } // 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
- Internal.cs
- CollectionView.cs
- InlineUIContainer.cs
- ControlPager.cs
- RuleSettings.cs
- FileDialog.cs
- NotCondition.cs
- BitmapEffectDrawingContextWalker.cs
- TransformedBitmap.cs
- XmlSerializerFactory.cs
- XPathBinder.cs
- ComponentTray.cs
- PerformanceCounterPermissionAttribute.cs
- PassportPrincipal.cs
- SafeHandles.cs
- ExtenderProviderService.cs
- FolderNameEditor.cs
- DNS.cs
- CallContext.cs
- DrawingCollection.cs
- DefaultTextStore.cs
- mansign.cs
- PropertyEmitter.cs
- IsolationInterop.cs
- CodeAttachEventStatement.cs
- EventDescriptor.cs
- SynchronizingStream.cs
- EntitySetBase.cs
- AuthenticationModuleElement.cs
- DesignerLoader.cs
- SqlDataSourceConnectionPanel.cs
- ActivityTrace.cs
- WebBrowserSiteBase.cs
- AssemblyInfo.cs
- PropertyMap.cs
- Pool.cs
- PathData.cs
- BlockCollection.cs
- rsa.cs
- CounterCreationDataCollection.cs
- hwndwrapper.cs
- DiscoveryMessageSequenceGenerator.cs
- UTF32Encoding.cs
- DataGridViewBand.cs
- PriorityBindingExpression.cs
- ZipFileInfoCollection.cs
- LocalizationCodeDomSerializer.cs
- RelationshipEntry.cs
- xmlglyphRunInfo.cs
- StringPropertyBuilder.cs
- FontDriver.cs
- FontCollection.cs
- QilNode.cs
- CompositeDataBoundControl.cs
- DataGridColumnHeadersPresenterAutomationPeer.cs
- IPAddress.cs
- NotificationContext.cs
- TextServicesCompartmentEventSink.cs
- QuadTree.cs
- ListBoxDesigner.cs
- userdatakeys.cs
- TabPage.cs
- IISUnsafeMethods.cs
- AnimationTimeline.cs
- FontStretches.cs
- ActivityExecutorOperation.cs
- PreservationFileWriter.cs
- XmlDocumentType.cs
- ControlFilterExpression.cs
- SizeLimitedCache.cs
- MsmqNonTransactedPoisonHandler.cs
- Helpers.cs
- ViewStateException.cs
- BigInt.cs
- Util.cs
- SortKey.cs
- NotSupportedException.cs
- TextElement.cs
- BufferedWebEventProvider.cs
- XmlQueryType.cs
- SevenBitStream.cs
- ScrollChangedEventArgs.cs
- DurableInstanceManager.cs
- WebPartVerb.cs
- DateTimeFormat.cs
- WebPartDisplayModeEventArgs.cs
- ASCIIEncoding.cs
- ObjectDataSourceDisposingEventArgs.cs
- ConnectionStringSettingsCollection.cs
- PolyLineSegmentFigureLogic.cs
- AdapterUtil.cs
- WebServiceFaultDesigner.cs
- RadioButtonRenderer.cs
- XmlDataSourceNodeDescriptor.cs
- SqlProviderServices.cs
- SapiRecoContext.cs
- NumericUpDownAcceleration.cs
- MobileDeviceCapabilitiesSectionHandler.cs
- Thread.cs
- ProxyAttribute.cs