Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / GlyphTypeface.cs / 1 / GlyphTypeface.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: GlyphTypeface implementation
//
// History:
// 06/04/2003 : mleonov - Moved GlyphTypeface from GlyphRun.cs
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows;
using System.Windows.Media.Composition;
using System.Windows.Media.TextFormatting;
using System.Windows.Markup;
using MS.Internal.FontRasterization;
using MS.Internal;
using MS.Internal.FontCache;
using MS.Internal.FontFace;
using MS.Internal.PresentationCore;
namespace System.Windows.Media
{
///
/// Physical font face corresponds to a font file on the disk
///
public class GlyphTypeface : ITypefaceMetrics, ISupportInitialize
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
///
/// Creates an uninitialized GlyphTypeface object. Caller should call ISupportInitialize.BeginInit()
/// to begin initializing the object and call ISupportInitialize.EndInit() to finish the initialization.
///
public GlyphTypeface()
{
}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface does not use style simulations.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
public GlyphTypeface(Uri typefaceSource) : this(typefaceSource, StyleSimulations.None)
{}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
/// Specifies style simulations to be applied to the newly created GlyphTypeface.
///
/// Critical - as this calls the internal constructor that's critical.
/// Safe - as the internal constructor does a Demand for FileIO for file
/// Uris for the case where fromPublic is true. We block constructing
/// GlyphTypeface directly in SEE since this'd allow guessing fonts on
/// a machine by trying to create a GlyphTypeface object.
///
///
[SecurityCritical]
public GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations) :
this (typefaceSource, styleSimulations, /* fromPublic = */ true)
{}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
/// Specifies style simulations to be applied to the newly created GlyphTypeface.
/// Specifies if the call to the constructor is from a public constructor
/// or if its from an internal method. For public constructor we demand FileIO for all files whereas
/// for internal calls we don't demand in the constructor.
///
/// Critical - as the instance of GlyphTypeface created with this constructor can
/// expose font information for the case where fromPublic is false.
///
[SecurityCritical]
internal GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
{
Initialize(typefaceSource, styleSimulations, fromPublic);
}
///
/// Critical - this method calls into other critical method.
///
[SecurityCritical]
private void Initialize(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
{
if (typefaceSource == null)
throw new ArgumentNullException("typefaceSource");
if (!typefaceSource.IsAbsoluteUri)
throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "typefaceSource");
// remember the original Uri that contains face index
_originalUri = new SecurityCriticalDataClass(typefaceSource);
// split the Uri into the font source Uri and face index
Uri fontSourceUri;
int faceIndex;
Util.SplitFontFaceIndex(typefaceSource, out fontSourceUri, out faceIndex);
_fileIOPermObj = new SecurityCriticalDataForSet(
SecurityHelper.CreateUriReadPermission(fontSourceUri)
);
// This permission demand is here so that untrusted callers are unable to check for file existence using GlyphTypeface ctor.
// Sensitive font data is protected by demands as the user tries to access it.
// The demand below is skipped for non-public calls, because in such cases
// fonts are exposed as logical fonts to the end user.
if (fromPublic)
DemandPermissionsForFontInformation();
// We skip permission demands for FontSource because the above line already demands them for the right callers.
_fontFace = new FontFaceLayoutInfo(new FontSource(fontSourceUri, true), faceIndex);
CacheManager.Lookup(_fontFace);
if ((styleSimulations & ~StyleSimulations.BoldItalicSimulation) != 0)
throw new InvalidEnumArgumentException("styleSimulations", (int)styleSimulations, typeof(StyleSimulations));
_styleSimulations = styleSimulations;
_initializationState = InitializationState.IsInitialized; // fully initialized
}
#endregion Constructors
//------------------------------------------------------
//
// Public Methods
//
//-----------------------------------------------------
#region Public Methods
///
/// Return hash code for this GlyphTypeface.
///
/// Hash code.
///
/// Critical - as this accesses _originalUri.
/// Safe - as this only does this to compute the hash code.
///
[SecurityCritical]
public override int GetHashCode()
{
CheckInitialized();
return _originalUri.Value.GetHashCode() ^ (int)StyleSimulations;
}
///
/// Compares this GlyphTypeface with another object.
///
/// Object to compare with.
/// Whether this object is equal to the input object.
///
/// Critical - as this accesses _originalUri.
/// Safe - as this only does this to perform a comparison with another object.
///
[SecurityCritical]
public override bool Equals(object o)
{
CheckInitialized();
GlyphTypeface t = o as GlyphTypeface;
if (t == null)
return false;
return StyleSimulations == t.StyleSimulations
&& _originalUri.Value == t._originalUri.Value;
}
///
/// Returns a geometry describing the path for a single glyph in the font.
/// The path represents the glyph
/// without grid fitting applied for rendering at a specific resolution.
///
/// Index of the glyph to get outline for.
/// Font size in drawing surface units.
/// Size to hint for in points.
///
[CLSCompliant(false)]
public Geometry GetGlyphOutline(ushort glyphIndex, double renderingEmSize, double hintingEmSize)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
// NOTE: This parameter is unused, and should be deleted. Not worth a breaking change just for this though.
return ComputeGlyphOutline(glyphIndex, false, renderingEmSize);
}
///
/// Returns the binary image of font subset.
///
/// Collection of glyph indices to be included into the subset.
/// Binary image of font subset.
///
/// Callers must have UnmanagedCode permission to call this API.
/// Callers must have FileIOPermission or WebPermission to font location to call this API.
///
///
/// Critical - returns raw font data.
/// Safe - (1) unmanaged code demand. This ensures PT callers can't directly access the TrueType subsetter in V1.
/// (2) fileIO or web permission demand for location of font. This ensures that even brokered access
/// via print dialog (which asserts unmanaged code) only succeeds if user has access to font source location.
///
[SecurityCritical]
[CLSCompliant(false)]
public byte[] ComputeSubset(ICollection glyphs)
{
SecurityHelper.DemandUnmanagedCode();
DemandPermissionsForFontInformation();
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
if (glyphs == null)
throw new ArgumentNullException("glyphs");
if (glyphs.Count <= 0)
throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeGreaterThanZero), "glyphs");
if (glyphs.Count > ushort.MaxValue)
throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeLessOrEqualTo, ushort.MaxValue), "glyphs");
UnmanagedMemoryStream pinnedFontSource = FontSource.GetUnmanagedStream();
try
{
TrueTypeFontDriver trueTypeDriver = new TrueTypeFontDriver(pinnedFontSource, _originalUri.Value);
trueTypeDriver.SetFace(FaceIndex);
return trueTypeDriver.ComputeFontSubset(glyphs);
}
catch (SEHException e)
{
throw Util.ConvertInPageException(FontSource, e);
}
finally
{
pinnedFontSource.Close();
}
}
///
/// Returns a font file stream represented by this GlyphTypeface.
///
/// A font file stream represented by this GlyphTypeface.
///
/// Critical - returns raw font data.
/// Safe - does a demand before it gives out the information asked.
///
[SecurityCritical]
public Stream GetFontStream()
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return FontSource.GetStream();
}
///
/// Exposed to allow printing code to access GetFontStream() in partial trust
///
///
/// Critical - returns a permission allowing access to GetFontStream in partial trust.
/// Caller must make sure there is no font data leak
///
[FriendAccessAllowed]
internal CodeAccessPermission CriticalFileReadPermission
{
[SecurityCritical]
get
{
CheckInitialized();
return _fileIOPermObj.Value;
}
}
///
/// Exposed to allow printing code to access FontUri in partial trust
///
///
/// Critical - returns a permission allowing access to FontUri
/// Caller must make sure there is no data leak
///
[FriendAccessAllowed]
internal CodeAccessPermission CriticalUriDiscoveryPermission
{
[SecurityCritical]
get
{
CheckInitialized();
return SecurityHelper.CreateUriDiscoveryPermission(_originalUri.Value);
}
}
#endregion Public Methods
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
#region Public Properties
///
/// Returns the original Uri of this glyph typeface object.
///
/// The Uri glyph typeface was constructed with.
///
/// Callers must have FileIOPermission(FileIOPermissionAccess.PathDiscovery) for the given Uri to call this API.
///
///
/// Critical - as this obtains Uri that can reveal local file system information.
/// Safe - as this does a discovery demand before it gives out the information asked.
///
public Uri FontUri
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
SecurityHelper.DemandUriDiscoveryPermission(_originalUri.Value);
return _originalUri.Value;
}
[SecurityCritical]
set
{
CheckInitializing(); // This can only be called in initialization
if (value == null)
throw new ArgumentNullException("value");
if (!value.IsAbsoluteUri)
throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "value");
_originalUri = new SecurityCriticalDataClass(value);
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the family name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the family name in English.
/// The family name excludes weight, style and stretch.
///
public IDictionary FamilyNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetFamilyNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The face name may identify weight, style and/or stretch.
///
public IDictionary FaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetFaceNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the family name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the family name in English.
/// The Win32FamilyName name excludes regular or bold weights and style,
/// but includes other weights and stretch.
///
public IDictionary Win32FamilyNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetWin32FamilyNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The face name may identify weight, style and/or stretch.
///
IDictionary ITypefaceMetrics.AdjustedFaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
IDictionary adjustedFaceNames = _fontFace.GetAdjustedFaceNameDictionary();
IDictionary adjustedLanguageFaceNames = new Dictionary(adjustedFaceNames.Count);
foreach (KeyValuePair pair in adjustedFaceNames)
{
adjustedLanguageFaceNames[XmlLanguage.GetLanguage(pair.Key.IetfLanguageTag)] = pair.Value;
}
if (_styleSimulations != StyleSimulations.None)
{
adjustedLanguageFaceNames = FontDifferentiator.AppendSimulationsToFaceNames(adjustedLanguageFaceNames, _styleSimulations);
}
return adjustedLanguageFaceNames;
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The Win32Face name may identify weights other than regular or bold and/or style,
/// but may not identify stretch or other weights.
///
public IDictionary Win32FaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetWin32FaceNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Version string in the fonts NAME table.
/// Version strings vary significantly in format - to obtain the version
/// as a numeric value use the 'Version' property,
/// do not attempt to parse the VersionString.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary VersionStrings
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetVersionStringDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Copyright notice.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Copyrights
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetCopyrightDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Manufacturer Name.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary ManufacturerNames
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetManufacturerNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// This is used to save any trademark notice/information for this font.
/// Such information should be based on legal advice.
/// This is distinctly separate from the copyright.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Trademarks
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetTrademarkDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Name of the designer of the typeface.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary DesignerNames
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDesignerNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Description of the typeface. Can contain revision information,
/// usage recommendations, history, features, etc.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Descriptions
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDescriptionDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// URL of font vendor (with protocol, e.g., `http://, `ftp://).
/// If a unique serial number is embedded in the URL,
/// it can be used to register the font.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary VendorUrls
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetVendorUrlDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// URL of typeface designer (with protocol, e.g., `http://, `ftp://).
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary DesignerUrls
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDesignerUrlDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Description of how the font may be legally used,
/// or different example scenarios for licensed use.
/// This field should be written in plain language, not legalese.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary LicenseDescriptions
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetLicenseDescriptionDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// This can be the font name, or any other text that the designer
/// thinks is the best sample to display the font in.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary SampleTexts
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetSampleTextDictionary();
}
}
///
/// Returns designed style (regular/italic/oblique) of this font face
///
/// Designed style of this font face.
public FontStyle Style
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Style;
}
}
///
/// Returns designed weight of this font face.
///
/// Designed weight of this font face.
public FontWeight Weight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Weight;
}
}
///
/// Returns designed stretch of this font face.
///
/// Designed stretch of this font face.
public FontStretch Stretch
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Stretch;
}
}
///
/// Font face version interpreted from the font's 'NAME' table.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public double Version
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.Version;
}
}
///
/// Height of character cell relative to em size.
///
public double Height
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)(_fontFace.DesignCellAscent + _fontFace.DesignCellDescent) / DesignEmHeight;
}
}
///
/// Distance from cell top to English baseline relative to em size.
///
public double Baseline
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.DesignCellAscent / DesignEmHeight;
}
}
///
/// Distance from baseline to top of English ----, relative to em size.
///
public double CapsHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.CapsHeight / DesignEmHeight;
}
}
///
/// Western x-height relative to em size.
///
public double XHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.xHeight / DesignEmHeight;
}
}
///
/// Returns true if this font does not conform to Unicode encoding:
/// it may be considered as a simple collection of symbols indexed by a codepoint.
///
public bool Symbol
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Symbol;
}
}
///
/// Position of underline relative to baseline relative to em size.
/// The value is usually negative, to place the underline below the baseline.
///
public double UnderlinePosition
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.UnderlinePosition / DesignEmHeight;
}
}
///
/// Thickness of underline relative to em size.
///
public double UnderlineThickness
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.UnderlineThickness / DesignEmHeight;
}
}
///
/// Position of strikeThrough relative to baseline relative to em size.
/// The value is usually positive, to place the Strikethrough above the baseline.
///
public double StrikethroughPosition
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.StrikethroughPosition / DesignEmHeight;
}
}
///
/// Thickness of Strikethrough relative to em size.
///
public double StrikethroughThickness
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.StrikethroughThickness / DesignEmHeight;
}
}
///
/// EmbeddingRights property describes font embedding permissions
/// specified in this glyph typeface.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public FontEmbeddingRight EmbeddingRights
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.EmbeddingRights;
}
}
#region ITypefaceMetrics implementation
///
/// Distance from baseline to top of English ----, relative to em size.
///
double ITypefaceMetrics.CapsHeight
{
get
{
return CapsHeight;
}
}
///
/// Western x-height relative to em size.
///
double ITypefaceMetrics.XHeight
{
get
{
return XHeight;
}
}
///
/// Returns true if this font does not conform to Unicode encoding:
/// it may be considered as a simple collection of symbols indexed by a codepoint.
///
bool ITypefaceMetrics.Symbol
{
get
{
return Symbol;
}
}
///
/// Position of underline relative to baseline relative to em size.
/// The value is usually negative, to place the underline below the baseline.
///
double ITypefaceMetrics.UnderlinePosition
{
get
{
return UnderlinePosition;
}
}
///
/// Thickness of underline relative to em size.
///
double ITypefaceMetrics.UnderlineThickness
{
get
{
return UnderlineThickness;
}
}
///
/// Position of strikeThrough relative to baseline relative to em size.
/// The value is usually positive, to place the Strikethrough above the baseline.
///
double ITypefaceMetrics.StrikethroughPosition
{
get
{
return StrikethroughPosition;
}
}
///
/// Thickness of Strikethrough relative to em size.
///
double ITypefaceMetrics.StrikethroughThickness
{
get
{
return StrikethroughThickness;
}
}
#endregion
// The next several properties return non CLS-compliant types. This is
// tracked by bug 1792236. For now, suppress the compiler warning.
//
#pragma warning disable 3003
///
/// Returns advance width for a given glyph.
///
public IDictionary AdvanceWidths
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetAdvanceWidth, _fontFace.GlyphCount);
}
}
///
/// Returns Advance height for a given glyph (Used for example in vertical layout).
///
public IDictionary AdvanceHeights
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetAdvanceHeight, _fontFace.GlyphCount);
}
}
///
/// Distance from leading end of advance vector to left edge of black box.
/// Positive when left edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// Negative when left edge of black box overhangs the alignment rectangle.
///
public IDictionary LeftSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetLeftSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from right edge of black box to right end of advance vector.
/// Positive when trailing edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// Negative when right edge of black box overhangs the alignment rectangle.
///
public IDictionary RightSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetRightSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from top end of (vertical) advance vector to top edge of black box.
/// Positive when top edge of black box is within the alignment rectangle
/// defined by the advance height and font cell height.
/// (The font cell height is a horizontal dimension in vertical layout).
/// Negative when top edge of black box overhangs the alignment rectangle.
///
public IDictionary TopSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetTopSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from bottom edge of black box to bottom end of advance vector.
/// Positive when bottom edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// (The font cell height is a horizontal dimension in vertical layout).
/// Negative when bottom edge of black box overhangs the alignment rectangle.
///
public IDictionary BottomSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetBottomSidebearing, _fontFace.GlyphCount);
}
}
///
/// Offset down from horizontal Western baseline to bottom of glyph black box.
///
public IDictionary DistancesFromHorizontalBaselineToBlackBoxBottom
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetBaseline, _fontFace.GlyphCount);
}
}
///
/// Returns nominal mapping of Unicode codepoint to glyph index as defined by the font 'CMAP' table.
///
///
/// Critical: May potentially leak a writeable cmap.
/// Safe: The cmap IDictionary exposure is read only.
///
public IDictionary CharacterToGlyphMap
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.CharacterMap;
}
}
#pragma warning restore 3003
///
/// Returns algorithmic font style simulations to be applied to the GlyphTypeface.
///
public StyleSimulations StyleSimulations
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _styleSimulations;
}
set
{
CheckInitializing();
_styleSimulations = value;
}
}
///
/// Obtains the number of glyphs in the glyph typeface.
///
/// The number of glyphs in the glyph typeface.
public int GlyphCount
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GlyphCount;
}
}
#endregion Public Properties
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
///
/// Returns the nominal advance width for a glyph.
///
/// Glyph index in the font.
/// The nominal advance width for the glyph relative to the em size of the font.
///
/// Critical - as this has unsafe block.
/// Safe - as this only gives width information which is safe to give out.
///
[SecurityCritical, SecurityTreatAsSafe]
internal double GetAdvanceWidth(ushort glyph)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
// We manually expand GetGlyphMetrics call because GetAdvanceWidth is a very frequently used function.
// When we get to using GetAdvanceHeight for vertical writing, we need to consider doing the same optimization there.
unsafe
{
FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph);
double aw = (double)cachedGlyphMetrics->advanceWidth / DesignEmHeight;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
{
// Bold simulation increases advance width and advance height by 2% of em size,
// except for glyphs that are empty or have zero advance widths.
// So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
if (cachedGlyphMetrics->advanceWidth != 0 &&
cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb &&
cachedGlyphMetrics->advanceHeight != 0 &&
cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0)
{
aw += 0.02;
}
}
return aw;
}
}
///
/// Returns the nominal advance width for a glyph in font design units.
///
/// Glyph index in the font.
/// The nominal advance width for the glyph in font design units.
internal double GetAdvanceWidthInDesignUnits(ushort glyph)
{
return GetAdvanceWidth(glyph) * DesignEmHeight;
}
///
/// This function will demand appropriate permissions depending on what
/// the source of the font information is. The value of _fileIOPermObj
/// is set correctly whenever _originalUri gets set.
///
internal void DemandPermissionsForFontInformation()
{
if (_fileIOPermObj.Value != null)
{
_fileIOPermObj.Value.Demand();
}
}
private double GetAdvanceHeight(ushort glyph)
{
double aw, ah, lsb, rsb, tsb, bsb, baseline;
GetGlyphMetrics(
glyph,
1.0,
out aw,
out ah,
out lsb,
out rsb,
out tsb,
out bsb,
out baseline
);
return ah;
}
private double GetLeftSidebearing(ushort glyph)
{
return (double)_fontFace.GetLeftSidebearing(glyph) / DesignEmHeight;
}
private double GetRightSidebearing(ushort glyph)
{
return (double)_fontFace.GetRightSidebearing(glyph) / DesignEmHeight;
}
private double GetTopSidebearing(ushort glyph)
{
return (double)_fontFace.GetTopSidebearing(glyph) / DesignEmHeight;
}
private double GetBottomSidebearing(ushort glyph)
{
return (double)_fontFace.GetBottomSidebearing(glyph) / DesignEmHeight;
}
private double GetBaseline(ushort glyph)
{
return (double)_fontFace.GetBaseline(glyph) / DesignEmHeight;
}
///
/// Optimized version of obtaining all of glyph metrics from font cache at once
/// without repeated checks and divisions.
///
///
/// Critical - as this uses unsafe code.
/// Safe - as this only gives information which is safe to give out.
///
[SecurityCritical, SecurityTreatAsSafe]
internal void GetGlyphMetrics(
ushort glyph,
double renderingEmSize,
out double aw,
out double ah,
out double lsb,
out double rsb,
out double tsb,
out double bsb,
out double baseline
)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
unsafe
{
FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph);
double designToEm = renderingEmSize / DesignEmHeight;
aw = designToEm * cachedGlyphMetrics->advanceWidth;
ah = designToEm * cachedGlyphMetrics->advanceHeight;
lsb = designToEm * cachedGlyphMetrics->lsb;
rsb = designToEm * cachedGlyphMetrics->rsb;
tsb = designToEm * cachedGlyphMetrics->tsb;
bsb = designToEm * cachedGlyphMetrics->bsb;
baseline = designToEm * cachedGlyphMetrics->baseline;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
{
// Bold simulation increases advance width and advance height by 2% of em size,
// except for glyphs that are empty or have zero advance widths.
// So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
if (cachedGlyphMetrics->advanceWidth != 0 &&
cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb &&
cachedGlyphMetrics->advanceHeight != 0 &&
cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0)
{
aw += 0.02 * renderingEmSize;
ah += 0.02 * renderingEmSize;
}
}
}
}
///
/// Returns a geometry describing the path for a single glyph in the font.
/// The path represents the glyph
/// without grid fitting applied for rendering at a specific resolution.
///
/// Index of the glyph to get outline for.
/// Specifies whether the glyph should be rotated sideways.
/// Font size in drawing surface units.
/// Geometry containing glyph outline.
///
/// Critical - as this calls GetGlyphs() which is critical.
/// Safe - as this doesn't expose font information but just gives out a Geometry.
///
[SecurityCritical, SecurityTreatAsSafe]
internal Geometry ComputeGlyphOutline(ushort glyphIndex, bool sideways, double renderingEmSize)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
using (GlyphPathElement pathElement = new GlyphPathElement(
FaceIndex,
FontSource,
GetRenderingFlags(sideways),
DesignEmHeight
))
{
PathGeometry pathGeometry;
unsafe
{
void*[] glyphOutlines = new void*[1];
FontCacheAccessor fontCacheAccessor = new FontCacheAccessor();
ushort[] glyphIndices = new ushort[1] { glyphIndex };
fontCacheAccessor.GetGlyphs(
pathElement,
glyphIndices,
glyphOutlines
);
void * outline = glyphOutlines[0];
Debug.Assert(outline != null);
if (FontTechnology == FontTechnology.PostscriptOpenType)
ConvertPostscriptOutline(outline, renderingEmSize, sideways, out pathGeometry);
else
ConvertTrueTypeOutline(outline, renderingEmSize, sideways, out pathGeometry);
// Make sure fontCacheAccessor doesn't go out of scope before the outlines get converted.
GC.KeepAlive(fontCacheAccessor);
}
// Make sure to always return Geometry.Empty from public methods for empty geometries.
if (pathGeometry == null || pathGeometry.IsEmpty())
return Geometry.Empty;
return pathGeometry;
}
}
///
/// Critical - unsafe code, accepts pointer parameters, etc.
///
[SecurityCritical]
private unsafe void ConvertTrueTypeOutline(void* trueTypeOutline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry)
{
GlyphPathData * outline = (GlyphPathData *)trueTypeOutline;
// scale factor from design units to user coordinate system
double designToUserScale = renderingEmSize / DesignEmHeight;
Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0);
if (sideways)
{
designToUser.Rotate(-90.0);
designToUser.Translate(outline->verOriginY * designToUserScale, outline->verOriginX * designToUserScale);
}
ushort* endp = GlyphPathData.EndPointNumbers(outline);
short* x = GlyphPathData.X(outline);
short* y = GlyphPathData.Y(outline);
byte* flags = GlyphPathData.Flags(outline);
// k is the index of the first point of the current contour
int k = 0;
pathGeometry = null;
// j is the index of the current contour
for (int j = 0; j < outline->numberOfContours; ++j)
{
int lastPointIndex = endp[j];
if (lastPointIndex <= k)
{
k = lastPointIndex + 1;
continue; // empty contour
}
Point startPoint;
PathFigure figure = new PathFigure();
// The first point on the curve
if (OnCurve(flags[k]))
{
// Easy case
startPoint = designToUser.Transform(new Point(x[k], y[k]));
++k;
}
else
{
// Is last contour point on the curve
if (OnCurve(flags[lastPointIndex]))
{
// Make the last point the first point and decrement the last point
startPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex]));
--lastPointIndex;
}
else
{
// First and last point are off the countour, fake a mid point
Point firstPoint = designToUser.Transform(new Point(x[k], y[k]));
Point lastPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex]));
startPoint = new Point(
(firstPoint.X + lastPoint.X) / 2,
(firstPoint.Y + lastPoint.Y) / 2
);
}
}
figure.StartPoint = startPoint;
bool inBezier = false;
Point bezierB = new Point();
while (k <= lastPointIndex)
{
Point currentPoint = designToUser.Transform(new Point(x[k], y[k]));
if (OnCurve(flags[k]))
{
if (!inBezier)
{
figure.Segments.Add(new LineSegment(currentPoint, true));
}
else
{
figure.Segments.Add(new QuadraticBezierSegment(bezierB, currentPoint, true));
inBezier = false;
}
}
else
{
if (inBezier)
{
figure.Segments.Add(new QuadraticBezierSegment(
bezierB,
new Point(
(bezierB.X + currentPoint.X) / 2,
(bezierB.Y + currentPoint.Y) / 2
),
true)
);
}
inBezier = true;
bezierB = currentPoint;
}
++k;
}
// explicitly set k to the start point of the next contour
// since in some cases lastPointIndex is not equal to endp[j]
k = endp[j] + 1;
// close the figure, assume start point is always on curve
if (inBezier)
{
figure.Segments.Add(new QuadraticBezierSegment(bezierB, startPoint, true));
}
figure.IsClosed = true;
if (pathGeometry == null)
{
pathGeometry = new PathGeometry();
pathGeometry.FillRule = FillRule.Nonzero;
}
pathGeometry.Figures.Add(figure);
}
}
///
/// Critical - unsafe code, accepts pointer parameters, etc.
///
[SecurityCritical]
private unsafe void ConvertPostscriptOutline(void * outline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry)
{
int * postscriptOutline = (int *)outline;
// scale factor from design units to user coordinate system
double designToUserScale = renderingEmSize / DesignEmHeight;
Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0);
if (sideways)
{
int verOriginX = postscriptOutline[0];
int verOriginY = postscriptOutline[1];
designToUser.Rotate(-90.0);
designToUser.Translate(verOriginY * designToUserScale, verOriginX * designToUserScale);
}
// Skip vertical origin and length to get to the actual contour data.
int * p = postscriptOutline + 3;
Debug.Assert(postscriptOutline[2] % sizeof(int) == 0);
int * end = p + (postscriptOutline[2] / sizeof(int));
pathGeometry = null;
// Current figure.
PathFigure figure = null;
for (;;)
{
if (p >= end)
break;
int tokenValue = *p;
switch ((OutlineTokenType)tokenValue)
{
case OutlineTokenType.MoveTo:
{
++p;
if (p + 1 >= end)
throw new FileFormatException(_originalUri.Value);
Point point = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
if (figure == null)
figure = new PathFigure();
figure.StartPoint = point;
p += 2;
break;
}
case OutlineTokenType.LineTo:
{
++p;
if (p + 1 >= end)
throw new FileFormatException(_originalUri.Value);
Point point = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.Segments.Add(new LineSegment(point, true));
p += 2;
break;
}
case OutlineTokenType.CurveTo:
{
++p;
if (p + 5 >= end)
throw new FileFormatException(_originalUri.Value);
Point point0 = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
Point point1 = designToUser.Transform(
new Point(p[2] * CFFConversionFactor, p[3] * CFFConversionFactor)
);
Point point2 = designToUser.Transform(
new Point(p[4] * CFFConversionFactor, p[5] * CFFConversionFactor)
);
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.Segments.Add(new BezierSegment(point0, point1, point2, true));
p += 6;
break;
}
case OutlineTokenType.ClosePath:
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.IsClosed = true;
if (pathGeometry == null)
{
pathGeometry = new PathGeometry();
pathGeometry.FillRule = FillRule.Nonzero;
}
pathGeometry.Figures.Add(figure);
figure = null;
++p;
break;
default:
throw new FileFormatException(_originalUri.Value);
}
}
}
///
/// Get advance widths of unshaped characters
///
/// character string
/// character length
/// character em size
/// unshaped advance widths
/// true if all characters map to missing glyph
/// array of character advance widths
///
/// Critical - takes unsafe char string and returns information in an unsafe int array
///
[SecurityCritical]
internal unsafe void GetAdvanceWidthsUnshaped(
char* unsafeCharString,
int stringLength,
double emSize,
int* advanceWidthsUnshaped,
bool nullFont
)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
Invariant.Assert(stringLength > 0);
if (!nullFont)
{
IDictionary cmap = CharacterToGlyphMap;
for (int i = 0; i < stringLength; i++)
{
ushort glyphIndex;
cmap.TryGetValue(unsafeCharString[i], out glyphIndex);
advanceWidthsUnshaped[i] = (int)Math.Round(emSize * GetAdvanceWidth(glyphIndex));
}
}
else
{
int missingGlyphWidth = (int)Math.Round(emSize * GetAdvanceWidth(0));
for (int i = 0; i < stringLength; i++)
{
advanceWidthsUnshaped[i] = missingGlyphWidth;
}
}
}
///
/// Compute an unshaped glyphrun object from specified character-based info
///
internal GlyphRun ComputeUnshapedGlyphRun(
Point origin,
CharacterBufferRange charBufferRange,
IList charWidths,
double emSize,
double emHintingSize,
bool nullGlyph,
CultureInfo cultureInfo,
string deviceFontName
)
{
Debug.Assert(charBufferRange.Length > 0);
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
ushort[] nominalGlyphs = new ushort[charBufferRange.Length];
// compute glyph positions
if (nullGlyph)
{
for (int i = 0; i < charBufferRange.Length; i++)
{
nominalGlyphs[i] = 0;
}
}
else
{
IDictionary cmap = CharacterToGlyphMap;
for (int i = 0; i < charBufferRange.Length; i++)
{
ushort glyphIndex;
cmap.TryGetValue(charBufferRange[i], out glyphIndex);
nominalGlyphs[i] = glyphIndex;
}
}
return GlyphRun.TryCreate(
this,
0, // bidiLevel
false, // sideway
emSize,
nominalGlyphs,
origin,
charWidths,
null, // glyphOffsets
new PartialList(charBufferRange.CharacterBuffer, charBufferRange.OffsetToFirstChar, charBufferRange.Length),
deviceFontName, // device font
null, // 1:1 mapping
null, // caret stops at every codepoint
XmlLanguage.GetLanguage(cultureInfo.IetfLanguageTag)
);
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal FontSource FontSource
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontSource;
}
}
///
/// 0 for TTF files
/// Face index within TrueType font collection for TTC files
///
internal int FaceIndex
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FaceIndex;
}
}
internal FontFaceLayoutInfo FontFaceLayoutInfo
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace;
}
}
internal ushort BlankGlyphIndex
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.BlankGlyph;
}
}
internal FontFaceLayoutInfo.RenderingHints RenderingHints
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontRenderingHints;
}
}
internal FontTechnology FontTechnology
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontTechnology;
}
}
internal short FontContrastAdjustment
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
Debug.Assert(-3 <= _fontFace.FontContrastAdjustment && _fontFace.FontContrastAdjustment <= 4);
return _fontFace.FontContrastAdjustment;
}
}
internal ushort DesignEmHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.DesignEmHeight;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
private static bool OnCurve(byte flag)
{
return (flag & 0x01) != 0;
}
private ushort GetRenderingFlags(bool sideways)
{
ushort renderingFlags = 0;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
renderingFlags |= (ushort)RenderingFlags.BoldSimulation;
if ((_styleSimulations & StyleSimulations.ItalicSimulation) != 0)
{
renderingFlags |= (ushort)RenderingFlags.ItalicSimulation;
if (sideways)
renderingFlags |= (ushort)RenderingFlags.SidewaysItalicSimulation;
}
if (FontTechnology != FontTechnology.PostscriptOpenType)
renderingFlags |= (ushort)MilGlyphRun.IsTrueType;
return renderingFlags;
}
#endregion Private Methods
#region ISupportInitialize interface
void ISupportInitialize.BeginInit()
{
if (_initializationState == InitializationState.IsInitialized)
{
// Cannont initialize a GlyphRun this is completely initialized.
throw new InvalidOperationException(SR.Get(SRID.OnlyOneInitialization));
}
if (_initializationState == InitializationState.IsInitializing)
{
// Cannot initialize a GlyphRun this already being initialized.
throw new InvalidOperationException(SR.Get(SRID.InInitialization));
}
_initializationState = InitializationState.IsInitializing;
}
///
/// Critical - this method calls into critical method.
///
[SecurityCritical]
void ISupportInitialize.EndInit()
{
if (_initializationState != InitializationState.IsInitializing)
{
// Cannot EndInit a GlyphRun that is not being initialized.
throw new InvalidOperationException(SR.Get(SRID.NotInInitialization));
}
Initialize(
(_originalUri == null ? null : _originalUri.Value),
_styleSimulations,
true
);
}
private void CheckInitialized()
{
if (_initializationState != InitializationState.IsInitialized)
{
throw new InvalidOperationException(SR.Get(SRID.InitializationIncomplete));
}
}
private void CheckInitializing()
{
if (_initializationState != InitializationState.IsInitializing)
{
throw new InvalidOperationException(SR.Get(SRID.NotInInitialization));
}
}
#endregion
//-----------------------------------------------------
//
// Private Nested Classes
//
//------------------------------------------------------
#region Private Nested Classes
private delegate double GlyphAccessor(ushort glyphIndex);
///
/// This class is a helper to implement named indexers
/// for glyph metrics.
///
private class GlyphIndexer : IDictionary
{
internal GlyphIndexer(GlyphAccessor accessor, ushort numberOfGlyphs)
{
_accessor = accessor;
_numberOfGlyphs = numberOfGlyphs;
}
#region IDictionary Members
public void Add(ushort key, double value)
{
throw new NotSupportedException();
}
public bool ContainsKey(ushort key)
{
return (key < _numberOfGlyphs);
}
public ICollection Keys
{
get { return new SequentialUshortCollection(_numberOfGlyphs); }
}
public bool Remove(ushort key)
{
throw new NotSupportedException();
}
public bool TryGetValue(ushort key, out double value)
{
if (ContainsKey(key))
{
value = this[key];
return true;
}
else
{
value = new double();
return false;
}
}
public ICollection Values
{
get { return new ValueCollection(this); }
}
public double this[ushort key]
{
get
{
return _accessor(key);
}
set
{
throw new NotSupportedException();
}
}
#endregion
#region ICollection> Members
public void Add(KeyValuePair item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(KeyValuePair item)
{
return ContainsKey(item.Key);
}
public void CopyTo(KeyValuePair[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(SR.Get(SRID.Collection_BadRank));
}
// The extra "arrayIndex >= array.Length" check in because even if _collection.Count
// is 0 the index is not allowed to be equal or greater than the length
// (from the MSDN ICollection docs)
if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
for (ushort i = 0; i < Count; ++i)
array[arrayIndex + i] = new KeyValuePair(i, this[i]);
}
public int Count
{
get { return _numberOfGlyphs; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(KeyValuePair item)
{
throw new NotSupportedException();
}
#endregion
#region IEnumerable> Members
public IEnumerator> GetEnumerator()
{
for (ushort i = 0; i < Count; ++i)
yield return new KeyValuePair(i, this[i]);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable>)this).GetEnumerator();
}
#endregion
private class ValueCollection : ICollection
{
public ValueCollection(GlyphIndexer glyphIndexer)
{
_glyphIndexer = glyphIndexer;
}
#region ICollection Members
public void Add(double item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(double item)
{
foreach (double d in this)
{
if (d == item)
return true;
}
return false;
}
public void CopyTo(double[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(SR.Get(SRID.Collection_BadRank));
}
// The extra "arrayIndex >= array.Length" check in because even if _collection.Count
// is 0 the index is not allowed to be equal or greater than the length
// (from the MSDN ICollection docs)
if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
for (ushort i = 0; i < Count; ++i)
array[arrayIndex + i] = _glyphIndexer[i];
}
public int Count
{
get { return _glyphIndexer._numberOfGlyphs; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(double item)
{
throw new NotSupportedException();
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
for (ushort i = 0; i < Count; ++i)
yield return _glyphIndexer[i];
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)this).GetEnumerator();
}
#endregion
private GlyphIndexer _glyphIndexer;
}
private GlyphAccessor _accessor;
private ushort _numberOfGlyphs;
}
#endregion Private Nested Classes
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private FontFaceLayoutInfo _fontFace;
private StyleSimulations _styleSimulations;
///
/// The Uri that was passed in to constructor.
///
///
/// This is critical as we do a demand based on this value public functions.
/// Only setting this Uri is critical, getting is fine. Hence using the
/// SecurityCriticalDataForSet object. Note that the object itself does not
/// need to be Critical, it's just setting it that makes it Critical.
///
private SecurityCriticalDataClass _originalUri;
///
/// Critical - as this object controls the Demand that'll be made before accessssing the
/// security sensitive contents of the font file. This also only Critical
/// for set. This should be correctly whenever _originalUri is set.
///
/// Caching object for perf reasons.
///
private SecurityCriticalDataForSet _fileIOPermObj;
private const double CFFConversionFactor = 1.0 / 65536.0;
private InitializationState _initializationState;
///
/// Initialization states of GlyphTypeface object.
///
private enum InitializationState
{
///
/// The state in which the GlyphTypeface has not been initialized.
/// At this state, all operations on the object would cause InvalidOperationException.
/// The object can only transit to 'IsInitializing' state with BeginInit() call.
///
Uninitialized,
///
/// The state in which the GlyphTypeface is being initialized. At this state, user can
/// set values into the required properties. The object can only transit to 'IsInitialized' state
/// with EndInit() call.
///
IsInitializing,
///
/// The state in which the GlyphTypeface object is fully initialized. At this state the object
/// is fully functional. There is no valid transition out of the state.
///
IsInitialized,
}
#endregion Private Fields
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: GlyphTypeface implementation
//
// History:
// 06/04/2003 : mleonov - Moved GlyphTypeface from GlyphRun.cs
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows;
using System.Windows.Media.Composition;
using System.Windows.Media.TextFormatting;
using System.Windows.Markup;
using MS.Internal.FontRasterization;
using MS.Internal;
using MS.Internal.FontCache;
using MS.Internal.FontFace;
using MS.Internal.PresentationCore;
namespace System.Windows.Media
{
///
/// Physical font face corresponds to a font file on the disk
///
public class GlyphTypeface : ITypefaceMetrics, ISupportInitialize
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
///
/// Creates an uninitialized GlyphTypeface object. Caller should call ISupportInitialize.BeginInit()
/// to begin initializing the object and call ISupportInitialize.EndInit() to finish the initialization.
///
public GlyphTypeface()
{
}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface does not use style simulations.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
public GlyphTypeface(Uri typefaceSource) : this(typefaceSource, StyleSimulations.None)
{}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
/// Specifies style simulations to be applied to the newly created GlyphTypeface.
///
/// Critical - as this calls the internal constructor that's critical.
/// Safe - as the internal constructor does a Demand for FileIO for file
/// Uris for the case where fromPublic is true. We block constructing
/// GlyphTypeface directly in SEE since this'd allow guessing fonts on
/// a machine by trying to create a GlyphTypeface object.
///
///
[SecurityCritical]
public GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations) :
this (typefaceSource, styleSimulations, /* fromPublic = */ true)
{}
///
/// Creates a new GlyphTypeface object from a .otf, .ttf or .ttc font face specified by typefaceSource.
/// The constructed GlyphTypeface uses style simulations specified by styleSimulations parameter.
///
/// Specifies the URI of a font file used by the newly created GlyphTypeface.
/// Specifies style simulations to be applied to the newly created GlyphTypeface.
/// Specifies if the call to the constructor is from a public constructor
/// or if its from an internal method. For public constructor we demand FileIO for all files whereas
/// for internal calls we don't demand in the constructor.
///
/// Critical - as the instance of GlyphTypeface created with this constructor can
/// expose font information for the case where fromPublic is false.
///
[SecurityCritical]
internal GlyphTypeface(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
{
Initialize(typefaceSource, styleSimulations, fromPublic);
}
///
/// Critical - this method calls into other critical method.
///
[SecurityCritical]
private void Initialize(Uri typefaceSource, StyleSimulations styleSimulations, bool fromPublic)
{
if (typefaceSource == null)
throw new ArgumentNullException("typefaceSource");
if (!typefaceSource.IsAbsoluteUri)
throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "typefaceSource");
// remember the original Uri that contains face index
_originalUri = new SecurityCriticalDataClass(typefaceSource);
// split the Uri into the font source Uri and face index
Uri fontSourceUri;
int faceIndex;
Util.SplitFontFaceIndex(typefaceSource, out fontSourceUri, out faceIndex);
_fileIOPermObj = new SecurityCriticalDataForSet(
SecurityHelper.CreateUriReadPermission(fontSourceUri)
);
// This permission demand is here so that untrusted callers are unable to check for file existence using GlyphTypeface ctor.
// Sensitive font data is protected by demands as the user tries to access it.
// The demand below is skipped for non-public calls, because in such cases
// fonts are exposed as logical fonts to the end user.
if (fromPublic)
DemandPermissionsForFontInformation();
// We skip permission demands for FontSource because the above line already demands them for the right callers.
_fontFace = new FontFaceLayoutInfo(new FontSource(fontSourceUri, true), faceIndex);
CacheManager.Lookup(_fontFace);
if ((styleSimulations & ~StyleSimulations.BoldItalicSimulation) != 0)
throw new InvalidEnumArgumentException("styleSimulations", (int)styleSimulations, typeof(StyleSimulations));
_styleSimulations = styleSimulations;
_initializationState = InitializationState.IsInitialized; // fully initialized
}
#endregion Constructors
//------------------------------------------------------
//
// Public Methods
//
//-----------------------------------------------------
#region Public Methods
///
/// Return hash code for this GlyphTypeface.
///
/// Hash code.
///
/// Critical - as this accesses _originalUri.
/// Safe - as this only does this to compute the hash code.
///
[SecurityCritical]
public override int GetHashCode()
{
CheckInitialized();
return _originalUri.Value.GetHashCode() ^ (int)StyleSimulations;
}
///
/// Compares this GlyphTypeface with another object.
///
/// Object to compare with.
/// Whether this object is equal to the input object.
///
/// Critical - as this accesses _originalUri.
/// Safe - as this only does this to perform a comparison with another object.
///
[SecurityCritical]
public override bool Equals(object o)
{
CheckInitialized();
GlyphTypeface t = o as GlyphTypeface;
if (t == null)
return false;
return StyleSimulations == t.StyleSimulations
&& _originalUri.Value == t._originalUri.Value;
}
///
/// Returns a geometry describing the path for a single glyph in the font.
/// The path represents the glyph
/// without grid fitting applied for rendering at a specific resolution.
///
/// Index of the glyph to get outline for.
/// Font size in drawing surface units.
/// Size to hint for in points.
///
[CLSCompliant(false)]
public Geometry GetGlyphOutline(ushort glyphIndex, double renderingEmSize, double hintingEmSize)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
// NOTE: This parameter is unused, and should be deleted. Not worth a breaking change just for this though.
return ComputeGlyphOutline(glyphIndex, false, renderingEmSize);
}
///
/// Returns the binary image of font subset.
///
/// Collection of glyph indices to be included into the subset.
/// Binary image of font subset.
///
/// Callers must have UnmanagedCode permission to call this API.
/// Callers must have FileIOPermission or WebPermission to font location to call this API.
///
///
/// Critical - returns raw font data.
/// Safe - (1) unmanaged code demand. This ensures PT callers can't directly access the TrueType subsetter in V1.
/// (2) fileIO or web permission demand for location of font. This ensures that even brokered access
/// via print dialog (which asserts unmanaged code) only succeeds if user has access to font source location.
///
[SecurityCritical]
[CLSCompliant(false)]
public byte[] ComputeSubset(ICollection glyphs)
{
SecurityHelper.DemandUnmanagedCode();
DemandPermissionsForFontInformation();
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
if (glyphs == null)
throw new ArgumentNullException("glyphs");
if (glyphs.Count <= 0)
throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeGreaterThanZero), "glyphs");
if (glyphs.Count > ushort.MaxValue)
throw new ArgumentException(SR.Get(SRID.CollectionNumberOfElementsMustBeLessOrEqualTo, ushort.MaxValue), "glyphs");
UnmanagedMemoryStream pinnedFontSource = FontSource.GetUnmanagedStream();
try
{
TrueTypeFontDriver trueTypeDriver = new TrueTypeFontDriver(pinnedFontSource, _originalUri.Value);
trueTypeDriver.SetFace(FaceIndex);
return trueTypeDriver.ComputeFontSubset(glyphs);
}
catch (SEHException e)
{
throw Util.ConvertInPageException(FontSource, e);
}
finally
{
pinnedFontSource.Close();
}
}
///
/// Returns a font file stream represented by this GlyphTypeface.
///
/// A font file stream represented by this GlyphTypeface.
///
/// Critical - returns raw font data.
/// Safe - does a demand before it gives out the information asked.
///
[SecurityCritical]
public Stream GetFontStream()
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return FontSource.GetStream();
}
///
/// Exposed to allow printing code to access GetFontStream() in partial trust
///
///
/// Critical - returns a permission allowing access to GetFontStream in partial trust.
/// Caller must make sure there is no font data leak
///
[FriendAccessAllowed]
internal CodeAccessPermission CriticalFileReadPermission
{
[SecurityCritical]
get
{
CheckInitialized();
return _fileIOPermObj.Value;
}
}
///
/// Exposed to allow printing code to access FontUri in partial trust
///
///
/// Critical - returns a permission allowing access to FontUri
/// Caller must make sure there is no data leak
///
[FriendAccessAllowed]
internal CodeAccessPermission CriticalUriDiscoveryPermission
{
[SecurityCritical]
get
{
CheckInitialized();
return SecurityHelper.CreateUriDiscoveryPermission(_originalUri.Value);
}
}
#endregion Public Methods
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
#region Public Properties
///
/// Returns the original Uri of this glyph typeface object.
///
/// The Uri glyph typeface was constructed with.
///
/// Callers must have FileIOPermission(FileIOPermissionAccess.PathDiscovery) for the given Uri to call this API.
///
///
/// Critical - as this obtains Uri that can reveal local file system information.
/// Safe - as this does a discovery demand before it gives out the information asked.
///
public Uri FontUri
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
SecurityHelper.DemandUriDiscoveryPermission(_originalUri.Value);
return _originalUri.Value;
}
[SecurityCritical]
set
{
CheckInitializing(); // This can only be called in initialization
if (value == null)
throw new ArgumentNullException("value");
if (!value.IsAbsoluteUri)
throw new ArgumentException(SR.Get(SRID.UriNotAbsolute), "value");
_originalUri = new SecurityCriticalDataClass(value);
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the family name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the family name in English.
/// The family name excludes weight, style and stretch.
///
public IDictionary FamilyNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetFamilyNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The face name may identify weight, style and/or stretch.
///
public IDictionary FaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetFaceNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the family name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the family name in English.
/// The Win32FamilyName name excludes regular or bold weights and style,
/// but includes other weights and stretch.
///
public IDictionary Win32FamilyNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetWin32FamilyNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The face name may identify weight, style and/or stretch.
///
IDictionary ITypefaceMetrics.AdjustedFaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
IDictionary adjustedFaceNames = _fontFace.GetAdjustedFaceNameDictionary();
IDictionary adjustedLanguageFaceNames = new Dictionary(adjustedFaceNames.Count);
foreach (KeyValuePair pair in adjustedFaceNames)
{
adjustedLanguageFaceNames[XmlLanguage.GetLanguage(pair.Key.IetfLanguageTag)] = pair.Value;
}
if (_styleSimulations != StyleSimulations.None)
{
adjustedLanguageFaceNames = FontDifferentiator.AppendSimulationsToFaceNames(adjustedLanguageFaceNames, _styleSimulations);
}
return adjustedLanguageFaceNames;
}
}
///
/// This property is indexed by a Culture Identifier.
/// It returns the face name in the specified language, or,
/// if the font does not provide a name for the specified language,
/// it returns the face name in English.
/// The Win32Face name may identify weights other than regular or bold and/or style,
/// but may not identify stretch or other weights.
///
public IDictionary Win32FaceNames
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GetWin32FaceNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Version string in the fonts NAME table.
/// Version strings vary significantly in format - to obtain the version
/// as a numeric value use the 'Version' property,
/// do not attempt to parse the VersionString.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary VersionStrings
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetVersionStringDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Copyright notice.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Copyrights
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetCopyrightDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Manufacturer Name.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary ManufacturerNames
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetManufacturerNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// This is used to save any trademark notice/information for this font.
/// Such information should be based on legal advice.
/// This is distinctly separate from the copyright.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Trademarks
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetTrademarkDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Name of the designer of the typeface.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary DesignerNames
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDesignerNameDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Description of the typeface. Can contain revision information,
/// usage recommendations, history, features, etc.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary Descriptions
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDescriptionDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// URL of font vendor (with protocol, e.g., `http://, `ftp://).
/// If a unique serial number is embedded in the URL,
/// it can be used to register the font.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary VendorUrls
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetVendorUrlDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// URL of typeface designer (with protocol, e.g., `http://, `ftp://).
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary DesignerUrls
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetDesignerUrlDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// Description of how the font may be legally used,
/// or different example scenarios for licensed use.
/// This field should be written in plain language, not legalese.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary LicenseDescriptions
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetLicenseDescriptionDictionary();
}
}
///
/// This property is indexed by a Culture Identifier.
/// This can be the font name, or any other text that the designer
/// thinks is the best sample to display the font in.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public IDictionary SampleTexts
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.GetSampleTextDictionary();
}
}
///
/// Returns designed style (regular/italic/oblique) of this font face
///
/// Designed style of this font face.
public FontStyle Style
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Style;
}
}
///
/// Returns designed weight of this font face.
///
/// Designed weight of this font face.
public FontWeight Weight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Weight;
}
}
///
/// Returns designed stretch of this font face.
///
/// Designed stretch of this font face.
public FontStretch Stretch
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Stretch;
}
}
///
/// Font face version interpreted from the font's 'NAME' table.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public double Version
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.Version;
}
}
///
/// Height of character cell relative to em size.
///
public double Height
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)(_fontFace.DesignCellAscent + _fontFace.DesignCellDescent) / DesignEmHeight;
}
}
///
/// Distance from cell top to English baseline relative to em size.
///
public double Baseline
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.DesignCellAscent / DesignEmHeight;
}
}
///
/// Distance from baseline to top of English ----, relative to em size.
///
public double CapsHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.CapsHeight / DesignEmHeight;
}
}
///
/// Western x-height relative to em size.
///
public double XHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.xHeight / DesignEmHeight;
}
}
///
/// Returns true if this font does not conform to Unicode encoding:
/// it may be considered as a simple collection of symbols indexed by a codepoint.
///
public bool Symbol
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.Symbol;
}
}
///
/// Position of underline relative to baseline relative to em size.
/// The value is usually negative, to place the underline below the baseline.
///
public double UnderlinePosition
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.UnderlinePosition / DesignEmHeight;
}
}
///
/// Thickness of underline relative to em size.
///
public double UnderlineThickness
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.UnderlineThickness / DesignEmHeight;
}
}
///
/// Position of strikeThrough relative to baseline relative to em size.
/// The value is usually positive, to place the Strikethrough above the baseline.
///
public double StrikethroughPosition
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.StrikethroughPosition / DesignEmHeight;
}
}
///
/// Thickness of Strikethrough relative to em size.
///
public double StrikethroughThickness
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return (double)_fontFace.StrikethroughThickness / DesignEmHeight;
}
}
///
/// EmbeddingRights property describes font embedding permissions
/// specified in this glyph typeface.
///
///
/// Critical - as this accesses _fontFace which can reveal Windows font information.
/// Safe - as this does a demand before it gives out the information asked.
///
public FontEmbeddingRight EmbeddingRights
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
DemandPermissionsForFontInformation();
return _fontFace.EmbeddingRights;
}
}
#region ITypefaceMetrics implementation
///
/// Distance from baseline to top of English ----, relative to em size.
///
double ITypefaceMetrics.CapsHeight
{
get
{
return CapsHeight;
}
}
///
/// Western x-height relative to em size.
///
double ITypefaceMetrics.XHeight
{
get
{
return XHeight;
}
}
///
/// Returns true if this font does not conform to Unicode encoding:
/// it may be considered as a simple collection of symbols indexed by a codepoint.
///
bool ITypefaceMetrics.Symbol
{
get
{
return Symbol;
}
}
///
/// Position of underline relative to baseline relative to em size.
/// The value is usually negative, to place the underline below the baseline.
///
double ITypefaceMetrics.UnderlinePosition
{
get
{
return UnderlinePosition;
}
}
///
/// Thickness of underline relative to em size.
///
double ITypefaceMetrics.UnderlineThickness
{
get
{
return UnderlineThickness;
}
}
///
/// Position of strikeThrough relative to baseline relative to em size.
/// The value is usually positive, to place the Strikethrough above the baseline.
///
double ITypefaceMetrics.StrikethroughPosition
{
get
{
return StrikethroughPosition;
}
}
///
/// Thickness of Strikethrough relative to em size.
///
double ITypefaceMetrics.StrikethroughThickness
{
get
{
return StrikethroughThickness;
}
}
#endregion
// The next several properties return non CLS-compliant types. This is
// tracked by bug 1792236. For now, suppress the compiler warning.
//
#pragma warning disable 3003
///
/// Returns advance width for a given glyph.
///
public IDictionary AdvanceWidths
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetAdvanceWidth, _fontFace.GlyphCount);
}
}
///
/// Returns Advance height for a given glyph (Used for example in vertical layout).
///
public IDictionary AdvanceHeights
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetAdvanceHeight, _fontFace.GlyphCount);
}
}
///
/// Distance from leading end of advance vector to left edge of black box.
/// Positive when left edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// Negative when left edge of black box overhangs the alignment rectangle.
///
public IDictionary LeftSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetLeftSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from right edge of black box to right end of advance vector.
/// Positive when trailing edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// Negative when right edge of black box overhangs the alignment rectangle.
///
public IDictionary RightSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetRightSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from top end of (vertical) advance vector to top edge of black box.
/// Positive when top edge of black box is within the alignment rectangle
/// defined by the advance height and font cell height.
/// (The font cell height is a horizontal dimension in vertical layout).
/// Negative when top edge of black box overhangs the alignment rectangle.
///
public IDictionary TopSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetTopSidebearing, _fontFace.GlyphCount);
}
}
///
/// Distance from bottom edge of black box to bottom end of advance vector.
/// Positive when bottom edge of black box is within the alignment rectangle
/// defined by the advance width and font cell height.
/// (The font cell height is a horizontal dimension in vertical layout).
/// Negative when bottom edge of black box overhangs the alignment rectangle.
///
public IDictionary BottomSideBearings
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetBottomSidebearing, _fontFace.GlyphCount);
}
}
///
/// Offset down from horizontal Western baseline to bottom of glyph black box.
///
public IDictionary DistancesFromHorizontalBaselineToBlackBoxBottom
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return new GlyphIndexer(this.GetBaseline, _fontFace.GlyphCount);
}
}
///
/// Returns nominal mapping of Unicode codepoint to glyph index as defined by the font 'CMAP' table.
///
///
/// Critical: May potentially leak a writeable cmap.
/// Safe: The cmap IDictionary exposure is read only.
///
public IDictionary CharacterToGlyphMap
{
[SecurityCritical]
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.CharacterMap;
}
}
#pragma warning restore 3003
///
/// Returns algorithmic font style simulations to be applied to the GlyphTypeface.
///
public StyleSimulations StyleSimulations
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _styleSimulations;
}
set
{
CheckInitializing();
_styleSimulations = value;
}
}
///
/// Obtains the number of glyphs in the glyph typeface.
///
/// The number of glyphs in the glyph typeface.
public int GlyphCount
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.GlyphCount;
}
}
#endregion Public Properties
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
///
/// Returns the nominal advance width for a glyph.
///
/// Glyph index in the font.
/// The nominal advance width for the glyph relative to the em size of the font.
///
/// Critical - as this has unsafe block.
/// Safe - as this only gives width information which is safe to give out.
///
[SecurityCritical, SecurityTreatAsSafe]
internal double GetAdvanceWidth(ushort glyph)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
// We manually expand GetGlyphMetrics call because GetAdvanceWidth is a very frequently used function.
// When we get to using GetAdvanceHeight for vertical writing, we need to consider doing the same optimization there.
unsafe
{
FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph);
double aw = (double)cachedGlyphMetrics->advanceWidth / DesignEmHeight;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
{
// Bold simulation increases advance width and advance height by 2% of em size,
// except for glyphs that are empty or have zero advance widths.
// So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
if (cachedGlyphMetrics->advanceWidth != 0 &&
cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb &&
cachedGlyphMetrics->advanceHeight != 0 &&
cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0)
{
aw += 0.02;
}
}
return aw;
}
}
///
/// Returns the nominal advance width for a glyph in font design units.
///
/// Glyph index in the font.
/// The nominal advance width for the glyph in font design units.
internal double GetAdvanceWidthInDesignUnits(ushort glyph)
{
return GetAdvanceWidth(glyph) * DesignEmHeight;
}
///
/// This function will demand appropriate permissions depending on what
/// the source of the font information is. The value of _fileIOPermObj
/// is set correctly whenever _originalUri gets set.
///
internal void DemandPermissionsForFontInformation()
{
if (_fileIOPermObj.Value != null)
{
_fileIOPermObj.Value.Demand();
}
}
private double GetAdvanceHeight(ushort glyph)
{
double aw, ah, lsb, rsb, tsb, bsb, baseline;
GetGlyphMetrics(
glyph,
1.0,
out aw,
out ah,
out lsb,
out rsb,
out tsb,
out bsb,
out baseline
);
return ah;
}
private double GetLeftSidebearing(ushort glyph)
{
return (double)_fontFace.GetLeftSidebearing(glyph) / DesignEmHeight;
}
private double GetRightSidebearing(ushort glyph)
{
return (double)_fontFace.GetRightSidebearing(glyph) / DesignEmHeight;
}
private double GetTopSidebearing(ushort glyph)
{
return (double)_fontFace.GetTopSidebearing(glyph) / DesignEmHeight;
}
private double GetBottomSidebearing(ushort glyph)
{
return (double)_fontFace.GetBottomSidebearing(glyph) / DesignEmHeight;
}
private double GetBaseline(ushort glyph)
{
return (double)_fontFace.GetBaseline(glyph) / DesignEmHeight;
}
///
/// Optimized version of obtaining all of glyph metrics from font cache at once
/// without repeated checks and divisions.
///
///
/// Critical - as this uses unsafe code.
/// Safe - as this only gives information which is safe to give out.
///
[SecurityCritical, SecurityTreatAsSafe]
internal void GetGlyphMetrics(
ushort glyph,
double renderingEmSize,
out double aw,
out double ah,
out double lsb,
out double rsb,
out double tsb,
out double bsb,
out double baseline
)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
unsafe
{
FontFaceLayoutInfo.GlyphMetrics * cachedGlyphMetrics = _fontFace.Metrics(glyph);
double designToEm = renderingEmSize / DesignEmHeight;
aw = designToEm * cachedGlyphMetrics->advanceWidth;
ah = designToEm * cachedGlyphMetrics->advanceHeight;
lsb = designToEm * cachedGlyphMetrics->lsb;
rsb = designToEm * cachedGlyphMetrics->rsb;
tsb = designToEm * cachedGlyphMetrics->tsb;
bsb = designToEm * cachedGlyphMetrics->bsb;
baseline = designToEm * cachedGlyphMetrics->baseline;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
{
// Bold simulation increases advance width and advance height by 2% of em size,
// except for glyphs that are empty or have zero advance widths.
// So, we compensate for the simulation when aw != 0 && left < right && ah != 0 && bottom > top
if (cachedGlyphMetrics->advanceWidth != 0 &&
cachedGlyphMetrics->lsb < cachedGlyphMetrics->advanceWidth - cachedGlyphMetrics->rsb &&
cachedGlyphMetrics->advanceHeight != 0 &&
cachedGlyphMetrics->advanceHeight - cachedGlyphMetrics->tsb - cachedGlyphMetrics->bsb > 0)
{
aw += 0.02 * renderingEmSize;
ah += 0.02 * renderingEmSize;
}
}
}
}
///
/// Returns a geometry describing the path for a single glyph in the font.
/// The path represents the glyph
/// without grid fitting applied for rendering at a specific resolution.
///
/// Index of the glyph to get outline for.
/// Specifies whether the glyph should be rotated sideways.
/// Font size in drawing surface units.
/// Geometry containing glyph outline.
///
/// Critical - as this calls GetGlyphs() which is critical.
/// Safe - as this doesn't expose font information but just gives out a Geometry.
///
[SecurityCritical, SecurityTreatAsSafe]
internal Geometry ComputeGlyphOutline(ushort glyphIndex, bool sideways, double renderingEmSize)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
using (GlyphPathElement pathElement = new GlyphPathElement(
FaceIndex,
FontSource,
GetRenderingFlags(sideways),
DesignEmHeight
))
{
PathGeometry pathGeometry;
unsafe
{
void*[] glyphOutlines = new void*[1];
FontCacheAccessor fontCacheAccessor = new FontCacheAccessor();
ushort[] glyphIndices = new ushort[1] { glyphIndex };
fontCacheAccessor.GetGlyphs(
pathElement,
glyphIndices,
glyphOutlines
);
void * outline = glyphOutlines[0];
Debug.Assert(outline != null);
if (FontTechnology == FontTechnology.PostscriptOpenType)
ConvertPostscriptOutline(outline, renderingEmSize, sideways, out pathGeometry);
else
ConvertTrueTypeOutline(outline, renderingEmSize, sideways, out pathGeometry);
// Make sure fontCacheAccessor doesn't go out of scope before the outlines get converted.
GC.KeepAlive(fontCacheAccessor);
}
// Make sure to always return Geometry.Empty from public methods for empty geometries.
if (pathGeometry == null || pathGeometry.IsEmpty())
return Geometry.Empty;
return pathGeometry;
}
}
///
/// Critical - unsafe code, accepts pointer parameters, etc.
///
[SecurityCritical]
private unsafe void ConvertTrueTypeOutline(void* trueTypeOutline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry)
{
GlyphPathData * outline = (GlyphPathData *)trueTypeOutline;
// scale factor from design units to user coordinate system
double designToUserScale = renderingEmSize / DesignEmHeight;
Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0);
if (sideways)
{
designToUser.Rotate(-90.0);
designToUser.Translate(outline->verOriginY * designToUserScale, outline->verOriginX * designToUserScale);
}
ushort* endp = GlyphPathData.EndPointNumbers(outline);
short* x = GlyphPathData.X(outline);
short* y = GlyphPathData.Y(outline);
byte* flags = GlyphPathData.Flags(outline);
// k is the index of the first point of the current contour
int k = 0;
pathGeometry = null;
// j is the index of the current contour
for (int j = 0; j < outline->numberOfContours; ++j)
{
int lastPointIndex = endp[j];
if (lastPointIndex <= k)
{
k = lastPointIndex + 1;
continue; // empty contour
}
Point startPoint;
PathFigure figure = new PathFigure();
// The first point on the curve
if (OnCurve(flags[k]))
{
// Easy case
startPoint = designToUser.Transform(new Point(x[k], y[k]));
++k;
}
else
{
// Is last contour point on the curve
if (OnCurve(flags[lastPointIndex]))
{
// Make the last point the first point and decrement the last point
startPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex]));
--lastPointIndex;
}
else
{
// First and last point are off the countour, fake a mid point
Point firstPoint = designToUser.Transform(new Point(x[k], y[k]));
Point lastPoint = designToUser.Transform(new Point(x[lastPointIndex], y[lastPointIndex]));
startPoint = new Point(
(firstPoint.X + lastPoint.X) / 2,
(firstPoint.Y + lastPoint.Y) / 2
);
}
}
figure.StartPoint = startPoint;
bool inBezier = false;
Point bezierB = new Point();
while (k <= lastPointIndex)
{
Point currentPoint = designToUser.Transform(new Point(x[k], y[k]));
if (OnCurve(flags[k]))
{
if (!inBezier)
{
figure.Segments.Add(new LineSegment(currentPoint, true));
}
else
{
figure.Segments.Add(new QuadraticBezierSegment(bezierB, currentPoint, true));
inBezier = false;
}
}
else
{
if (inBezier)
{
figure.Segments.Add(new QuadraticBezierSegment(
bezierB,
new Point(
(bezierB.X + currentPoint.X) / 2,
(bezierB.Y + currentPoint.Y) / 2
),
true)
);
}
inBezier = true;
bezierB = currentPoint;
}
++k;
}
// explicitly set k to the start point of the next contour
// since in some cases lastPointIndex is not equal to endp[j]
k = endp[j] + 1;
// close the figure, assume start point is always on curve
if (inBezier)
{
figure.Segments.Add(new QuadraticBezierSegment(bezierB, startPoint, true));
}
figure.IsClosed = true;
if (pathGeometry == null)
{
pathGeometry = new PathGeometry();
pathGeometry.FillRule = FillRule.Nonzero;
}
pathGeometry.Figures.Add(figure);
}
}
///
/// Critical - unsafe code, accepts pointer parameters, etc.
///
[SecurityCritical]
private unsafe void ConvertPostscriptOutline(void * outline, double renderingEmSize, bool sideways, out PathGeometry pathGeometry)
{
int * postscriptOutline = (int *)outline;
// scale factor from design units to user coordinate system
double designToUserScale = renderingEmSize / DesignEmHeight;
Matrix designToUser = new Matrix(designToUserScale, 0, 0, -designToUserScale, 0, 0);
if (sideways)
{
int verOriginX = postscriptOutline[0];
int verOriginY = postscriptOutline[1];
designToUser.Rotate(-90.0);
designToUser.Translate(verOriginY * designToUserScale, verOriginX * designToUserScale);
}
// Skip vertical origin and length to get to the actual contour data.
int * p = postscriptOutline + 3;
Debug.Assert(postscriptOutline[2] % sizeof(int) == 0);
int * end = p + (postscriptOutline[2] / sizeof(int));
pathGeometry = null;
// Current figure.
PathFigure figure = null;
for (;;)
{
if (p >= end)
break;
int tokenValue = *p;
switch ((OutlineTokenType)tokenValue)
{
case OutlineTokenType.MoveTo:
{
++p;
if (p + 1 >= end)
throw new FileFormatException(_originalUri.Value);
Point point = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
if (figure == null)
figure = new PathFigure();
figure.StartPoint = point;
p += 2;
break;
}
case OutlineTokenType.LineTo:
{
++p;
if (p + 1 >= end)
throw new FileFormatException(_originalUri.Value);
Point point = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.Segments.Add(new LineSegment(point, true));
p += 2;
break;
}
case OutlineTokenType.CurveTo:
{
++p;
if (p + 5 >= end)
throw new FileFormatException(_originalUri.Value);
Point point0 = designToUser.Transform(
new Point(p[0] * CFFConversionFactor, p[1] * CFFConversionFactor)
);
Point point1 = designToUser.Transform(
new Point(p[2] * CFFConversionFactor, p[3] * CFFConversionFactor)
);
Point point2 = designToUser.Transform(
new Point(p[4] * CFFConversionFactor, p[5] * CFFConversionFactor)
);
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.Segments.Add(new BezierSegment(point0, point1, point2, true));
p += 6;
break;
}
case OutlineTokenType.ClosePath:
if (figure == null)
throw new FileFormatException(_originalUri.Value);
figure.IsClosed = true;
if (pathGeometry == null)
{
pathGeometry = new PathGeometry();
pathGeometry.FillRule = FillRule.Nonzero;
}
pathGeometry.Figures.Add(figure);
figure = null;
++p;
break;
default:
throw new FileFormatException(_originalUri.Value);
}
}
}
///
/// Get advance widths of unshaped characters
///
/// character string
/// character length
/// character em size
/// unshaped advance widths
/// true if all characters map to missing glyph
/// array of character advance widths
///
/// Critical - takes unsafe char string and returns information in an unsafe int array
///
[SecurityCritical]
internal unsafe void GetAdvanceWidthsUnshaped(
char* unsafeCharString,
int stringLength,
double emSize,
int* advanceWidthsUnshaped,
bool nullFont
)
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
Invariant.Assert(stringLength > 0);
if (!nullFont)
{
IDictionary cmap = CharacterToGlyphMap;
for (int i = 0; i < stringLength; i++)
{
ushort glyphIndex;
cmap.TryGetValue(unsafeCharString[i], out glyphIndex);
advanceWidthsUnshaped[i] = (int)Math.Round(emSize * GetAdvanceWidth(glyphIndex));
}
}
else
{
int missingGlyphWidth = (int)Math.Round(emSize * GetAdvanceWidth(0));
for (int i = 0; i < stringLength; i++)
{
advanceWidthsUnshaped[i] = missingGlyphWidth;
}
}
}
///
/// Compute an unshaped glyphrun object from specified character-based info
///
internal GlyphRun ComputeUnshapedGlyphRun(
Point origin,
CharacterBufferRange charBufferRange,
IList charWidths,
double emSize,
double emHintingSize,
bool nullGlyph,
CultureInfo cultureInfo,
string deviceFontName
)
{
Debug.Assert(charBufferRange.Length > 0);
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
ushort[] nominalGlyphs = new ushort[charBufferRange.Length];
// compute glyph positions
if (nullGlyph)
{
for (int i = 0; i < charBufferRange.Length; i++)
{
nominalGlyphs[i] = 0;
}
}
else
{
IDictionary cmap = CharacterToGlyphMap;
for (int i = 0; i < charBufferRange.Length; i++)
{
ushort glyphIndex;
cmap.TryGetValue(charBufferRange[i], out glyphIndex);
nominalGlyphs[i] = glyphIndex;
}
}
return GlyphRun.TryCreate(
this,
0, // bidiLevel
false, // sideway
emSize,
nominalGlyphs,
origin,
charWidths,
null, // glyphOffsets
new PartialList(charBufferRange.CharacterBuffer, charBufferRange.OffsetToFirstChar, charBufferRange.Length),
deviceFontName, // device font
null, // 1:1 mapping
null, // caret stops at every codepoint
XmlLanguage.GetLanguage(cultureInfo.IetfLanguageTag)
);
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal FontSource FontSource
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontSource;
}
}
///
/// 0 for TTF files
/// Face index within TrueType font collection for TTC files
///
internal int FaceIndex
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FaceIndex;
}
}
internal FontFaceLayoutInfo FontFaceLayoutInfo
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace;
}
}
internal ushort BlankGlyphIndex
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.BlankGlyph;
}
}
internal FontFaceLayoutInfo.RenderingHints RenderingHints
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontRenderingHints;
}
}
internal FontTechnology FontTechnology
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.FontTechnology;
}
}
internal short FontContrastAdjustment
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
Debug.Assert(-3 <= _fontFace.FontContrastAdjustment && _fontFace.FontContrastAdjustment <= 4);
return _fontFace.FontContrastAdjustment;
}
}
internal ushort DesignEmHeight
{
get
{
CheckInitialized(); // This can only be called on fully initialized GlyphTypeface
return _fontFace.DesignEmHeight;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
private static bool OnCurve(byte flag)
{
return (flag & 0x01) != 0;
}
private ushort GetRenderingFlags(bool sideways)
{
ushort renderingFlags = 0;
if ((_styleSimulations & StyleSimulations.BoldSimulation) != 0)
renderingFlags |= (ushort)RenderingFlags.BoldSimulation;
if ((_styleSimulations & StyleSimulations.ItalicSimulation) != 0)
{
renderingFlags |= (ushort)RenderingFlags.ItalicSimulation;
if (sideways)
renderingFlags |= (ushort)RenderingFlags.SidewaysItalicSimulation;
}
if (FontTechnology != FontTechnology.PostscriptOpenType)
renderingFlags |= (ushort)MilGlyphRun.IsTrueType;
return renderingFlags;
}
#endregion Private Methods
#region ISupportInitialize interface
void ISupportInitialize.BeginInit()
{
if (_initializationState == InitializationState.IsInitialized)
{
// Cannont initialize a GlyphRun this is completely initialized.
throw new InvalidOperationException(SR.Get(SRID.OnlyOneInitialization));
}
if (_initializationState == InitializationState.IsInitializing)
{
// Cannot initialize a GlyphRun this already being initialized.
throw new InvalidOperationException(SR.Get(SRID.InInitialization));
}
_initializationState = InitializationState.IsInitializing;
}
///
/// Critical - this method calls into critical method.
///
[SecurityCritical]
void ISupportInitialize.EndInit()
{
if (_initializationState != InitializationState.IsInitializing)
{
// Cannot EndInit a GlyphRun that is not being initialized.
throw new InvalidOperationException(SR.Get(SRID.NotInInitialization));
}
Initialize(
(_originalUri == null ? null : _originalUri.Value),
_styleSimulations,
true
);
}
private void CheckInitialized()
{
if (_initializationState != InitializationState.IsInitialized)
{
throw new InvalidOperationException(SR.Get(SRID.InitializationIncomplete));
}
}
private void CheckInitializing()
{
if (_initializationState != InitializationState.IsInitializing)
{
throw new InvalidOperationException(SR.Get(SRID.NotInInitialization));
}
}
#endregion
//-----------------------------------------------------
//
// Private Nested Classes
//
//------------------------------------------------------
#region Private Nested Classes
private delegate double GlyphAccessor(ushort glyphIndex);
///
/// This class is a helper to implement named indexers
/// for glyph metrics.
///
private class GlyphIndexer : IDictionary
{
internal GlyphIndexer(GlyphAccessor accessor, ushort numberOfGlyphs)
{
_accessor = accessor;
_numberOfGlyphs = numberOfGlyphs;
}
#region IDictionary Members
public void Add(ushort key, double value)
{
throw new NotSupportedException();
}
public bool ContainsKey(ushort key)
{
return (key < _numberOfGlyphs);
}
public ICollection Keys
{
get { return new SequentialUshortCollection(_numberOfGlyphs); }
}
public bool Remove(ushort key)
{
throw new NotSupportedException();
}
public bool TryGetValue(ushort key, out double value)
{
if (ContainsKey(key))
{
value = this[key];
return true;
}
else
{
value = new double();
return false;
}
}
public ICollection Values
{
get { return new ValueCollection(this); }
}
public double this[ushort key]
{
get
{
return _accessor(key);
}
set
{
throw new NotSupportedException();
}
}
#endregion
#region ICollection> Members
public void Add(KeyValuePair item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(KeyValuePair item)
{
return ContainsKey(item.Key);
}
public void CopyTo(KeyValuePair[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(SR.Get(SRID.Collection_BadRank));
}
// The extra "arrayIndex >= array.Length" check in because even if _collection.Count
// is 0 the index is not allowed to be equal or greater than the length
// (from the MSDN ICollection docs)
if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
for (ushort i = 0; i < Count; ++i)
array[arrayIndex + i] = new KeyValuePair(i, this[i]);
}
public int Count
{
get { return _numberOfGlyphs; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(KeyValuePair item)
{
throw new NotSupportedException();
}
#endregion
#region IEnumerable> Members
public IEnumerator> GetEnumerator()
{
for (ushort i = 0; i < Count; ++i)
yield return new KeyValuePair(i, this[i]);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable>)this).GetEnumerator();
}
#endregion
private class ValueCollection : ICollection
{
public ValueCollection(GlyphIndexer glyphIndexer)
{
_glyphIndexer = glyphIndexer;
}
#region ICollection Members
public void Add(double item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(double item)
{
foreach (double d in this)
{
if (d == item)
return true;
}
return false;
}
public void CopyTo(double[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(SR.Get(SRID.Collection_BadRank));
}
// The extra "arrayIndex >= array.Length" check in because even if _collection.Count
// is 0 the index is not allowed to be equal or greater than the length
// (from the MSDN ICollection docs)
if (arrayIndex < 0 || arrayIndex >= array.Length || (arrayIndex + Count) > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
for (ushort i = 0; i < Count; ++i)
array[arrayIndex + i] = _glyphIndexer[i];
}
public int Count
{
get { return _glyphIndexer._numberOfGlyphs; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(double item)
{
throw new NotSupportedException();
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
for (ushort i = 0; i < Count; ++i)
yield return _glyphIndexer[i];
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)this).GetEnumerator();
}
#endregion
private GlyphIndexer _glyphIndexer;
}
private GlyphAccessor _accessor;
private ushort _numberOfGlyphs;
}
#endregion Private Nested Classes
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private FontFaceLayoutInfo _fontFace;
private StyleSimulations _styleSimulations;
///
/// The Uri that was passed in to constructor.
///
///
/// This is critical as we do a demand based on this value public functions.
/// Only setting this Uri is critical, getting is fine. Hence using the
/// SecurityCriticalDataForSet object. Note that the object itself does not
/// need to be Critical, it's just setting it that makes it Critical.
///
private SecurityCriticalDataClass _originalUri;
///
/// Critical - as this object controls the Demand that'll be made before accessssing the
/// security sensitive contents of the font file. This also only Critical
/// for set. This should be correctly whenever _originalUri is set.
///
/// Caching object for perf reasons.
///
private SecurityCriticalDataForSet _fileIOPermObj;
private const double CFFConversionFactor = 1.0 / 65536.0;
private InitializationState _initializationState;
///
/// Initialization states of GlyphTypeface object.
///
private enum InitializationState
{
///
/// The state in which the GlyphTypeface has not been initialized.
/// At this state, all operations on the object would cause InvalidOperationException.
/// The object can only transit to 'IsInitializing' state with BeginInit() call.
///
Uninitialized,
///
/// The state in which the GlyphTypeface is being initialized. At this state, user can
/// set values into the required properties. The object can only transit to 'IsInitialized' state
/// with EndInit() call.
///
IsInitializing,
///
/// The state in which the GlyphTypeface object is fully initialized. At this state the object
/// is fully functional. There is no valid transition out of the state.
///
IsInitialized,
}
#endregion Private Fields
}
}
// 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
- StaticDataManager.cs
- FileRegion.cs
- ReservationCollection.cs
- RootBrowserWindowAutomationPeer.cs
- EditingMode.cs
- ElementAtQueryOperator.cs
- SectionVisual.cs
- DeclarativeCatalogPart.cs
- StickyNoteHelper.cs
- FrameSecurityDescriptor.cs
- SrgsGrammar.cs
- OutputCacheEntry.cs
- Converter.cs
- PackageDigitalSignatureManager.cs
- DocumentGrid.cs
- PointCollection.cs
- DiagnosticEventProvider.cs
- PriorityQueue.cs
- RoutedPropertyChangedEventArgs.cs
- Vector.cs
- Publisher.cs
- GeneralTransformGroup.cs
- ListView.cs
- SqlBooleanMismatchVisitor.cs
- TCPListener.cs
- OpacityConverter.cs
- FixedBufferAttribute.cs
- ISessionStateStore.cs
- EntityStoreSchemaGenerator.cs
- ResourceContainer.cs
- TreeBuilderBamlTranslator.cs
- XamlContextStack.cs
- TextServicesCompartmentContext.cs
- DecimalConstantAttribute.cs
- ProfileInfo.cs
- TemplateKey.cs
- Convert.cs
- ExpressionList.cs
- VisualProxy.cs
- LookupNode.cs
- EditorPartChrome.cs
- UIPropertyMetadata.cs
- RuntimeHelpers.cs
- DataObjectSettingDataEventArgs.cs
- AssertFilter.cs
- HyperLink.cs
- DependencyObjectProvider.cs
- DtdParser.cs
- StorageMappingFragment.cs
- EntityEntry.cs
- SupportsEventValidationAttribute.cs
- Rijndael.cs
- DuplexClientBase.cs
- FormsIdentity.cs
- XmlElementAttributes.cs
- SafeTimerHandle.cs
- PrintPreviewGraphics.cs
- EnlistmentState.cs
- EnlistmentTraceIdentifier.cs
- DefinitionUpdate.cs
- SqlCacheDependency.cs
- EndpointIdentityConverter.cs
- OleAutBinder.cs
- UnescapedXmlDiagnosticData.cs
- loginstatus.cs
- TransactionsSectionGroup.cs
- NetworkAddressChange.cs
- EventLogPermissionEntry.cs
- BoundsDrawingContextWalker.cs
- DetailsView.cs
- XmlWhitespace.cs
- UnsafeNetInfoNativeMethods.cs
- WebHttpDispatchOperationSelector.cs
- HostingEnvironmentException.cs
- LocalizableResourceBuilder.cs
- ETagAttribute.cs
- Glyph.cs
- BoolExpr.cs
- SapiInterop.cs
- Int32CAMarshaler.cs
- FormsAuthenticationUserCollection.cs
- XmlCharCheckingReader.cs
- ErrorStyle.cs
- MSHTMLHost.cs
- HtmlEmptyTagControlBuilder.cs
- UnmanagedBitmapWrapper.cs
- CacheModeConverter.cs
- PropertyDescriptorComparer.cs
- SecurityUtils.cs
- IISMapPath.cs
- ZoneMembershipCondition.cs
- SchemaInfo.cs
- WindowPattern.cs
- TextShapeableCharacters.cs
- LocationUpdates.cs
- GridToolTip.cs
- EncoderExceptionFallback.cs
- followingquery.cs
- ReferenceSchema.cs
- OleDbDataAdapter.cs