Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextShapeableCharacters.cs / 1 / TextShapeableCharacters.cs
//------------------------------------------------------------------------
//
// Microsoft Windows Client Platform
// Copyright (C) Microsoft Corporation
//
// File: TextShapeableCharacters.cs
//
// Contents: Implementation of text shapeable symbols for characters
//
// Spec: http://team/sites/Avalon/Specs/Text%20Formatting%20API.doc
//
// Created: 1-2-2004 Worachai Chaoweeraprasit (wchao)
// History: 1-19-2004 garyyyang: Change the class to internal
//
//-----------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Security;
using System.Windows;
using System.Windows.Markup; // for XmlLanguage
using System.Windows.Media;
using MS.Internal;
using MS.Internal.FontCache;
using MS.Internal.TextFormatting;
using MS.Internal.Shaping;
namespace System.Windows.Media.TextFormatting
{
///
/// A specialized TextShapeableSymbols implemented by TextFormatter to represent
/// a collection of glyphs from a physical typeface.
///
internal sealed class TextShapeableCharacters : TextShapeableSymbols
{
private CharacterBufferRange _characterBufferRange;
private TextRunProperties _properties;
private double _emSize; // after-scaled
private Item _textItem;
private ShapeTypeface _shapeTypeface;
private bool _nullShape;
#region Constructors
///
/// Construct a shapeable characters object
///
///
/// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
/// has previously returned true.
///
internal TextShapeableCharacters(
CharacterBufferRange characterRange,
TextRunProperties properties,
double emSize,
Item textItem,
ShapeTypeface shapeTypeface,
bool nullShape
)
{
_characterBufferRange = characterRange;
_properties = properties;
_emSize = emSize;
_textItem = textItem;
_shapeTypeface = shapeTypeface;
_nullShape = nullShape;
}
#endregion
#region TextRun implementation
///
/// Character reference
///
public sealed override CharacterBufferReference CharacterBufferReference
{
get
{
return _characterBufferRange.CharacterBufferReference;
}
}
///
/// Character length of the run
///
public sealed override int Length
{
get
{
return _characterBufferRange.Length;
}
}
///
/// A set of properties shared by every characters in the run
///
public sealed override TextRunProperties Properties
{
get
{
return _properties;
}
}
#endregion
#region TextShapeableSymbols implementation
///
/// Map specified character string into glyphs
///
internal sealed override ushort[] GetGlyphs(
CheckedCharPointer characterString,
int length,
ShapingOptions shapeOptions,
FeatureSet featureSet,
CheckedUShortPointer clusterMap,
CheckedCharacterShapingPropertiesPointer characterProperties,
out GlyphShapingProperties[] glyphProperties,
out int glyphCount
)
{
Invariant.Assert(_shapeTypeface != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
ushort[] glyphs;
if (_nullShape && _textItem.Script != ScriptID.Control)
{
glyphs = GetNullGlyphs(
length,
characterString,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
}
else
{
glyphs = _shapeTypeface.GetGlyphs(
characterString,
length,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
_textItem,
shapeOptions,
featureSet,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
if ( glyphs == null
|| glyphs.Length == 0
|| glyphCount == 0)
{
glyphs = GetNullGlyphs(
length,
characterString,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
}
}
return glyphs;
}
///
/// Shape specified character string into an array of missing glyphs
///
///
/// Critical - the method probes into checked pointer
/// Safe - The method fills in null glyphs, null glyphs are ok to expose
///
[SecurityCritical, SecurityTreatAsSafe]
private unsafe ushort[] GetNullGlyphs(
int length,
CheckedCharPointer characterString,
CheckedCharacterShapingPropertiesPointer characterProperties,
CheckedUShortPointer clusterMap,
out GlyphShapingProperties[] glyphProperties,
out int glyphCount
)
{
glyphCount = 0;
ushort[] glyphs = new ushort[length];
glyphProperties = new GlyphShapingProperties[length];
// Probe into the checked pointer
ushort * pClusterMap = clusterMap.Probe(0, length);
CharacterShapingProperties* pCharacterProperties = characterProperties.Probe(0, length);
char * charBuffer = characterString.Probe(0, length);
int wordCount;
for(int i = 0; i < length; i = i + wordCount)
{
wordCount = 1;
pClusterMap[i] = (ushort) glyphCount;
pCharacterProperties[i].CanGlyphAlone = true;
pCharacterProperties[i].EngineReserved = 0; // Engine reserved. Single glyph cluster
glyphs[glyphCount] = 0;
glyphProperties[glyphCount] = new GlyphShapingProperties(
(ushort)(GlyphFlags.ClusterStart | GlyphFlags.Unresolved), // glyph flags
(ushort)((1 << 8) | 0) // Engine reserved. Single glyph cluster
);
glyphCount ++;
if (i < length -1 && ((charBuffer[i] & 0xFC00) == 0xD800) && ((charBuffer[i + 1] & 0xFC00) == 0xDC00))
{
// Both higher and lower surrogate should point to the same glyph.
wordCount = 2;
pClusterMap[i + 1] = pClusterMap[i];
pCharacterProperties[i + 1].CanGlyphAlone = true;
}
}
return glyphs;
}
///
/// Get placement of glyphs
///
internal sealed override void GetGlyphPlacements(
CheckedUShortPointer glyphIndices,
CheckedGlyphShapingPropertiesPointer glyphProperties,
int glyphCount,
CheckedUShortPointer clusterMap,
CheckedCharacterShapingPropertiesPointer characterProperties,
int length,
ShapingOptions shapeOptions,
FeatureSet featureSet,
double scalingFactor,
CheckedIntPointer glyphAdvances,
CheckedGlyphOffsetPointer glyphOffsets
)
{
Invariant.Assert(_shapeTypeface != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
_shapeTypeface.GetGlyphPlacements(
_characterBufferRange,
glyphIndices,
glyphProperties,
glyphCount,
_textItem,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
clusterMap,
characterProperties,
length,
shapeOptions,
featureSet,
_emSize * scalingFactor,
glyphAdvances,
glyphOffsets
);
}
///
/// Compute a shaped glyph run object from specified glyph-based info
///
internal sealed override GlyphRun ComputeShapedGlyphRun(
Point origin,
char[] characterString,
ushort[] clusterMap,
ushort[] glyphIndices,
GlyphShapingProperties[] glyphProperties,
IList glyphAdvances,
IList glyphOffsets,
bool rightToLeft,
bool sideways
)
{
Invariant.Assert(_shapeTypeface != null);
Invariant.Assert(glyphIndices != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
bool[] caretStops = null;
if ( clusterMap != null
&& (HasExtendedCharacter || NeedsCaretInfo)
)
{
caretStops = new bool[clusterMap.Length + 1];
// caret stops at cluster boundaries, the first and the last entries are always set
caretStops[0] = true;
caretStops[clusterMap.Length] = true;
ushort lastGlyph = clusterMap[0];
for (int i = 1; i < clusterMap.Length; i++)
{
ushort glyph = clusterMap[i];
if (glyph != lastGlyph)
{
caretStops[i] = true;
lastGlyph = glyph;
}
}
}
return GlyphRun.TryCreate(
_shapeTypeface.GlyphTypeface,
(rightToLeft ? 1 : 0),
sideways,
_emSize,
glyphIndices,
origin,
glyphAdvances,
glyphOffsets,
characterString,
null,
clusterMap,
caretStops,
XmlLanguage.GetLanguage(CultureMapper.GetSpecificCulture(_properties.CultureInfo).IetfLanguageTag)
);
}
private GlyphTypeface GetGlyphTypeface(out bool nullFont)
{
GlyphTypeface glyphTypeface;
if (_shapeTypeface == null)
{
// We're in the optimized path where the GlyphTypeface depends only
// on the Typeface, not on the particular input characters.
Typeface typeface = _properties.Typeface;
// Get the GlyphTypeface.
glyphTypeface = typeface.TryGetGlyphTypeface();
// If Typeface does not specify *any* valid font family, then we use
// the GlyphTypeface for Arial but only to display missing glyphs.
nullFont = typeface.NullFont;
}
else
{
// Font linking has mapped the input to a specific GlyphTypeface.
glyphTypeface = _shapeTypeface.GlyphTypeface;
// If font linking could not find *any* physical font family, then we
// use the GlyphTypeface for Arial but only to display missing glyphs.
nullFont = _nullShape;
}
Invariant.Assert(glyphTypeface != null);
return glyphTypeface;
}
///
/// Compute unshaped glyph run object from the specified character-based info
///
internal sealed override GlyphRun ComputeUnshapedGlyphRun(
Point origin,
char[] characterString,
IList characterAdvances
)
{
bool nullFont;
GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
Invariant.Assert(glyphTypeface != null);
return glyphTypeface.ComputeUnshapedGlyphRun(
origin,
new CharacterBufferRange(
characterString,
0, // offsetToFirstChar
characterString.Length
),
characterAdvances,
_emSize,
_properties.FontHintingEmSize,
nullFont,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
(_shapeTypeface == null || _shapeTypeface.DeviceFont == null) ? null : _shapeTypeface.DeviceFont.Name
);
}
///
/// Draw glyph run to the drawing surface
///
internal sealed override void Draw(
DrawingContext drawingContext,
Brush foregroundBrush,
GlyphRun glyphRun
)
{
if (drawingContext == null)
throw new ArgumentNullException("drawingContext");
glyphRun.EmitBackground(drawingContext, _properties.BackgroundBrush);
drawingContext.DrawGlyphRun(
foregroundBrush != null ? foregroundBrush : _properties.ForegroundBrush,
glyphRun
);
}
///
/// Get advance widths of unshaped characters
///
///
/// Critical: This code calls into unsafe code blocks
///
[SecurityCritical]
internal sealed override unsafe void GetAdvanceWidthsUnshaped(
char* characterString,
int characterLength,
double scalingFactor,
int* advanceWidthsUnshaped
)
{
if (!IsShapingRequired)
{
if ( (_shapeTypeface != null)
&& (_shapeTypeface.DeviceFont != null))
{
// Use device font to compute advance widths
_shapeTypeface.DeviceFont.GetAdvanceWidths(
characterString,
characterLength,
_emSize * scalingFactor,
advanceWidthsUnshaped
);
}
else
{
bool nullFont;
GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
Invariant.Assert(glyphTypeface != null);
glyphTypeface.GetAdvanceWidthsUnshaped(
characterString,
characterLength,
_emSize * scalingFactor,
advanceWidthsUnshaped,
nullFont
);
}
}
else
{
GlyphTypeface glyphTypeface = _shapeTypeface.GlyphTypeface;
Invariant.Assert(glyphTypeface != null);
Invariant.Assert(characterLength > 0);
IDictionary cmap = glyphTypeface.CharacterToGlyphMap;
// compensate for approximated usual reduction of shaped widths for complex script
scalingFactor *= ApproximateNominalToIdealWidthRatio * _emSize;
for (int i = 0; i < characterLength; i++)
{
ushort glyphIndex;
cmap.TryGetValue(characterString[i], out glyphIndex);
advanceWidthsUnshaped[i] = (int)Math.Round(scalingFactor * glyphTypeface.GetAdvanceWidth(glyphIndex));
}
}
}
///
/// Get the ratio of typical ideal glyph width over nominal character width. It is used to
/// compensate the usual reduction of shaped widths.
///
internal sealed override double ApproximateNominalToIdealWidthRatio
{
get
{
double nominalToIdealWidthRatio = 1.0;
// Apply a scaling ratio if:
// 1) the script is not Latin (hence more likely to formed into ligature)
// 2) or the run contains combining mark or extended characters
if ( _textItem.Script != ScriptID.Latin
|| (_textItem.Flags & (ItemFlags.HasCombiningMark | ItemFlags.HasExtendedCharacter)) != 0
)
{
nominalToIdealWidthRatio = IsScriptIndic(_textItem.Script) ? 0.35 : 0.75;
}
return nominalToIdealWidthRatio;
}
}
///
/// Returns true if specified script is Indic.
///
private bool IsScriptIndic(ScriptID script)
{
return script == ScriptID.Bengali
|| script == ScriptID.Devanagari
|| script == ScriptID.Gurmukhi
|| script == ScriptID.Gujarati
|| script == ScriptID.Kannada
|| script == ScriptID.Malayalam
|| script == ScriptID.Oriya
|| script == ScriptID.Tamil
|| script == ScriptID.Telugu;
}
///
/// Return value indicates whether two runs can shape together
///
internal sealed override bool CanShapeTogether(
TextShapeableSymbols shapeable
)
{
TextShapeableCharacters charShape = shapeable as TextShapeableCharacters;
if (charShape == null)
return false;
return
_shapeTypeface.Equals(charShape._shapeTypeface)
&& _textItem.Script == charShape._textItem.Script
// Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters.
&& (_textItem.Flags & ItemFlags.HasExtendedCharacter) == (charShape._textItem.Flags & ItemFlags.HasExtendedCharacter)
&& _emSize == charShape._emSize
&& (
_properties.CultureInfo == null ?
charShape._properties.CultureInfo == null
: _properties.CultureInfo.Equals(charShape._properties.CultureInfo)
)
&& _nullShape == charShape._nullShape;
}
///
/// Indicate whether run cannot be treated as simple characters because shaping is required.
///
/// The following cases use simple rendering without shaping:
/// o No _shapeTypeface. This happens in very simple rendering cases.
/// o Non-Unicode (i.e. symbol) fonts.
/// o When using a device font.
///
/// Note that the presence of a device font in _shapeTypeface.DeviceFont implies use of
/// a device font in all cases except where digit substitution applies. This special
/// case occurs because the cached result per codepoint of TypefaceMap must include the device font
/// for non-western digits in order to support device font rendering of the non-Western
/// digit Unicode codepoints. The device font is not used however when the non-Western digits
/// are displayed as a result of digit substitution from backing store Western digits.
///
internal sealed override bool IsShapingRequired
{
get
{
return
(_shapeTypeface != null) // Can't use shaping without a shape typeface
&& ( (_shapeTypeface.DeviceFont == null) // Can't use shaping when rendering with a device font
|| (_textItem.DigitCulture != null)) // -- unless substituting digits
&& (!IsSymbol); // Can't use shaping for symbol (non-Unicode) fonts
}
}
///
/// A Boolean value indicates whether additional info is required for caret positioning
///
internal sealed override bool NeedsCaretInfo
{
get
{
return (_textItem.Flags & ItemFlags.HasCombiningMark) != 0
|| (Script.Flags[(int)_textItem.Script] & ScriptFlags.NeedsCaretInfo) != 0;
}
}
///
/// A Boolean value indicates whether run has extended character
///
internal sealed override bool HasExtendedCharacter
{
get
{
return (_textItem.Flags & ItemFlags.HasExtendedCharacter) != 0;
}
}
///
/// Run height
///
internal sealed override double Height
{
get
{
return _properties.Typeface.LineSpacing * _properties.FontRenderingEmSize;
}
}
///
/// Distance from top to baseline
///
internal sealed override double Baseline
{
get
{
return _properties.Typeface.Baseline * _properties.FontRenderingEmSize;
}
}
///
/// Distance from baseline to underline position relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double UnderlinePosition
{
get
{
return _properties.Typeface.UnderlinePosition;
}
}
///
/// Underline thickness relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double UnderlineThickness
{
get
{
return _properties.Typeface.UnderlineThickness;
}
}
///
/// Distance from baseline to strike-through position relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double StrikethroughPosition
{
get
{
return _properties.Typeface.StrikethroughPosition;
}
}
///
/// strike-through thickness relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double StrikethroughThickness
{
get
{
return _properties.Typeface.StrikethroughThickness;
}
}
#endregion
///
/// Whether all characters in this run are non-Unicode character (symbol)
///
internal bool IsSymbol
{
get
{
if (_shapeTypeface != null)
return _shapeTypeface.GlyphTypeface.Symbol;
return _properties.Typeface.Symbol;
}
}
///
/// Returns maximum possible cluster size for the run. Normally, this
/// is 8 characters, but Indic scripts require this to be 15.
///
internal const ushort DefaultMaxClusterSize = 8;
private const ushort IndicMaxClusterSize = 15;
internal sealed override ushort MaxClusterSize
{
get
{
switch (_textItem.Script)
{
case ScriptID.Bengali:
case ScriptID.Devanagari:
case ScriptID.Gurmukhi:
case ScriptID.Gujarati:
case ScriptID.Kannada:
case ScriptID.Malayalam:
case ScriptID.Oriya:
case ScriptID.Tamil:
case ScriptID.Telugu:
return IndicMaxClusterSize;
}
return DefaultMaxClusterSize;
}
}
}
}
// 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
//
// File: TextShapeableCharacters.cs
//
// Contents: Implementation of text shapeable symbols for characters
//
// Spec: http://team/sites/Avalon/Specs/Text%20Formatting%20API.doc
//
// Created: 1-2-2004 Worachai Chaoweeraprasit (wchao)
// History: 1-19-2004 garyyyang: Change the class to internal
//
//-----------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Security;
using System.Windows;
using System.Windows.Markup; // for XmlLanguage
using System.Windows.Media;
using MS.Internal;
using MS.Internal.FontCache;
using MS.Internal.TextFormatting;
using MS.Internal.Shaping;
namespace System.Windows.Media.TextFormatting
{
///
/// A specialized TextShapeableSymbols implemented by TextFormatter to represent
/// a collection of glyphs from a physical typeface.
///
internal sealed class TextShapeableCharacters : TextShapeableSymbols
{
private CharacterBufferRange _characterBufferRange;
private TextRunProperties _properties;
private double _emSize; // after-scaled
private Item _textItem;
private ShapeTypeface _shapeTypeface;
private bool _nullShape;
#region Constructors
///
/// Construct a shapeable characters object
///
///
/// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
/// has previously returned true.
///
internal TextShapeableCharacters(
CharacterBufferRange characterRange,
TextRunProperties properties,
double emSize,
Item textItem,
ShapeTypeface shapeTypeface,
bool nullShape
)
{
_characterBufferRange = characterRange;
_properties = properties;
_emSize = emSize;
_textItem = textItem;
_shapeTypeface = shapeTypeface;
_nullShape = nullShape;
}
#endregion
#region TextRun implementation
///
/// Character reference
///
public sealed override CharacterBufferReference CharacterBufferReference
{
get
{
return _characterBufferRange.CharacterBufferReference;
}
}
///
/// Character length of the run
///
public sealed override int Length
{
get
{
return _characterBufferRange.Length;
}
}
///
/// A set of properties shared by every characters in the run
///
public sealed override TextRunProperties Properties
{
get
{
return _properties;
}
}
#endregion
#region TextShapeableSymbols implementation
///
/// Map specified character string into glyphs
///
internal sealed override ushort[] GetGlyphs(
CheckedCharPointer characterString,
int length,
ShapingOptions shapeOptions,
FeatureSet featureSet,
CheckedUShortPointer clusterMap,
CheckedCharacterShapingPropertiesPointer characterProperties,
out GlyphShapingProperties[] glyphProperties,
out int glyphCount
)
{
Invariant.Assert(_shapeTypeface != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
ushort[] glyphs;
if (_nullShape && _textItem.Script != ScriptID.Control)
{
glyphs = GetNullGlyphs(
length,
characterString,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
}
else
{
glyphs = _shapeTypeface.GetGlyphs(
characterString,
length,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
_textItem,
shapeOptions,
featureSet,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
if ( glyphs == null
|| glyphs.Length == 0
|| glyphCount == 0)
{
glyphs = GetNullGlyphs(
length,
characterString,
characterProperties,
clusterMap,
out glyphProperties,
out glyphCount
);
}
}
return glyphs;
}
///
/// Shape specified character string into an array of missing glyphs
///
///
/// Critical - the method probes into checked pointer
/// Safe - The method fills in null glyphs, null glyphs are ok to expose
///
[SecurityCritical, SecurityTreatAsSafe]
private unsafe ushort[] GetNullGlyphs(
int length,
CheckedCharPointer characterString,
CheckedCharacterShapingPropertiesPointer characterProperties,
CheckedUShortPointer clusterMap,
out GlyphShapingProperties[] glyphProperties,
out int glyphCount
)
{
glyphCount = 0;
ushort[] glyphs = new ushort[length];
glyphProperties = new GlyphShapingProperties[length];
// Probe into the checked pointer
ushort * pClusterMap = clusterMap.Probe(0, length);
CharacterShapingProperties* pCharacterProperties = characterProperties.Probe(0, length);
char * charBuffer = characterString.Probe(0, length);
int wordCount;
for(int i = 0; i < length; i = i + wordCount)
{
wordCount = 1;
pClusterMap[i] = (ushort) glyphCount;
pCharacterProperties[i].CanGlyphAlone = true;
pCharacterProperties[i].EngineReserved = 0; // Engine reserved. Single glyph cluster
glyphs[glyphCount] = 0;
glyphProperties[glyphCount] = new GlyphShapingProperties(
(ushort)(GlyphFlags.ClusterStart | GlyphFlags.Unresolved), // glyph flags
(ushort)((1 << 8) | 0) // Engine reserved. Single glyph cluster
);
glyphCount ++;
if (i < length -1 && ((charBuffer[i] & 0xFC00) == 0xD800) && ((charBuffer[i + 1] & 0xFC00) == 0xDC00))
{
// Both higher and lower surrogate should point to the same glyph.
wordCount = 2;
pClusterMap[i + 1] = pClusterMap[i];
pCharacterProperties[i + 1].CanGlyphAlone = true;
}
}
return glyphs;
}
///
/// Get placement of glyphs
///
internal sealed override void GetGlyphPlacements(
CheckedUShortPointer glyphIndices,
CheckedGlyphShapingPropertiesPointer glyphProperties,
int glyphCount,
CheckedUShortPointer clusterMap,
CheckedCharacterShapingPropertiesPointer characterProperties,
int length,
ShapingOptions shapeOptions,
FeatureSet featureSet,
double scalingFactor,
CheckedIntPointer glyphAdvances,
CheckedGlyphOffsetPointer glyphOffsets
)
{
Invariant.Assert(_shapeTypeface != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
_shapeTypeface.GetGlyphPlacements(
_characterBufferRange,
glyphIndices,
glyphProperties,
glyphCount,
_textItem,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
clusterMap,
characterProperties,
length,
shapeOptions,
featureSet,
_emSize * scalingFactor,
glyphAdvances,
glyphOffsets
);
}
///
/// Compute a shaped glyph run object from specified glyph-based info
///
internal sealed override GlyphRun ComputeShapedGlyphRun(
Point origin,
char[] characterString,
ushort[] clusterMap,
ushort[] glyphIndices,
GlyphShapingProperties[] glyphProperties,
IList glyphAdvances,
IList glyphOffsets,
bool rightToLeft,
bool sideways
)
{
Invariant.Assert(_shapeTypeface != null);
Invariant.Assert(glyphIndices != null);
// Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set
// will a potential device font be ignored and come through shaping.
Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null);
bool[] caretStops = null;
if ( clusterMap != null
&& (HasExtendedCharacter || NeedsCaretInfo)
)
{
caretStops = new bool[clusterMap.Length + 1];
// caret stops at cluster boundaries, the first and the last entries are always set
caretStops[0] = true;
caretStops[clusterMap.Length] = true;
ushort lastGlyph = clusterMap[0];
for (int i = 1; i < clusterMap.Length; i++)
{
ushort glyph = clusterMap[i];
if (glyph != lastGlyph)
{
caretStops[i] = true;
lastGlyph = glyph;
}
}
}
return GlyphRun.TryCreate(
_shapeTypeface.GlyphTypeface,
(rightToLeft ? 1 : 0),
sideways,
_emSize,
glyphIndices,
origin,
glyphAdvances,
glyphOffsets,
characterString,
null,
clusterMap,
caretStops,
XmlLanguage.GetLanguage(CultureMapper.GetSpecificCulture(_properties.CultureInfo).IetfLanguageTag)
);
}
private GlyphTypeface GetGlyphTypeface(out bool nullFont)
{
GlyphTypeface glyphTypeface;
if (_shapeTypeface == null)
{
// We're in the optimized path where the GlyphTypeface depends only
// on the Typeface, not on the particular input characters.
Typeface typeface = _properties.Typeface;
// Get the GlyphTypeface.
glyphTypeface = typeface.TryGetGlyphTypeface();
// If Typeface does not specify *any* valid font family, then we use
// the GlyphTypeface for Arial but only to display missing glyphs.
nullFont = typeface.NullFont;
}
else
{
// Font linking has mapped the input to a specific GlyphTypeface.
glyphTypeface = _shapeTypeface.GlyphTypeface;
// If font linking could not find *any* physical font family, then we
// use the GlyphTypeface for Arial but only to display missing glyphs.
nullFont = _nullShape;
}
Invariant.Assert(glyphTypeface != null);
return glyphTypeface;
}
///
/// Compute unshaped glyph run object from the specified character-based info
///
internal sealed override GlyphRun ComputeUnshapedGlyphRun(
Point origin,
char[] characterString,
IList characterAdvances
)
{
bool nullFont;
GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
Invariant.Assert(glyphTypeface != null);
return glyphTypeface.ComputeUnshapedGlyphRun(
origin,
new CharacterBufferRange(
characterString,
0, // offsetToFirstChar
characterString.Length
),
characterAdvances,
_emSize,
_properties.FontHintingEmSize,
nullFont,
CultureMapper.GetSpecificCulture(_properties.CultureInfo),
(_shapeTypeface == null || _shapeTypeface.DeviceFont == null) ? null : _shapeTypeface.DeviceFont.Name
);
}
///
/// Draw glyph run to the drawing surface
///
internal sealed override void Draw(
DrawingContext drawingContext,
Brush foregroundBrush,
GlyphRun glyphRun
)
{
if (drawingContext == null)
throw new ArgumentNullException("drawingContext");
glyphRun.EmitBackground(drawingContext, _properties.BackgroundBrush);
drawingContext.DrawGlyphRun(
foregroundBrush != null ? foregroundBrush : _properties.ForegroundBrush,
glyphRun
);
}
///
/// Get advance widths of unshaped characters
///
///
/// Critical: This code calls into unsafe code blocks
///
[SecurityCritical]
internal sealed override unsafe void GetAdvanceWidthsUnshaped(
char* characterString,
int characterLength,
double scalingFactor,
int* advanceWidthsUnshaped
)
{
if (!IsShapingRequired)
{
if ( (_shapeTypeface != null)
&& (_shapeTypeface.DeviceFont != null))
{
// Use device font to compute advance widths
_shapeTypeface.DeviceFont.GetAdvanceWidths(
characterString,
characterLength,
_emSize * scalingFactor,
advanceWidthsUnshaped
);
}
else
{
bool nullFont;
GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont);
Invariant.Assert(glyphTypeface != null);
glyphTypeface.GetAdvanceWidthsUnshaped(
characterString,
characterLength,
_emSize * scalingFactor,
advanceWidthsUnshaped,
nullFont
);
}
}
else
{
GlyphTypeface glyphTypeface = _shapeTypeface.GlyphTypeface;
Invariant.Assert(glyphTypeface != null);
Invariant.Assert(characterLength > 0);
IDictionary cmap = glyphTypeface.CharacterToGlyphMap;
// compensate for approximated usual reduction of shaped widths for complex script
scalingFactor *= ApproximateNominalToIdealWidthRatio * _emSize;
for (int i = 0; i < characterLength; i++)
{
ushort glyphIndex;
cmap.TryGetValue(characterString[i], out glyphIndex);
advanceWidthsUnshaped[i] = (int)Math.Round(scalingFactor * glyphTypeface.GetAdvanceWidth(glyphIndex));
}
}
}
///
/// Get the ratio of typical ideal glyph width over nominal character width. It is used to
/// compensate the usual reduction of shaped widths.
///
internal sealed override double ApproximateNominalToIdealWidthRatio
{
get
{
double nominalToIdealWidthRatio = 1.0;
// Apply a scaling ratio if:
// 1) the script is not Latin (hence more likely to formed into ligature)
// 2) or the run contains combining mark or extended characters
if ( _textItem.Script != ScriptID.Latin
|| (_textItem.Flags & (ItemFlags.HasCombiningMark | ItemFlags.HasExtendedCharacter)) != 0
)
{
nominalToIdealWidthRatio = IsScriptIndic(_textItem.Script) ? 0.35 : 0.75;
}
return nominalToIdealWidthRatio;
}
}
///
/// Returns true if specified script is Indic.
///
private bool IsScriptIndic(ScriptID script)
{
return script == ScriptID.Bengali
|| script == ScriptID.Devanagari
|| script == ScriptID.Gurmukhi
|| script == ScriptID.Gujarati
|| script == ScriptID.Kannada
|| script == ScriptID.Malayalam
|| script == ScriptID.Oriya
|| script == ScriptID.Tamil
|| script == ScriptID.Telugu;
}
///
/// Return value indicates whether two runs can shape together
///
internal sealed override bool CanShapeTogether(
TextShapeableSymbols shapeable
)
{
TextShapeableCharacters charShape = shapeable as TextShapeableCharacters;
if (charShape == null)
return false;
return
_shapeTypeface.Equals(charShape._shapeTypeface)
&& _textItem.Script == charShape._textItem.Script
// Extended characters need to be shaped by surrogate shaper. They cannot be shaped together with non-exteneded characters.
&& (_textItem.Flags & ItemFlags.HasExtendedCharacter) == (charShape._textItem.Flags & ItemFlags.HasExtendedCharacter)
&& _emSize == charShape._emSize
&& (
_properties.CultureInfo == null ?
charShape._properties.CultureInfo == null
: _properties.CultureInfo.Equals(charShape._properties.CultureInfo)
)
&& _nullShape == charShape._nullShape;
}
///
/// Indicate whether run cannot be treated as simple characters because shaping is required.
///
/// The following cases use simple rendering without shaping:
/// o No _shapeTypeface. This happens in very simple rendering cases.
/// o Non-Unicode (i.e. symbol) fonts.
/// o When using a device font.
///
/// Note that the presence of a device font in _shapeTypeface.DeviceFont implies use of
/// a device font in all cases except where digit substitution applies. This special
/// case occurs because the cached result per codepoint of TypefaceMap must include the device font
/// for non-western digits in order to support device font rendering of the non-Western
/// digit Unicode codepoints. The device font is not used however when the non-Western digits
/// are displayed as a result of digit substitution from backing store Western digits.
///
internal sealed override bool IsShapingRequired
{
get
{
return
(_shapeTypeface != null) // Can't use shaping without a shape typeface
&& ( (_shapeTypeface.DeviceFont == null) // Can't use shaping when rendering with a device font
|| (_textItem.DigitCulture != null)) // -- unless substituting digits
&& (!IsSymbol); // Can't use shaping for symbol (non-Unicode) fonts
}
}
///
/// A Boolean value indicates whether additional info is required for caret positioning
///
internal sealed override bool NeedsCaretInfo
{
get
{
return (_textItem.Flags & ItemFlags.HasCombiningMark) != 0
|| (Script.Flags[(int)_textItem.Script] & ScriptFlags.NeedsCaretInfo) != 0;
}
}
///
/// A Boolean value indicates whether run has extended character
///
internal sealed override bool HasExtendedCharacter
{
get
{
return (_textItem.Flags & ItemFlags.HasExtendedCharacter) != 0;
}
}
///
/// Run height
///
internal sealed override double Height
{
get
{
return _properties.Typeface.LineSpacing * _properties.FontRenderingEmSize;
}
}
///
/// Distance from top to baseline
///
internal sealed override double Baseline
{
get
{
return _properties.Typeface.Baseline * _properties.FontRenderingEmSize;
}
}
///
/// Distance from baseline to underline position relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double UnderlinePosition
{
get
{
return _properties.Typeface.UnderlinePosition;
}
}
///
/// Underline thickness relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double UnderlineThickness
{
get
{
return _properties.Typeface.UnderlineThickness;
}
}
///
/// Distance from baseline to strike-through position relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double StrikethroughPosition
{
get
{
return _properties.Typeface.StrikethroughPosition;
}
}
///
/// strike-through thickness relative to TextRunProperties.FontRenderingEmSize
///
internal sealed override double StrikethroughThickness
{
get
{
return _properties.Typeface.StrikethroughThickness;
}
}
#endregion
///
/// Whether all characters in this run are non-Unicode character (symbol)
///
internal bool IsSymbol
{
get
{
if (_shapeTypeface != null)
return _shapeTypeface.GlyphTypeface.Symbol;
return _properties.Typeface.Symbol;
}
}
///
/// Returns maximum possible cluster size for the run. Normally, this
/// is 8 characters, but Indic scripts require this to be 15.
///
internal const ushort DefaultMaxClusterSize = 8;
private const ushort IndicMaxClusterSize = 15;
internal sealed override ushort MaxClusterSize
{
get
{
switch (_textItem.Script)
{
case ScriptID.Bengali:
case ScriptID.Devanagari:
case ScriptID.Gurmukhi:
case ScriptID.Gujarati:
case ScriptID.Kannada:
case ScriptID.Malayalam:
case ScriptID.Oriya:
case ScriptID.Tamil:
case ScriptID.Telugu:
return IndicMaxClusterSize;
}
return DefaultMaxClusterSize;
}
}
}
}
// 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
- MeasureItemEvent.cs
- DetailsViewUpdateEventArgs.cs
- AvTraceDetails.cs
- DataControlImageButton.cs
- AudioFileOut.cs
- AddInAttribute.cs
- UpdatableGenericsFeature.cs
- SqlDependencyUtils.cs
- WebPartConnectVerb.cs
- FontUnitConverter.cs
- entityreference_tresulttype.cs
- SimpleBitVector32.cs
- UserMapPath.cs
- NestPullup.cs
- ModifiableIteratorCollection.cs
- CompModSwitches.cs
- SetStoryboardSpeedRatio.cs
- MediaScriptCommandRoutedEventArgs.cs
- MenuItemBinding.cs
- BaseCAMarshaler.cs
- ExtensionSimplifierMarkupObject.cs
- BulletedList.cs
- GZipDecoder.cs
- x509store.cs
- CachedFontFamily.cs
- AudioBase.cs
- HwndKeyboardInputProvider.cs
- ILGenerator.cs
- TransactionOptions.cs
- ScriptRegistrationManager.cs
- FontDialog.cs
- NetworkStream.cs
- PropertyPushdownHelper.cs
- ClientCredentials.cs
- ControlUtil.cs
- SizeConverter.cs
- CapabilitiesPattern.cs
- LoginStatusDesigner.cs
- PropertyInformation.cs
- CommandField.cs
- Vertex.cs
- __Filters.cs
- CodeAttributeDeclaration.cs
- CompositeDataBoundControl.cs
- ListViewAutomationPeer.cs
- RemoteCryptoTokenProvider.cs
- DesignerAdRotatorAdapter.cs
- BaseCodeDomTreeGenerator.cs
- ClipboardData.cs
- DataBoundLiteralControl.cs
- CompilationSection.cs
- OracleFactory.cs
- CategoryAttribute.cs
- BufferedWebEventProvider.cs
- SmtpFailedRecipientException.cs
- PopupRoot.cs
- WebBaseEventKeyComparer.cs
- QfeChecker.cs
- PageContentCollection.cs
- ByteArrayHelperWithString.cs
- MonitoringDescriptionAttribute.cs
- AutomationIdentifierGuids.cs
- SqlDataSourceDesigner.cs
- PropertyCollection.cs
- __Error.cs
- PagerStyle.cs
- DispatchChannelSink.cs
- ResourcePool.cs
- FieldDescriptor.cs
- QilFactory.cs
- ConfigurationElementCollection.cs
- NameValueFileSectionHandler.cs
- TitleStyle.cs
- TableLayoutPanelResizeGlyph.cs
- TimeSpan.cs
- Light.cs
- EncoderBestFitFallback.cs
- RemoteWebConfigurationHostStream.cs
- FastPropertyAccessor.cs
- WCFServiceClientProxyGenerator.cs
- Endpoint.cs
- TextWriter.cs
- TempFiles.cs
- QueryOutputWriter.cs
- AdCreatedEventArgs.cs
- StreamReader.cs
- ReplyChannelAcceptor.cs
- NavigationEventArgs.cs
- ManifestResourceInfo.cs
- loginstatus.cs
- WebScriptEndpointElement.cs
- TakeQueryOptionExpression.cs
- ProtocolsConfigurationEntry.cs
- OverrideMode.cs
- XPathExpr.cs
- OutputCacheProfileCollection.cs
- XmlDataDocument.cs
- ErrorProvider.cs
- _ListenerResponseStream.cs
- Registry.cs