Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / GlyphsSerializer.cs / 1305600 / GlyphsSerializer.cs
//------------------------------------------------------------------------------
// Microsoft Avalon
// Copyright (c) Microsoft Corporation, all rights reserved
//
// File: GlyphsSerializer.cs
//
//-----------------------------------------------------------------------------
using System;
using System.Windows.Threading;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using MS.Internal;
using MS.Win32;
using Microsoft.Win32.SafeHandles;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using System.Security.Permissions;
using MS.Internal.PresentationCore;
namespace System.Windows.Media
{
///
///
///
[FriendAccessAllowed] // used by System.Printing.dll
internal class GlyphsSerializer
{
#region public methods
///
///
///
///
public GlyphsSerializer(GlyphRun glyphRun)
{
if (glyphRun == null)
{
throw new ArgumentNullException("glyphRun");
}
_glyphTypeface = glyphRun.GlyphTypeface;
_milToEm = EmScaleFactor / glyphRun.FontRenderingEmSize;
_sideways = glyphRun.IsSideways;
_characters = glyphRun.Characters;
_caretStops = glyphRun.CaretStops;
// the first value in the cluster map can be non-zero, in which case it's applied as an offset to all
// subsequent entries in the cluster map
_clusters = glyphRun.ClusterMap;
if (_clusters != null)
_glyphClusterInitialOffset = _clusters[0];
_indices = glyphRun.GlyphIndices;
_advances = glyphRun.AdvanceWidths;
_offsets = glyphRun.GlyphOffsets;
// "100,50,,0;".Length is a capacity estimate for an individual glyph
_glyphStringBuider = new StringBuilder(10);
// string length * _glyphStringBuider.Capacity is an estimate for the whole string
_indicesStringBuider = new StringBuilder(
Math.Max(
(_characters == null ? 0 : _characters.Count),
_indices.Count
)
* _glyphStringBuider.Capacity
);
}
///
/// Encode glyph run glyph information into Indices, UnicodeString and CaretStops string.
///
public void ComputeContentStrings(out string characters, out string indices, out string caretStops)
{
if (_clusters != null)
{
// the algorithm works by finding (n:m) clusters and appending m glyphs for each cluster
int characterIndex;
int glyphClusterStart = 0;
int charClusterStart = 0;
bool forceNewCluster = true;
for (characterIndex = 0; characterIndex < _clusters.Count; ++characterIndex)
{
if (forceNewCluster)
{
glyphClusterStart = _clusters[characterIndex];
charClusterStart = characterIndex;
forceNewCluster = false;
continue;
}
if (_clusters[characterIndex] != glyphClusterStart)
{
// end of cluster, flush it
Debug.Assert(_clusters[characterIndex] > glyphClusterStart);
AddCluster(glyphClusterStart - _glyphClusterInitialOffset, _clusters[characterIndex] - _glyphClusterInitialOffset, charClusterStart, characterIndex);
// start a new cluster
glyphClusterStart = _clusters[characterIndex];
charClusterStart = characterIndex;
}
// otherwise, we are still within a cluster
}
// flush the last cluster
Debug.Assert(_indices.Count > glyphClusterStart - _glyphClusterInitialOffset);
AddCluster(glyphClusterStart - _glyphClusterInitialOffset, _indices.Count, charClusterStart, characterIndex);
}
else
{
// zero cluster map means 1:1 mapping
Debug.Assert(_characters == null || _characters.Count == 0 || _indices.Count == _characters.Count);
for (int i = 0; i < _indices.Count; ++i)
AddCluster(i, i + 1, i, i + 1);
}
// remove trailing semicolons
RemoveTrailingCharacters(_indicesStringBuider, GlyphSeparator);
indices = _indicesStringBuider.ToString();
if (_characters == null || _characters.Count == 0)
{
characters = string.Empty;
}
else
{
StringBuilder builder = new StringBuilder(_characters.Count);
foreach(char ch in _characters)
{
builder.Append(ch);
}
characters = builder.ToString();
}
caretStops = CreateCaretStopsString();
}
#endregion public methods
#region private methods
private void RemoveTrailingCharacters(StringBuilder sb, char trailingCharacter)
{
int length = sb.Length;
int trailingCharIndex = length - 1;
while (trailingCharIndex >= 0)
{
if (sb[trailingCharIndex] != trailingCharacter)
break;
--trailingCharIndex;
}
sb.Length = trailingCharIndex + 1;
}
private void AddGlyph(int glyph, int sourceCharacter)
{
Debug.Assert(_glyphStringBuider.Length == 0);
// glyph index
ushort fontIndex = _indices[glyph];
ushort glyphIndexFromCmap;
if (sourceCharacter == -1 ||
!_glyphTypeface.CharacterToGlyphMap.TryGetValue(sourceCharacter, out glyphIndexFromCmap) ||
fontIndex != glyphIndexFromCmap)
{
_glyphStringBuider.Append(fontIndex.ToString(CultureInfo.InvariantCulture));
}
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// advance width
int normalizedAdvance = (int)Math.Round(_advances[glyph] * _milToEm);
double fontAdvance = _sideways ? _glyphTypeface.AdvanceHeights[fontIndex] : _glyphTypeface.AdvanceWidths[fontIndex];
if (normalizedAdvance != (int)Math.Round(fontAdvance * EmScaleFactor))
{
_glyphStringBuider.Append(normalizedAdvance.ToString(CultureInfo.InvariantCulture));
}
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// u,v offset
if (_offsets != null)
{
// u offset
int offset = (int)Math.Round(_offsets[glyph].X * _milToEm);
if (offset != 0)
_glyphStringBuider.Append(offset.ToString(CultureInfo.InvariantCulture));
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// v offset
offset = (int)Math.Round(_offsets[glyph].Y * _milToEm);
if (offset != 0)
_glyphStringBuider.Append(offset.ToString(CultureInfo.InvariantCulture));
_glyphStringBuider.Append(GlyphSubEntrySeparator);
}
// flags are not implemented yet
// remove trailing commas
RemoveTrailingCharacters(_glyphStringBuider, GlyphSubEntrySeparator);
_glyphStringBuider.Append(GlyphSeparator);
_indicesStringBuider.Append(_glyphStringBuider.ToString());
// reset for next glyph
_glyphStringBuider.Length = 0;
}
private void AddCluster(int glyphClusterStart, int glyphClusterEnd, int charClusterStart, int charClusterEnd)
{
int charactersInCluster = charClusterEnd - charClusterStart;
int glyphsInCluster = glyphClusterEnd - glyphClusterStart;
// no source character to deduce glyph properties from
int sourceCharacter = -1;
// the format is ... [(CharacterClusterSize[:GlyphClusterSize])] GlyphIndex ...
if (glyphsInCluster != 1)
{
_indicesStringBuider.AppendFormat(CultureInfo.InvariantCulture, "({0}:{1})", charactersInCluster, glyphsInCluster);
}
else
{
if (charactersInCluster != 1)
_indicesStringBuider.AppendFormat(CultureInfo.InvariantCulture, "({0})", charactersInCluster);
else
{
// 1:1 cluster, we can omit (n:m) specification and possibly deduce some
// glyph properties from character
if (_characters != null && _characters.Count != 0)
sourceCharacter = _characters[charClusterStart];
}
}
for (int glyph = glyphClusterStart; glyph < glyphClusterEnd; ++glyph)
{
AddGlyph(glyph, sourceCharacter);
}
}
private string CreateCaretStopsString()
{
if (_caretStops == null)
return String.Empty;
// Since the trailing 0xF (i.e. all true) entries in the caret stop specifications can be omitted,
// we can limit the caret stop list walk until the last nibble that contains 'false'.
int caretStopStringLength = 0;
int lastCaretStop = 0;
for (int i = _caretStops.Count - 1; i >= 0; --i)
{
if (!_caretStops[i])
{
caretStopStringLength = (i + 4) / 4;
// lastCaretStop to consider when building, the rest will correpond to 0xF entries
lastCaretStop = Math.Min(i | 3, _caretStops.Count - 1);
break;
}
}
// All values are set to true, so we don't have to include caret stop string at all.
if (caretStopStringLength == 0)
return String.Empty;
StringBuilder sb = new StringBuilder(caretStopStringLength);
byte mask = 0x8;
byte accumulatedValue = 0;
for (int i = 0; i <= lastCaretStop; ++i)
{
if (_caretStops[i])
accumulatedValue |= mask;
if (mask != 1)
mask >>= 1;
else
{
sb.AppendFormat("{0:x1}", accumulatedValue);
accumulatedValue = 0;
mask = 0x8;
}
}
if (mask != 0x8)
sb.AppendFormat("{0:x1}", accumulatedValue);
Debug.Assert(caretStopStringLength == sb.ToString().Length);
return sb.ToString();
}
#endregion private methods
#region private data
private GlyphTypeface _glyphTypeface;
private IList _characters;
private double _milToEm;
private bool _sideways;
private int _glyphClusterInitialOffset;
private IList _clusters;
private IList _indices;
private IList _advances;
private IList _offsets;
private IList _caretStops;
private StringBuilder _indicesStringBuider;
private StringBuilder _glyphStringBuider;
private const char GlyphSubEntrySeparator = ',';
private const char GlyphSeparator = ';';
private const double EmScaleFactor = 100.0;
#endregion region private data
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
// Microsoft Avalon
// Copyright (c) Microsoft Corporation, all rights reserved
//
// File: GlyphsSerializer.cs
//
//-----------------------------------------------------------------------------
using System;
using System.Windows.Threading;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using MS.Internal;
using MS.Win32;
using Microsoft.Win32.SafeHandles;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using System.Security.Permissions;
using MS.Internal.PresentationCore;
namespace System.Windows.Media
{
///
///
///
[FriendAccessAllowed] // used by System.Printing.dll
internal class GlyphsSerializer
{
#region public methods
///
///
///
///
public GlyphsSerializer(GlyphRun glyphRun)
{
if (glyphRun == null)
{
throw new ArgumentNullException("glyphRun");
}
_glyphTypeface = glyphRun.GlyphTypeface;
_milToEm = EmScaleFactor / glyphRun.FontRenderingEmSize;
_sideways = glyphRun.IsSideways;
_characters = glyphRun.Characters;
_caretStops = glyphRun.CaretStops;
// the first value in the cluster map can be non-zero, in which case it's applied as an offset to all
// subsequent entries in the cluster map
_clusters = glyphRun.ClusterMap;
if (_clusters != null)
_glyphClusterInitialOffset = _clusters[0];
_indices = glyphRun.GlyphIndices;
_advances = glyphRun.AdvanceWidths;
_offsets = glyphRun.GlyphOffsets;
// "100,50,,0;".Length is a capacity estimate for an individual glyph
_glyphStringBuider = new StringBuilder(10);
// string length * _glyphStringBuider.Capacity is an estimate for the whole string
_indicesStringBuider = new StringBuilder(
Math.Max(
(_characters == null ? 0 : _characters.Count),
_indices.Count
)
* _glyphStringBuider.Capacity
);
}
///
/// Encode glyph run glyph information into Indices, UnicodeString and CaretStops string.
///
public void ComputeContentStrings(out string characters, out string indices, out string caretStops)
{
if (_clusters != null)
{
// the algorithm works by finding (n:m) clusters and appending m glyphs for each cluster
int characterIndex;
int glyphClusterStart = 0;
int charClusterStart = 0;
bool forceNewCluster = true;
for (characterIndex = 0; characterIndex < _clusters.Count; ++characterIndex)
{
if (forceNewCluster)
{
glyphClusterStart = _clusters[characterIndex];
charClusterStart = characterIndex;
forceNewCluster = false;
continue;
}
if (_clusters[characterIndex] != glyphClusterStart)
{
// end of cluster, flush it
Debug.Assert(_clusters[characterIndex] > glyphClusterStart);
AddCluster(glyphClusterStart - _glyphClusterInitialOffset, _clusters[characterIndex] - _glyphClusterInitialOffset, charClusterStart, characterIndex);
// start a new cluster
glyphClusterStart = _clusters[characterIndex];
charClusterStart = characterIndex;
}
// otherwise, we are still within a cluster
}
// flush the last cluster
Debug.Assert(_indices.Count > glyphClusterStart - _glyphClusterInitialOffset);
AddCluster(glyphClusterStart - _glyphClusterInitialOffset, _indices.Count, charClusterStart, characterIndex);
}
else
{
// zero cluster map means 1:1 mapping
Debug.Assert(_characters == null || _characters.Count == 0 || _indices.Count == _characters.Count);
for (int i = 0; i < _indices.Count; ++i)
AddCluster(i, i + 1, i, i + 1);
}
// remove trailing semicolons
RemoveTrailingCharacters(_indicesStringBuider, GlyphSeparator);
indices = _indicesStringBuider.ToString();
if (_characters == null || _characters.Count == 0)
{
characters = string.Empty;
}
else
{
StringBuilder builder = new StringBuilder(_characters.Count);
foreach(char ch in _characters)
{
builder.Append(ch);
}
characters = builder.ToString();
}
caretStops = CreateCaretStopsString();
}
#endregion public methods
#region private methods
private void RemoveTrailingCharacters(StringBuilder sb, char trailingCharacter)
{
int length = sb.Length;
int trailingCharIndex = length - 1;
while (trailingCharIndex >= 0)
{
if (sb[trailingCharIndex] != trailingCharacter)
break;
--trailingCharIndex;
}
sb.Length = trailingCharIndex + 1;
}
private void AddGlyph(int glyph, int sourceCharacter)
{
Debug.Assert(_glyphStringBuider.Length == 0);
// glyph index
ushort fontIndex = _indices[glyph];
ushort glyphIndexFromCmap;
if (sourceCharacter == -1 ||
!_glyphTypeface.CharacterToGlyphMap.TryGetValue(sourceCharacter, out glyphIndexFromCmap) ||
fontIndex != glyphIndexFromCmap)
{
_glyphStringBuider.Append(fontIndex.ToString(CultureInfo.InvariantCulture));
}
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// advance width
int normalizedAdvance = (int)Math.Round(_advances[glyph] * _milToEm);
double fontAdvance = _sideways ? _glyphTypeface.AdvanceHeights[fontIndex] : _glyphTypeface.AdvanceWidths[fontIndex];
if (normalizedAdvance != (int)Math.Round(fontAdvance * EmScaleFactor))
{
_glyphStringBuider.Append(normalizedAdvance.ToString(CultureInfo.InvariantCulture));
}
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// u,v offset
if (_offsets != null)
{
// u offset
int offset = (int)Math.Round(_offsets[glyph].X * _milToEm);
if (offset != 0)
_glyphStringBuider.Append(offset.ToString(CultureInfo.InvariantCulture));
_glyphStringBuider.Append(GlyphSubEntrySeparator);
// v offset
offset = (int)Math.Round(_offsets[glyph].Y * _milToEm);
if (offset != 0)
_glyphStringBuider.Append(offset.ToString(CultureInfo.InvariantCulture));
_glyphStringBuider.Append(GlyphSubEntrySeparator);
}
// flags are not implemented yet
// remove trailing commas
RemoveTrailingCharacters(_glyphStringBuider, GlyphSubEntrySeparator);
_glyphStringBuider.Append(GlyphSeparator);
_indicesStringBuider.Append(_glyphStringBuider.ToString());
// reset for next glyph
_glyphStringBuider.Length = 0;
}
private void AddCluster(int glyphClusterStart, int glyphClusterEnd, int charClusterStart, int charClusterEnd)
{
int charactersInCluster = charClusterEnd - charClusterStart;
int glyphsInCluster = glyphClusterEnd - glyphClusterStart;
// no source character to deduce glyph properties from
int sourceCharacter = -1;
// the format is ... [(CharacterClusterSize[:GlyphClusterSize])] GlyphIndex ...
if (glyphsInCluster != 1)
{
_indicesStringBuider.AppendFormat(CultureInfo.InvariantCulture, "({0}:{1})", charactersInCluster, glyphsInCluster);
}
else
{
if (charactersInCluster != 1)
_indicesStringBuider.AppendFormat(CultureInfo.InvariantCulture, "({0})", charactersInCluster);
else
{
// 1:1 cluster, we can omit (n:m) specification and possibly deduce some
// glyph properties from character
if (_characters != null && _characters.Count != 0)
sourceCharacter = _characters[charClusterStart];
}
}
for (int glyph = glyphClusterStart; glyph < glyphClusterEnd; ++glyph)
{
AddGlyph(glyph, sourceCharacter);
}
}
private string CreateCaretStopsString()
{
if (_caretStops == null)
return String.Empty;
// Since the trailing 0xF (i.e. all true) entries in the caret stop specifications can be omitted,
// we can limit the caret stop list walk until the last nibble that contains 'false'.
int caretStopStringLength = 0;
int lastCaretStop = 0;
for (int i = _caretStops.Count - 1; i >= 0; --i)
{
if (!_caretStops[i])
{
caretStopStringLength = (i + 4) / 4;
// lastCaretStop to consider when building, the rest will correpond to 0xF entries
lastCaretStop = Math.Min(i | 3, _caretStops.Count - 1);
break;
}
}
// All values are set to true, so we don't have to include caret stop string at all.
if (caretStopStringLength == 0)
return String.Empty;
StringBuilder sb = new StringBuilder(caretStopStringLength);
byte mask = 0x8;
byte accumulatedValue = 0;
for (int i = 0; i <= lastCaretStop; ++i)
{
if (_caretStops[i])
accumulatedValue |= mask;
if (mask != 1)
mask >>= 1;
else
{
sb.AppendFormat("{0:x1}", accumulatedValue);
accumulatedValue = 0;
mask = 0x8;
}
}
if (mask != 0x8)
sb.AppendFormat("{0:x1}", accumulatedValue);
Debug.Assert(caretStopStringLength == sb.ToString().Length);
return sb.ToString();
}
#endregion private methods
#region private data
private GlyphTypeface _glyphTypeface;
private IList _characters;
private double _milToEm;
private bool _sideways;
private int _glyphClusterInitialOffset;
private IList _clusters;
private IList _indices;
private IList _advances;
private IList _offsets;
private IList _caretStops;
private StringBuilder _indicesStringBuider;
private StringBuilder _glyphStringBuider;
private const char GlyphSubEntrySeparator = ',';
private const char GlyphSeparator = ';';
private const double EmScaleFactor = 100.0;
#endregion region private data
}
}
// 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
- ExpressionBuilderContext.cs
- AutomationPatternInfo.cs
- Encoding.cs
- CacheDependency.cs
- FlowLayoutPanel.cs
- RelatedEnd.cs
- PageThemeCodeDomTreeGenerator.cs
- PermissionSet.cs
- _NetworkingPerfCounters.cs
- ProofTokenCryptoHandle.cs
- BoundingRectTracker.cs
- EqualityComparer.cs
- Italic.cs
- DataGridColumnStyleMappingNameEditor.cs
- SqlParameterCollection.cs
- BrushConverter.cs
- WmfPlaceableFileHeader.cs
- SqlCommandBuilder.cs
- UrlAuthFailedErrorFormatter.cs
- WeakReadOnlyCollection.cs
- HttpSessionStateWrapper.cs
- TextRangeEditTables.cs
- XmlObjectSerializerContext.cs
- QueryOptionExpression.cs
- XsltContext.cs
- ToolStripDesignerAvailabilityAttribute.cs
- TriggerActionCollection.cs
- WmpBitmapDecoder.cs
- WebPartManager.cs
- DesignBindingConverter.cs
- HttpModuleCollection.cs
- PenLineCapValidation.cs
- ProfileSection.cs
- HtmlContainerControl.cs
- Faults.cs
- ConfigurationException.cs
- Table.cs
- Expression.cs
- PackageRelationship.cs
- formatstringdialog.cs
- UntrustedRecipientException.cs
- GradientBrush.cs
- PageSettings.cs
- XmlStreamNodeWriter.cs
- ThumbAutomationPeer.cs
- RadialGradientBrush.cs
- codemethodreferenceexpression.cs
- SmiMetaDataProperty.cs
- DataGrid.cs
- CommandEventArgs.cs
- BitmapFrameDecode.cs
- MessagePropertyFilter.cs
- MatchingStyle.cs
- Mappings.cs
- ToolStripManager.cs
- GridLength.cs
- TransactionInformation.cs
- TemplateEditingService.cs
- JsonDataContract.cs
- JsonXmlDataContract.cs
- ScriptDescriptor.cs
- ProgressBarHighlightConverter.cs
- TemplateBindingExtensionConverter.cs
- TypeElementCollection.cs
- Set.cs
- DbSetClause.cs
- Barrier.cs
- XmlSecureResolver.cs
- DynamicQueryableWrapper.cs
- ThemeableAttribute.cs
- TextRangeEditLists.cs
- ReceiveCompletedEventArgs.cs
- HttpValueCollection.cs
- BaseResourcesBuildProvider.cs
- ValueTypeFixupInfo.cs
- RowCache.cs
- WebRequestModulesSection.cs
- FastPropertyAccessor.cs
- ObjectAssociationEndMapping.cs
- XAMLParseException.cs
- WmpBitmapDecoder.cs
- TabControlToolboxItem.cs
- TextEffectCollection.cs
- DeleteStoreRequest.cs
- OneToOneMappingSerializer.cs
- StringUtil.cs
- DBDataPermission.cs
- PropertyMapper.cs
- MsmqInputSessionChannel.cs
- HighlightComponent.cs
- OverflowException.cs
- XmlILModule.cs
- DependencyPropertyChangedEventArgs.cs
- CurrentChangingEventManager.cs
- TcpProcessProtocolHandler.cs
- AppModelKnownContentFactory.cs
- BindingBase.cs
- DoubleConverter.cs
- BufferBuilder.cs
- WindowsListViewScroll.cs