Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / FontCache / GlyphElement.cs / 1 / GlyphElement.cs
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Security; using System.Security.Permissions; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; using MS.Internal; using MS.Internal.FontFace; using MS.Utility; using MS.Internal.FontRasterization; using Adobe.CffRasterizer; using System.Windows.Media.Composition; using MS.Internal.PresentationCore; // Since we disable PreSharp warnings in this file, we first need to disable warnings about unknown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 namespace MS.Internal.FontCache { ////// Glyph element class. /// Layout is: /// glyph block structure | file name string /// [FriendAccessAllowed] internal abstract class BaseGlyphElement : IFontCacheElement, IDisposable { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct GlyphBlock { internal int faceIndex; internal int cbFileNameLength; internal ushort renderingFlags; internal ushort baseglyphIndex; ////// Critical - as this accesses unsafe code blocks /// TreatAsSafe - as this does not return any unsafe pointers and is used to compare two blocks /// [SecurityCritical, SecurityTreatAsSafe] internal unsafe bool Equal(GlyphBlock* rhs) { Invariant.Assert(rhs != null); return this.faceIndex == rhs->faceIndex && this.cbFileNameLength == rhs->cbFileNameLength && this.baseglyphIndex == rhs->baseglyphIndex && this.renderingFlags == rhs->renderingFlags; } } protected BaseGlyphElement(int glyphsPerBlock) { _glyphsPerBlock = glyphsPerBlock; Reset(); Debug.Assert(_key.baseglyphIndex != GetBaseGlyph(_key.baseglyphIndex)); } ////// Critical - as this calls GetUriString /// TreatAsSafe - as this does not uses the result only to compute the string length. /// [SecurityCritical, SecurityTreatAsSafe] protected BaseGlyphElement(int glyphsPerBlock, int faceIndex, FontSource fontSource, ushort renderingFlags) : this(glyphsPerBlock) { _fontSource = fontSource; _key.renderingFlags = renderingFlags; _key.faceIndex = faceIndex; unsafe { _key.cbFileNameLength = FontSource.GetUriString().Length * sizeof(char); } } ////// Critical as this calls _fontStream.Close(), which is a file operation. /// TreatAsSafe as it only releases the file handle. /// [SecurityCritical, SecurityTreatAsSafe] public void Dispose() { if (_rasterizer != null) { _rasterizer.Dispose(); _rasterizer = null; } if (_fontStream != null) { _fontStream.Close(); _fontStream = null; } } ////// Critical - as this accesses _glyphdata which is a pointer /// TreatAsSafe: This does not expose the data and simply resets the stream /// [SecurityCritical, SecurityTreatAsSafe] internal void Reset() { unsafe { _glyphData = null; } _cacher = null; _key.baseglyphIndex = 1; } internal FontSource FontSource { get { return _fontSource; } } internal int FaceIndex { get { return _key.faceIndex; } } internal RenderingFlags RenderingFlags { get { return (RenderingFlags)_key.renderingFlags; } } internal bool IsTrueType { get { return (_key.renderingFlags & (ushort)MIL_GLYPHRUN_FLAGS.MilGlyphRunIsTrueType) != 0; } } ////// Prevent JIT from inlining this method, so that PresentationCFFRasterizer.dll and PresentationCFFRasterizerNative.dll are loaded on demand. /// ////// Critical - This method calls critical code (OTFRasterizer()) /// Safe - This method doesn't expose any ciritical information. /// [MethodImpl(MethodImplOptions.NoInlining)] [SecurityCritical, SecurityTreatAsSafe] protected void CreateOtfRasterizer() { _rasterizer = new OTFRasterizer(); } ////// Critical - as this accesses unsafe code blocks and allocates an object that can hold unmanaged code and returns it /// [SecurityCritical] protected unsafe void* Allocate(int size) { int newOffset = _cacher.Alloc(size); return _cacher[newOffset]; } ////// Critical: This code acceses unsafe code and is used to allocate memory. It returns a pointer /// [SecurityCritical] protected unsafe void* AllocateNoThrow(int size) { try { return Allocate(size); } catch (FontCacheFullException) { return null; } } ////// Obtains a base glyph index for this cache element /// ///The base glyph index internal ushort GetBaseGlyph() { return _key.baseglyphIndex; } internal void SetBaseGlyph(ushort glyphIndex) { Debug.Assert(glyphIndex == GetBaseGlyph(glyphIndex)); _key.baseglyphIndex = glyphIndex; } internal ushort GetBaseGlyph(ushort glyphIndex) { return (ushort)(glyphIndex - glyphIndex % _glyphsPerBlock); } ////// Critical - as this gives out glyphstream /// [SecurityCritical] protected unsafe int* GlyphEntry(ushort glyphIndex) { Invariant.Assert(GetBaseGlyph(glyphIndex) == _key.baseglyphIndex); return _glyphData + (glyphIndex - _key.baseglyphIndex); } ////// Returns whether a given glyph is cached /// /// Glyph index ///true if the glyph is cached, false otherwise ////// Critical - as this accesses unsafe code blocks /// TreatAsSafe - as this does not return the stream /// [SecurityCritical, SecurityTreatAsSafe] internal bool IsGlyphCached(ushort glyphIndex) { unsafe { return *GlyphEntry(glyphIndex) != Util.nullOffset; } } ////// Critical - as this accesses unsafe code blocks and returns a glyph pointer /// [SecurityCritical] internal unsafe void* GetGlyph(ushort glyphIndex) { Invariant.Assert(IsGlyphCached(glyphIndex)); int offset = *GlyphEntry(glyphIndex); return _cacher[offset]; } ////// Critical - as this accesses unsafe code blocks and sets data from a pointer /// [SecurityCritical] protected unsafe void SetGlyph(ushort glyphIndex, void* data) { *GlyphEntry(glyphIndex) = _cacher[(byte*)data]; Debug.Assert(IsGlyphCached(glyphIndex)); } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: The calls to probe is bounds checked /// and the usage of elementcacher and checkedpointer are tracked. /// [SecurityCritical, SecurityTreatAsSafe] protected void InitGlyphData(CheckedPointer p, ElementCacher cacher) { unsafe { _glyphData = (int*)p.Probe(0, _glyphsPerBlock * sizeof(int)); Util.FillMemory(_glyphData, _glyphsPerBlock * sizeof(int), Util.nullOffset); } _cacher = cacher; } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: The calls to probe is bounds checked /// and the usage of elementcacher and checkedpointer are tracked. /// [SecurityCritical, SecurityTreatAsSafe] protected void SetGlyphData(CheckedPointer p, ElementCacher cacher) { unsafe { _glyphData = (int*)p.Probe(0, _glyphsPerBlock * sizeof(int)); } _cacher = cacher; } ////// Critical - as this gives out glyph data in the form of a pointer /// internal unsafe void* GlyphData { [SecurityCritical] get { return _glyphData; } } ////// Adds glyph to the cache /// /// Index of the glyph ///Whether the glyph index was valid for this font. ////// Critical - as this results in the rasterizer accessing font stream. /// TreatAsSafe - as this results in obtaining glyph data that the client is supposed to see anyway. /// [SecurityCritical, SecurityTreatAsSafe] internal abstract bool AddGlyph(ushort glyphIndex); ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: Probe is bounds checked and validates pointer. /// [SecurityCritical, SecurityTreatAsSafe] public virtual bool Match(CheckedPointer p) { unsafe { GlyphBlock* rhs = (GlyphBlock*)p.Probe(0, sizeof(GlyphBlock)); if (!_key.Equal(rhs)) return false; return Util.StringEqualIgnoreCase(p + sizeof(GlyphBlock), FontSource.GetUriString()); } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// [SecurityCritical] public virtual void RetrieveKey(CheckedPointer m) { unsafe { _key = *(GlyphBlock*)m.Probe(0, sizeof(GlyphBlock)); // Validate the base glyph index now so that malformed miss reports // don't trip Invarient.Assert() later when we try to construct the element. if (GetBaseGlyph(_key.baseglyphIndex) != _key.baseglyphIndex) throw new ArgumentOutOfRangeException(); // As the name size could come from arbitrary code // sending miss reports to the font cache server, // we must validate it so that Util.StringCopy() doesn't // call Invariant::Assert() if nameSize is invalid. if ((_key.cbFileNameLength < 0) || ((_key.cbFileNameLength % 2) != 0)) throw new ArgumentOutOfRangeException(); string fileName = Util.StringCopyFromCheckedPointer(m + sizeof(GlyphBlock), _key.cbFileNameLength); _fontSource = new FontSource(new Uri(fileName, UriKind.Absolute), false); } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: Probe is type and bounds checked and this functionality is safe to expose /// [SecurityCritical, SecurityTreatAsSafe] internal void StoreKeyInternal(CheckedPointer d, out int realSize) { realSize = InternalGetSize(); unsafe { GlyphBlock* glyphBlock = (GlyphBlock*)d.Probe(0, sizeof(GlyphBlock)); *glyphBlock = _key; Util.StringCopyToCheckedPointer(d + sizeof(GlyphBlock), FontSource.GetUriString()); } } public virtual int Size { get { return InternalGetSize(); } } public virtual bool IsAppSpecific { get { return _fontSource.IsAppSpecific; } } private int InternalGetSize() { unsafe { return sizeof(GlyphBlock) + _key.cbFileNameLength; } } ////// Critical: This code has unsafe code blocks which call into HasMemory. /// TreatAsSafe: This code is safe to call , since the _key variable is always /// pointing to a valid object and passing it to HashMemory which accepts a void pointer /// is safe. /// [SecurityCritical, SecurityTreatAsSafe] public override int GetHashCode() { int hash = 0; unsafe { fixed (GlyphBlock* k = &_key) { hash = HashFn.HashMemory(k, sizeof(GlyphBlock), hash); } } hash = HashFn.HashMultiply(hash) + FontSource.GetHashCode(); return hash; } public abstract void GetData(CheckedPointer p, ElementCacher cacher); public abstract void AddToCache(CheckedPointer p, ElementCacher cacher); public abstract int Type { get;} public abstract void StoreKey(CheckedPointer d, out int realSize); ////// Cached TrueType rasterizer instance /// protected IFontRasterizer _rasterizer; ////// Critical - as this gives out UnmanagedMemoryStream content which is from a file. /// [SecurityCritical] protected UnmanagedMemoryStream _fontStream; ////// The total number of glyphs in the font /// protected ushort _numberOfGlyphs; private int _glyphsPerBlock; ////// Critical - as this gives out glyph data in the form of a pointer /// [SecurityCritical] private unsafe int* _glyphData; // points to bitmap array in the cache private ElementCacher _cacher; private FontSource _fontSource; private GlyphBlock _key; } ////// This structure represents a black and white glyph bitmap. /// In font cache the structure is immediately followed by height*stride bytes of pixel data. /// Empty bitmaps have zero height. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] internal unsafe struct GlyphBitmap { internal int horOriginX; // horizontal X origin of glyph bitmap internal int horOriginY; // horizontal Y origin of glyph bitmap internal int horAdvance; // hinted advance width internal int verOriginX; // vertical X origin of glyph bitmap internal int verOriginY; // vertical Y origin of glyph bitmap internal int verAdvance; // hinted advance height internal int width; // bitmap width in pixels internal int height; // bitmap height in pixels internal int stride; // number of bytes to store one pixel row } ////// Glyph bitmap element class. /// Represents a block of glyph bitmaps /// Layout is: /// base glyph block | bitmap block | table of blockSize pointers to glyph data /// [FriendAccessAllowed] internal sealed class GlyphBitmapElement : BaseGlyphElement { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal unsafe struct BitmapBlock { internal int a00; internal int a01; internal int a10; internal int a11; internal ushort pointSize; internal ushort renderingMode; ////// Critical - as this accesses unsafe code blocks /// TreatAsSafe - as this does not return unsafe information but is used to compare blocks /// [SecurityCritical, SecurityTreatAsSafe] internal bool Equal(BitmapBlock* rhs) { Invariant.Assert(rhs != null); return this.a00 == rhs->a00 && this.a01 == rhs->a01 && this.a10 == rhs->a10 && this.a11 == rhs->a11 && this.pointSize == rhs->pointSize && this.renderingMode == rhs->renderingMode; } } ////// Critical - Calls into the critical RetrieveKey method. /// [SecurityCritical] internal GlyphBitmapElement(CheckedPointer key) : base(BitmapsPerBlock) { RetrieveKey(key); } internal GlyphBitmapElement( int faceIndex, int a00, int a01, int a10, int a11, ushort pointSize, ushort renderingMode, ushort renderingFlags, FontSource fontSource ) : base(BitmapsPerBlock, faceIndex, fontSource, renderingFlags) { _bitmapKey.a00 = a00; _bitmapKey.a01 = a01; _bitmapKey.a10 = a10; _bitmapKey.a11 = a11; _bitmapKey.pointSize = pointSize; _bitmapKey.renderingMode = renderingMode; } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: The call to probe is checked for boundaries and pointer validity. /// This code is safe to call. /// [SecurityCritical, SecurityTreatAsSafe] public override void StoreKey(CheckedPointer d, out int realSize) { Debug.Assert(!FontSource.IsAppSpecific); int baseSize; StoreKeyInternal(d, out baseSize); baseSize = Util.Align4(baseSize); unsafe { realSize = baseSize + sizeof(BitmapBlock); void* dst = d.Probe(baseSize, sizeof(BitmapBlock)); *(BitmapBlock*)dst = _bitmapKey; } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// [SecurityCritical] public override void RetrieveKey(CheckedPointer m) { base.RetrieveKey(m); int baseSize = Util.Align4(base.Size); unsafe { BitmapBlock* s = (BitmapBlock*)m.Probe(baseSize, sizeof(BitmapBlock)); _bitmapKey = *s; } } ////// Critical: This code has unsafe code blocks It calls into HasMemory /// TreatAsSafe: This function is safe to call /// [SecurityCritical, SecurityTreatAsSafe] public override int GetHashCode() { int hash = base.GetHashCode(); unsafe { fixed (BitmapBlock* k = &_bitmapKey) { hash = HashFn.HashMemory(k, sizeof(BitmapBlock), hash); } } return HashFn.HashScramble(hash); } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: CheckedPointer construction is tracked and probe checks for invalid conditions /// [SecurityCritical, SecurityTreatAsSafe] public override bool Match(CheckedPointer p) { if (!base.Match(p)) return false; unsafe { BitmapBlock* b = (BitmapBlock*)p.Probe(Util.Align4(base.Size), sizeof(BitmapBlock)); return _bitmapKey.Equal(b); } } public override void GetData(CheckedPointer p, ElementCacher cacher) { unsafe { SetGlyphData(p + (Util.Align4(base.Size) + sizeof(BitmapBlock)), cacher); } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: Checked Pointer and ElementCacher are safe to work with. Construction is /// tracked for checkedpointer /// [SecurityCritical, SecurityTreatAsSafe] public override void AddToCache(CheckedPointer p, ElementCacher cacher) { int baseSize; StoreKeyInternal(p, out baseSize); baseSize = Util.Align4(baseSize); unsafe { BitmapBlock* b = (BitmapBlock*)p.Probe(baseSize, sizeof(BitmapBlock) + BitmapsPerBlock * sizeof(int)); *b = _bitmapKey; InitGlyphData(p + (baseSize + sizeof(BitmapBlock)), cacher); } } public override int Size { get { unsafe { return Util.Align4(base.Size) + sizeof(BitmapBlock) + BitmapsPerBlock * sizeof(int); } } } public override int Type { get { return 1; } } ////// Critical: This code calls into unsafe code blocks /// TreatAsSafe: This code allocates and returns an IntPtr that points to a bitmap. /// The IntPtr will fail to support any unsafe operations. /// [SecurityCritical, SecurityTreatAsSafe] private IntPtr AllocateBitmap(int size) { unsafe { // Reserve space to copy the bitmap header. byte* buffer = (byte*)AllocateNoThrow(sizeof(GlyphBitmap) + size); if (buffer == null) return IntPtr.Zero; // Pointer the rasterizer to the bitmap storage. return (IntPtr)(buffer + sizeof(GlyphBitmap)); } } //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 ////// Critical - as this results in the rasterizer accessing font stream. /// TreatAsSafe - as this results in obtaining glyph bitmaps that the client is supposed to see anyway. /// [SecurityCritical, SecurityTreatAsSafe] internal override bool AddGlyph(ushort glyphIndex) { try { if (_rasterizer == null) { if (IsTrueType) _rasterizer = new TrueTypeRasterizer(); else CreateOtfRasterizer(); _fontStream = FontSource.GetUnmanagedStream(); _numberOfGlyphs = _rasterizer.NewFont(_fontStream, FontSource.Uri, FaceIndex); MS.Internal.FontRasterization.Transform tform = new MS.Internal.FontRasterization.Transform(); tform.a00 = _bitmapKey.a00; tform.a01 = _bitmapKey.a01; tform.a10 = _bitmapKey.a10; tform.a11 = _bitmapKey.a11; _rasterizer.NewTransform( _bitmapKey.pointSize, tform, (OverscaleMode)_bitmapKey.renderingMode, RenderingFlags); } if (glyphIndex >= _numberOfGlyphs) return false; MS.Internal.FontRasterization.GlyphBitmap glyphBitmap; GlyphMetrics glyphMetrics; try { _rasterizer.NewGlyph(glyphIndex); _rasterizer.GetBitmap( AllocateBitmap, // allocation delegate IntPtr.Zero, // current buffer -1, // sentinel value that forces the rasterizer to allocate memory even for empty glyphs // we use it to make sure glyph header is allocated out glyphBitmap, out glyphMetrics ); // Check whether glyph bitmap coordinates overflow the 16 bit range that GlyphCache.cs relies on. // Windows Client Task 50200 tracks a more complete solution to this issue that will ensure rasterizers // can display extremely large bitmaps without truncation. if ((short)glyphMetrics.horizontalOrigin.x != glyphMetrics.horizontalOrigin.x || (short)glyphMetrics.horizontalOrigin.y != glyphMetrics.horizontalOrigin.y || (short)glyphMetrics.horizontalAdvance != glyphMetrics.horizontalAdvance || (short)glyphMetrics.verticalOrigin.x != glyphMetrics.verticalOrigin.x || (short)glyphMetrics.verticalOrigin.y != glyphMetrics.verticalOrigin.y || (short)glyphMetrics.verticalAdvance != glyphMetrics.verticalAdvance || (ushort)glyphMetrics.width != glyphMetrics.width || (ushort)glyphMetrics.height != glyphMetrics.height || (ushort)glyphBitmap.stride != glyphBitmap.stride ) { throw new FileFormatException(FontSource.Uri); } } catch (FileFormatException) { unsafe { // Create empty bitmap with zero metrics for malformed glyph programs. GlyphBitmap* gb = (GlyphBitmap*)Allocate(sizeof(GlyphBitmap)); // Cache memory is zero initialized by default. Debug.Assert(gb->horOriginX == 0); Debug.Assert(gb->height == 0); SetGlyph(glyphIndex, gb); return true; } } catch (OutOfMemoryException e) { object delegateError = e.Data["GetMemoryDelegateError"]; // In case the exception was raised due to the delegate failure, // throw FontCacheFullException so that we have a chance to renew the cache and retry the request. if (delegateError != null && (bool)delegateError) throw new FontCacheFullException(); throw; } // Glyph rendering code requires stride to be a multiple of 4, // make sure glyph rasterizers do the same. Debug.Assert((glyphBitmap.stride & 3) == 0); unsafe { GlyphBitmap* gd = (GlyphBitmap*)((byte*)glyphBitmap.pixels - sizeof(GlyphBitmap)); gd->horOriginX = glyphMetrics.horizontalOrigin.x; gd->horOriginY = glyphMetrics.horizontalOrigin.y; gd->horAdvance = glyphMetrics.horizontalAdvance; gd->verOriginX = glyphMetrics.verticalOrigin.x; gd->verOriginY = glyphMetrics.verticalOrigin.y; gd->verAdvance = glyphMetrics.verticalAdvance; gd->stride = glyphBitmap.stride; gd->width = glyphMetrics.width; gd->height = glyphMetrics.height; SetGlyph(glyphIndex, gd); } return true; } catch (SEHException e) { throw Util.ConvertInPageException(FontSource, e); } } private BitmapBlock _bitmapKey; private const int BitmapsPerBlock = 128; }; ////// Glyph path element class. /// Represents a block of glyph outlines /// Layout is: /// glyph block structure | file name string | usEmResolution | table of blockSize pointers to glyph data /// [FriendAccessAllowed] internal sealed class GlyphPathElement : BaseGlyphElement { [StructLayout(LayoutKind.Sequential, Pack = 1)] private unsafe struct OutlineBlock { internal ushort designEmHeight; } ////// Outline data is prefixed by a header containing three integers. /// private static readonly int GlyphOutlineHeaderSize = 3 * sizeof(int); /// /// Create a GlyphPathElement for a specific font face /// internal GlyphPathElement(int faceIndex, FontSource fontSource, ushort renderingFlags, ushort designEmHeight) : base(OutlinesPerBlock, faceIndex, fontSource, renderingFlags) { _outlineKey.designEmHeight = designEmHeight; } ////// Critical - Calls into the critical RetrieveKey method. /// [SecurityCritical] internal GlyphPathElement(CheckedPointer key) : base(OutlinesPerBlock) { RetrieveKey(key); } public override int GetHashCode() { int hash = base.GetHashCode(); return HashFn.HashScramble(hash); } public override void GetData(CheckedPointer p, ElementCacher cacher) { unsafe { SetGlyphData( p + (Util.Align4(base.Size) + Util.Align4(sizeof(OutlineBlock))), cacher); } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: ElementCacher and Checkedpointer are safe to work with /// Also adding this to cache is a safe operation /// [SecurityCritical, SecurityTreatAsSafe] public override void AddToCache(CheckedPointer p, ElementCacher cacher) { int baseSize; StoreKeyInternal(p, out baseSize); baseSize = Util.Align4(baseSize); unsafe { OutlineBlock* b = (OutlineBlock*)p.Probe(baseSize, Util.Align4(sizeof(OutlineBlock)) + OutlinesPerBlock * sizeof(int)); *b = _outlineKey; InitGlyphData(p + (baseSize + Util.Align4(sizeof(OutlineBlock))), cacher); } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// TreatAsSafe: CheckedPointer is safe to work with. Probe does bounds checking and /// pointer validation. /// [SecurityCritical, SecurityTreatAsSafe] public override void StoreKey(CheckedPointer d, out int realSize) { Debug.Assert(!FontSource.IsAppSpecific); int baseSize; StoreKeyInternal(d, out baseSize); baseSize = Util.Align4(baseSize); unsafe { realSize = baseSize + sizeof(OutlineBlock); void* dst = d.Probe(baseSize, sizeof(OutlineBlock)); *(OutlineBlock*)dst = _outlineKey; } } ////// Critical: Calls into probe which is critical and also has unsafe code blocks /// [SecurityCritical] public override void RetrieveKey(CheckedPointer m) { base.RetrieveKey(m); int baseSize = Util.Align4(base.Size); unsafe { OutlineBlock* s = (OutlineBlock*)m.Probe(baseSize, sizeof(OutlineBlock)); _outlineKey = *s; } } public override int Size { get { unsafe { return Util.Align4(base.Size) + Util.Align4(sizeof(OutlineBlock)) + OutlinesPerBlock * sizeof(int); } } } public override int Type { get { return 4; } } ////// Critical: Allocates memory and calls into unsafe code. This code is also unsafe /// TreatAsSafe: This call returns an IntPtr which is safe to expose because if /// you try to do anything with it that is unsafe it will throw an exception /// [SecurityCritical, SecurityTreatAsSafe] private IntPtr AllocateOutline(int size) { unsafe { // Allocate room for vertical origin, length and the outline itself. byte* data = (byte*)AllocateNoThrow(GlyphOutlineHeaderSize + size); if (data == null) return IntPtr.Zero; return (IntPtr)(data + GlyphOutlineHeaderSize); } } ////// Critical - as this results in the rasterizer accessing font stream. /// TreatAsSafe - as this results in obtaining glyph outline that the client is supposed to see anyway. /// [SecurityCritical, SecurityTreatAsSafe] internal override bool AddGlyph(ushort glyphIndex) { try { if (_rasterizer == null) { if (IsTrueType) _rasterizer = new TrueTypeRasterizer(); else CreateOtfRasterizer(); _fontStream = FontSource.GetUnmanagedStream(); _numberOfGlyphs = _rasterizer.NewFont(_fontStream, FontSource.Uri, FaceIndex); // if (!IsTrueType) { MS.Internal.FontRasterization.Transform tform = new MS.Internal.FontRasterization.Transform(); tform.a01 = tform.a10 = 0; tform.a00 = tform.a11 = _outlineKey.designEmHeight * 0x10000; _rasterizer.NewTransform( 12, tform, OverscaleMode.None, RenderingFlags); } else { unsafe { _pathAllocator = new TrueTypeRasterizer.Allocator(Allocate); } } } if (glyphIndex >= _numberOfGlyphs) return false; if (IsGlyphCached(glyphIndex)) { // another thread already rasterized the glyph // so we can skip adding it return true; } if (!IsTrueType) { _rasterizer.NewGlyph(glyphIndex); GlyphMetrics glyphMetrics; GlyphOutline glyphOutline; try { _rasterizer.GetOutline( AllocateOutline, // allocation delegate IntPtr.Zero, // current buffer -1, // sentinel value that forces the rasterizer to allocate memory even for empty glyphs // we use it to make sure glyph header is allocated out glyphOutline, out glyphMetrics ); } catch (OutOfMemoryException e) { object delegateError = e.Data["GetMemoryDelegateError"]; // In case the exception was raised due to the delegate failure, // throw FontCacheFullException so that we have a chance to renew the cache and retry the request. if (delegateError != null && (bool)delegateError) throw new FontCacheFullException(); throw; } unsafe { int* p = (int*)((byte*)glyphOutline.outline - GlyphOutlineHeaderSize); p[0] = glyphMetrics.verticalOrigin.x; p[1] = glyphMetrics.verticalOrigin.y; p[2] = glyphOutline.length; SetGlyph(glyphIndex, p); } } else { unsafe { GlyphPathData* gpd = ((TrueTypeRasterizer)_rasterizer).GetPath(_pathAllocator, RenderingFlags, glyphIndex); SetGlyph(glyphIndex, gpd); } } return true; } catch (SEHException e) { throw Util.ConvertInPageException(FontSource, e); } } private TrueTypeRasterizer.Allocator _pathAllocator; private OutlineBlock _outlineKey; private const int OutlinesPerBlock = 128; }; ////// Wrapper class for glyph cache access. Getting glyph bitmaps and outlines is more complex than /// using other font cache elements because data for different glyphs can come from different caches. /// The caller should GC.KeepAlive an instance of FontCacheAccessor class while glyph data is being used, /// otherwise there is risk of cache being garbage collected while bitmap data is used. /// internal class FontCacheAccessor { private List_nativeCaches; internal FontCacheAccessor() { _nativeCaches = new List (2); } /// /// Critical - as this calls GetGlyphs() which is Critical and return font information /// via glyphBitmaps parameter. /// [SecurityCritical] internal unsafe void GetBitmaps( string fontFileName, int faceIndex, int scaleX, int scaleY, ushort pointSize, ushort renderingMode, ushort renderingFlags, int glyphCount, ushort[] glyphIndices, void*[] glyphBitmaps ) { try { using (GlyphBitmapElement elem = new GlyphBitmapElement( faceIndex, scaleX, 0, 0, scaleY, pointSize, renderingMode, renderingFlags, // We set skipDemand to true here because we should have validated // whether the caller can access this font previously. // At this point we don't have context about the caller any more. new FontSource(new Uri(fontFileName, UriKind.Absolute), true) )) { GetGlyphs( elem, new PartialList(glyphIndices, 0, glyphCount), glyphBitmaps ); } } // Disable PreSharp warning about empty catch bodies, please see comments below. #pragma warning disable 6502 // Don't fail because of malformed fonts, use empty glyph bitmap stubs. catch (FileFormatException) { } // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs. catch (IOException) { } // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs. catch (UnauthorizedAccessException) { } // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs. catch (System.Net.WebException) { } #pragma warning restore 6502 catch (ArgumentOutOfRangeException e) { if (e.ParamName != "transform") throw; // Don't fail because of invalid transformations, because they can frequently happen in the process of animating text. } } /// /// Critical - as this calls the critical function GetServerCache() and exposes /// font cache data via glyphsArray parameter. /// [SecurityCritical] internal unsafe void GetGlyphs( BaseGlyphElement element, IListglyphIndices, void*[] glyphsArray ) { ElementCacher c; if (!element.IsAppSpecific) { c = CacheManager.GetServerCache(); if (c != null) { bool allFound = true; element.Reset(); for (int i = 0; i < glyphIndices.Count; ++i) { Debug.Assert(glyphsArray[i] == null); ushort glyph = glyphIndices[i]; ushort baseGlyph = element.GetBaseGlyph(glyph); if (element.GetBaseGlyph() != baseGlyph) { element.Reset(); element.SetBaseGlyph(baseGlyph); if (!c.ReadOnlyLookup(element)) { allFound = false; continue; } } if (element.GlyphData == null || !element.IsGlyphCached(glyph)) { allFound = false; continue; } CacheManager.SaveNativeCache(c, _nativeCaches); glyphsArray[i] = element.GetGlyph(glyph); Debug.Assert(glyphsArray[i] != null); } if (allFound) return; } } bool retry = false; c = CacheManager.GetCurrentCache(); Debug.Assert(c != null); element.Reset(); for (int i = 0; i < glyphIndices.Count; ++i) { if (glyphsArray[i] != null) continue; if (retry) { c = CacheManager.RenewCache(c); element.Reset(); } ushort glyph = glyphIndices[i]; ushort baseGlyph = element.GetBaseGlyph(glyph); try { if (element.GetBaseGlyph() != baseGlyph) { element.SetBaseGlyph(baseGlyph); if (!c.LookupAndAdd(element) && !element.IsAppSpecific) CacheManager.SendMissReport(element); } if (!element.IsGlyphCached(glyph)) { if (!element.AddGlyph(glyph)) { // client passed an invalid glyph index throw new ArgumentOutOfRangeException("glyph", SR.Get(SRID.GlyphIndexOutOfRange, glyph)); } } } catch (FontCacheFullException) { retry = true; --i; continue; } retry = false; CacheManager.SaveNativeCache(c, _nativeCaches); glyphsArray[i] = element.GetGlyph(glyph); Debug.Assert(glyphsArray[i] != null); } } }; } // 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
- DynamicValidator.cs
- Helper.cs
- PartDesigner.cs
- SqlWebEventProvider.cs
- CorrelationToken.cs
- AsyncResult.cs
- GridEntryCollection.cs
- DataGridViewRowsRemovedEventArgs.cs
- AmbientValueAttribute.cs
- QilChoice.cs
- TableCellAutomationPeer.cs
- MobileUserControl.cs
- MailMessage.cs
- CodeTypeDelegate.cs
- MsmqProcessProtocolHandler.cs
- BinaryObjectReader.cs
- ScrollProperties.cs
- Subtree.cs
- DNS.cs
- AnnotationComponentManager.cs
- DispatcherTimer.cs
- IriParsingElement.cs
- PackagePartCollection.cs
- ThreadLocal.cs
- RegionData.cs
- IntAverageAggregationOperator.cs
- ForceCopyBuildProvider.cs
- WebExceptionStatus.cs
- GridViewDeletedEventArgs.cs
- SystemDropShadowChrome.cs
- HttpCachePolicyElement.cs
- HtmlElement.cs
- Variant.cs
- URLAttribute.cs
- ProxyWebPart.cs
- RelationshipEnd.cs
- GridEntry.cs
- HebrewCalendar.cs
- SqlFlattener.cs
- Trace.cs
- BasicKeyConstraint.cs
- OracleBoolean.cs
- FullTextLine.cs
- Delay.cs
- ViewSimplifier.cs
- RenderCapability.cs
- ProcessThreadCollection.cs
- SmtpSpecifiedPickupDirectoryElement.cs
- CharacterMetrics.cs
- WindowsFormsHost.cs
- BitmapEffectDrawing.cs
- DataGridItemCollection.cs
- GeometryDrawing.cs
- JpegBitmapEncoder.cs
- KerberosTicketHashIdentifierClause.cs
- TabletCollection.cs
- X509ScopedServiceCertificateElementCollection.cs
- BounceEase.cs
- InfoCardBaseException.cs
- DropTarget.cs
- HighContrastHelper.cs
- _ShellExpression.cs
- QueryOutputWriter.cs
- SqlDataReader.cs
- SatelliteContractVersionAttribute.cs
- AmbiguousMatchException.cs
- NetDataContractSerializer.cs
- SingleAnimationUsingKeyFrames.cs
- HealthMonitoringSectionHelper.cs
- InputDevice.cs
- AssemblyHash.cs
- NamedPipeAppDomainProtocolHandler.cs
- ComPlusDiagnosticTraceRecords.cs
- ModelTreeManager.cs
- IdleTimeoutMonitor.cs
- Helpers.cs
- ListViewDeleteEventArgs.cs
- ObjectDataSourceChooseTypePanel.cs
- ByteStack.cs
- CodeGenerationManager.cs
- Util.cs
- DataGridViewBindingCompleteEventArgs.cs
- TreeViewBindingsEditor.cs
- InvalidFilterCriteriaException.cs
- ModuleConfigurationInfo.cs
- EventSourceCreationData.cs
- OdbcEnvironment.cs
- ComponentResourceManager.cs
- Bidi.cs
- PieceNameHelper.cs
- SchemaImporter.cs
- XmlIlGenerator.cs
- NetStream.cs
- XmlStreamStore.cs
- DoubleLinkList.cs
- FrameworkContentElement.cs
- WmlLinkAdapter.cs
- TemplateControlBuildProvider.cs
- Fonts.cs
- Util.cs