Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / TextFormatting / TextShapeableCharacters.cs / 3 / TextShapeableCharacters.cs
//------------------------------------------------------------------------
//
// Microsoft Windows Client Platform
// Copyright (C) Microsoft Corporation
//
// File: TextShapeableCharacters.cs
//
// Contents: Implementation of text shapeable symbols for characters
//
// Spec: [....]/sites/Avalon/Specs/Text%20Formatting%20API.doc
//
// Created: 1-2-2004 [....] ([....])
// 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
- GridViewDeletedEventArgs.cs
- NullRuntimeConfig.cs
- IpcPort.cs
- MemoryMappedViewAccessor.cs
- StandardOleMarshalObject.cs
- DataGridCell.cs
- XamlToRtfWriter.cs
- WebHttpSecurityElement.cs
- TextEditorContextMenu.cs
- SafeMarshalContext.cs
- FrameworkElementFactory.cs
- Timeline.cs
- XmlNamedNodeMap.cs
- ToolboxItem.cs
- DiagnosticSection.cs
- SQLInt32.cs
- CreateUserWizard.cs
- VectorValueSerializer.cs
- RuleRefElement.cs
- SimpleRecyclingCache.cs
- FloaterParagraph.cs
- UIElementAutomationPeer.cs
- HtmlElementCollection.cs
- DomainConstraint.cs
- OpCopier.cs
- ScaleTransform.cs
- WebSysDefaultValueAttribute.cs
- CodeArrayIndexerExpression.cs
- LoadGrammarCompletedEventArgs.cs
- PropertyOrder.cs
- newinstructionaction.cs
- ExternalDataExchangeService.cs
- Process.cs
- NativeMethods.cs
- HttpDebugHandler.cs
- SystemWebExtensionsSectionGroup.cs
- ImmComposition.cs
- OLEDB_Enum.cs
- MultilineStringConverter.cs
- BadImageFormatException.cs
- MediaContext.cs
- MultiByteCodec.cs
- Style.cs
- ImageBrush.cs
- securestring.cs
- ReachUIElementCollectionSerializer.cs
- OpCellTreeNode.cs
- IdleTimeoutMonitor.cs
- HtmlSelect.cs
- ApplyHostConfigurationBehavior.cs
- ResXResourceReader.cs
- XmlEventCache.cs
- WebPartsSection.cs
- WebBrowserNavigatingEventHandler.cs
- RuleSettings.cs
- MetadataArtifactLoaderCompositeResource.cs
- StreamSecurityUpgradeAcceptor.cs
- LiteralControl.cs
- LinkArea.cs
- _SSPIWrapper.cs
- AssertFilter.cs
- NetworkStream.cs
- LinkedList.cs
- UnsafeMethods.cs
- MissingManifestResourceException.cs
- VirtualDirectoryMapping.cs
- ObjectQueryExecutionPlan.cs
- Polyline.cs
- SequentialUshortCollection.cs
- GrammarBuilderWildcard.cs
- xmlsaver.cs
- TransformGroup.cs
- ResourceManager.cs
- ResourceReader.cs
- Endpoint.cs
- PageAsyncTask.cs
- CustomTypeDescriptor.cs
- ContextMenuAutomationPeer.cs
- KoreanLunisolarCalendar.cs
- DataSourceXmlSerializer.cs
- WebFaultClientMessageInspector.cs
- XmlUnspecifiedAttribute.cs
- HtmlTextArea.cs
- TreeSet.cs
- OleCmdHelper.cs
- ClientSideQueueItem.cs
- TypeForwardedToAttribute.cs
- DataSourceControl.cs
- SqlTypeConverter.cs
- RawStylusSystemGestureInputReport.cs
- CalendarModeChangedEventArgs.cs
- WebPartDisplayModeCollection.cs
- GeneralTransform2DTo3DTo2D.cs
- IconBitmapDecoder.cs
- InternalsVisibleToAttribute.cs
- FormViewDeleteEventArgs.cs
- ScriptDescriptor.cs
- SafeNativeMethods.cs
- HttpPostProtocolReflector.cs
- ListMarkerLine.cs