GlyphElement.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / 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 System.Windows.Media; 

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;
using UnsafeNativeMethods = MS.Win32.PresentationCore.UnsafeNativeMethods;
 
// 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)MilGlyphRun.IsTrueType) != 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); 
                    }

                    if (glyphMetrics.width > (glyphBitmap.stride * 8))
                    { 
                        throw new System.ArgumentException("Rasterizer produced an invalid width", "glyphMetrics.width");
                    } 
                } 
                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;

        private class FontFaceID 
        {
            // 
            // The font file name should not be accessible outside of SecurityCritical 
            // functions.
            // 
            internal SecurityCriticalData _fontFileName;
            internal int _faceIndex;
            internal int _scaleX;
            internal int _scaleY; 
            internal ushort _flags;
            internal float _renderingEmSize; 
 
            /// 
            /// Helper function: wraps FontFace information into a FontFaceID struct 
            /// 
            internal FontFaceID(SecurityCriticalData fontFileName,
                                             int fontFaceIndex,
                                             uint scaleX, 
                                             uint scaleY,
                                             ushort glyphRunFlags, 
                                             float emSize) 
            {
                _fontFileName = fontFileName; 
                _faceIndex = fontFaceIndex;
                _scaleX = (int)scaleX;
                _scaleY = (int)scaleY;
                _flags = glyphRunFlags; 
                _renderingEmSize = emSize;
 
                if (_scaleY > _verticalAntialiasingThreashold) 
                {
                    // we are using VAA (vertical anti aliasing, that means 6*5 overscaled 
                    // bitmaps instead of regular 6*1) if font size is big, or if VAA
                    // is forced by user
                    _flags |= (ushort)MilGlyphRun.ForceVAA;
                } 
            }
        } 
 
        private const ushort _fontCacheFlagMask
            = (ushort)MilGlyphRun.Hinting 
            | (ushort)MilGlyphRun.BoldSimulation
            | (ushort)MilGlyphRun.ItalicSimulation
            | (ushort)MilGlyphRun.Sideways
            | (ushort)MilGlyphRun.IsTrueType; 

        private const ushort _faceFlagMask 
            = _fontCacheFlagMask 
            | (ushort)MilGlyphRun.ForceVAA
            | (ushort)MilGlyphRun.VerticalDropOut; 

        private const uint _verticalAntialiasingThreashold = 20 * 0x10000;

        // Matches GLYPH_BASE_CREATE_REQUEST in native code 
        unsafe private struct GLYPH_BASE_CREATE_REQUEST
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok 
            public uint         uFontFaceIndex;     // IN font typeface index
 
            public ushort       usGlyphRunFlags;    // IN GlyphRun flags

            public uint         dScaleX;
            public uint         dScaleY; 

            public float        muSize; 
 
            //
            //  
            // Validation has already been done on the font filename, so we protect it
            // here.
            // 
            // 
            [SecurityCritical]
            public char *       pszFontFileName;    // IN font filename string 
 
            public ushort       usGlyphCount;       // IN number of glyphs in a glyph run
 
            public ushort *     pusGlyphIndices;    // IN glyph indices in a glyph run
                                                    // (caller responsible for alloc/free)
#pragma warning restore 649
        } 

        unsafe private struct GLYPH_GEOMETRY_CREATE_REQUEST 
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok
#pragma warning disable 169  // baseRequest is not used directly, but is required for casting 
            GLYPH_BASE_CREATE_REQUEST baseRequest;

            public float        fBaseLineX;
            public float        fBaseLineY; 

            public float *      pfGlyphPositions; 
#pragma warning restore 169 
#pragma warning restore 649
        } 

        // Matches GLYPH_BITMAP_CREATE_REQUEST in native code
        unsafe private struct GLYPH_BITMAP_CREATE_REQUEST
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok
#pragma warning disable 169  // baseRequest is not used directly, but is required for casting 
            GLYPH_BASE_CREATE_REQUEST baseRequest; 

            public uint         faceHandle;         // IN internal font face identifier 

#pragma warning restore 169
#pragma warning restore 649
        } 

        ///  
        /// Callback entry point for unmanaged code to ask for glyph realizations. 
        /// 
        ///  
        /// Critical - calls critical code
        ///
        [SecurityCritical]
        internal static int CreateGlyphsCallback(IntPtr /*CMilSlaveGlyphCache* */ nativeObject, 
                                                 IntPtr /*GLYPH_BITMAP_CREATE_REQUEST | GLYPH_GEOMETRY_CREATE_REQUEST* */ request,
                                                 ushort       isGeometryRequest) 
        { 
            try
            { 
                FontCacheAccessor fontCacheAccessor = new FontCacheAccessor();

                fontCacheAccessor.CreateGlyphsAtRenderTime(nativeObject, request, isGeometryRequest);
            } 
            catch (Exception e)
            { 
                // 
                // Need to catch all exceptions at this entry point and convert them into a
                // HRESULT that managed code can understand and handle. 
                //
                e.ToString();
                return HRESULT.E_FAIL;
            } 
            return HRESULT.S_OK;
        } 
 
        /// 
        /// Marshals glyph requests 
        /// 
        /// 
        /// Critical - calls critical code
        /// 
        [SecurityCritical]
        private unsafe void CreateGlyphsAtRenderTime(IntPtr /*CMilSlaveGlyphCache* */ nativeObject, 
                                                     IntPtr /*GLYPH_BITMAP_CREATE_REQUEST | GLYPH_GEOMETRY_CREATE_REQUEST* */ request, 
                                                     ushort       isGeometryRequest)
        { 
            GLYPH_BASE_CREATE_REQUEST* pRequest = (GLYPH_BASE_CREATE_REQUEST*)request;

            string fontFileName = new String(pRequest->pszFontFileName);
 
            FontFaceID faceId = new FontFaceID(new SecurityCriticalData(fontFileName),
                                                  (int)pRequest->uFontFaceIndex, 
                                                  pRequest->dScaleX, 
                                                  pRequest->dScaleY,
                                                  pRequest->usGlyphRunFlags, 
                                                  pRequest->muSize);

            ushort[] glyphIndices = new ushort[pRequest->usGlyphCount];
 
            int glyphCount = checked((int)pRequest->usGlyphCount);
 
            // Put Marshal.CopyArray or something in here 
            for (uint n = 0; n < pRequest->usGlyphCount; n++)
            { 
                glyphIndices[n] = pRequest->pusGlyphIndices[n];
            }

            if (isGeometryRequest == 0) 
            {
                GLYPH_BITMAP_CREATE_REQUEST* pRequestAsBitmap = (GLYPH_BITMAP_CREATE_REQUEST*)request; 
 
                // Realize and send bitmaps
                CreateGlyphBitmapsHelper( 
                    nativeObject,
                    faceId,
                    glyphIndices,
                    pRequestAsBitmap->faceHandle 
                    );
            } 
            else 
            {
                GLYPH_GEOMETRY_CREATE_REQUEST* pRequestAsGlyphs = (GLYPH_GEOMETRY_CREATE_REQUEST*)request; 

                // Realize and send geometry
                CreateGlyphGeometryHelper(
                    nativeObject, 
                    faceId,
                    glyphIndices, 
                    pRequestAsGlyphs->pfGlyphPositions, 
                    pRequestAsGlyphs->fBaseLineX,
                    pRequestAsGlyphs->fBaseLineY 
                    );
            }
        }
 
        /// 
        /// Critical - as this accesses critical data and calls critical code 
        ///  
        [SecurityCritical]
        private unsafe void CreateGlyphGeometryHelper( 
            IntPtr nativeGlyphRun,
            FontFaceID faceId,
            ushort[] glyphIndices,
            float *pGlyphPositions, 
            float fBaseLineX,
            float fBaseLineY 
            ) 
        {
            Debug.Assert(glyphIndices.Length > 0); 

            Geometry glyphRunGeometry = BuildGeometry(faceId, glyphIndices, pGlyphPositions, fBaseLineX, fBaseLineY);

            if (glyphRunGeometry.IsEmpty()) 
            {
                return; 
            } 

            // If glyphRunGeometry is non empty, it is of type GeometryGroup, and all the 
            // geometries inside are of type PathGeometry
            GeometryGroup glyphRunGroup = (GeometryGroup)glyphRunGeometry;

            Geometry.PathGeometryData glyphRunPathData = glyphRunGroup.GetAsPathGeometry().GetPathGeometryData(); 

            // Packet layout is: 
            //   MILCMD_GLYPHRUN_SETRENDERGEOMETRY 
            //   MILCMD_PATHGEOMETRY
            //   PathFigure data block (glyphRunPathData.SerializedData) 

            // Allocate sufficient memory
            uint pathGeometrySize = (uint)sizeof(DUCE.MILCMD_PATHGEOMETRY);
            uint dataLength = (uint)glyphRunPathData.SerializedData.Length; 

            uint packetSize = checked(pathGeometrySize + dataLength); 
 
            byte[] packetBlock = new byte[packetSize];
 
            fixed (byte* packet = packetBlock)
            {
                DUCE.MILCMD_PATHGEOMETRY *pathGeometryPacket = (DUCE.MILCMD_PATHGEOMETRY *)(packet);
                pathGeometryPacket->Type = MILCMD.MilCmdPathGeometry; 
                //pathGeometryPacket->Transform = 0;
                pathGeometryPacket->FillRule = glyphRunGroup.FillRule; 
                pathGeometryPacket->FiguresSize = glyphRunPathData.Size; 

                byte* pathData = (byte *)(packet + pathGeometrySize); 
                Marshal.Copy(glyphRunPathData.SerializedData, 0, (IntPtr)pathData, glyphRunPathData.SerializedData.Length);

                // Send packet
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphRun_SetGeometryAtRenderTime( 
                    nativeGlyphRun,
                    (byte *)packet, 
                    packetSize 
                    ));
            } 
        }

        /// 
        /// Obtains geometry for the glyph run. 
        /// 
        /// The geometry returned contains the combined geometry of all glyphs in the glyph run. 
        /// Overlapping contours are merged by performing a Boolean union operation. 
        /// 
        /// Critical - performs unsafe operations 
        /// 
        [SecurityCritical]
        private unsafe Geometry BuildGeometry(
            FontFaceID faceId, 
            ushort[] glyphIndices,
            float *pPositions, 
            float fBaseLineX, 
            float fBaseLineY
            ) 
        {
            GeometryGroup accumulatedGeometry = null;

            Uri fontURI = new Uri(faceId._fontFileName.Value, UriKind.Absolute); 

            bool IsSideways = ((faceId._flags & (UInt16)MilGlyphRun.Sideways)  != 0); 
            bool IsLeftToRight = ((faceId._flags & (UInt16)MilGlyphRun.IsLeftToRight) != 0); 

            // If there are Y positions the array is packed as positions XYXYXY etc, if there 
            // are no Y positions, it's just XXX and Y is assumed to be 0.
            bool HasYPositions = ((faceId._flags & (UInt16)MilGlyphRun.HasYPositions) != 0);

            StyleSimulations style = StyleSimulations.None; 
            if ((faceId._flags & (UInt16)MilGlyphRun.BoldSimulation) != 0)
            { 
                style |= StyleSimulations.BoldSimulation; 
            }
            if ((faceId._flags & (UInt16)MilGlyphRun.ItalicSimulation) != 0) 
            {
                style |= StyleSimulations.ItalicSimulation;
            }
 
            GlyphTypeface glyphTypeface = new GlyphTypeface(fontURI, style, false);
 
            for (int i = 0; i < glyphIndices.Length; i++) 
            {
                ushort glyphIndex = glyphIndices[i]; 

                Geometry glyphGeometry = glyphTypeface.ComputeGlyphOutline(glyphIndex, IsSideways, faceId._renderingEmSize);
                if (glyphGeometry.IsEmpty())
                    continue; 

                // transform glyphGeometry to the glyph origin 
                unsafe { 
                    float xPosition;
                    float yPosition; 
                    if (HasYPositions)
                    {
                        xPosition = ((float*)pPositions)[2*i];
                        yPosition = ((float*)pPositions)[2 * i + 1]; 
                    }
                    else 
                    { 
                        //
                        // If there are no Y positions, the first X position is always assumed to be 0 and is 
                        // ommitted, making the array one element smaller. If there are Y positions, all X
                        // and Y positions are fully specified
                        //
                        xPosition = (i == 0) ? 0 : ((float*)pPositions)[i-1]; 
                        yPosition = 0;
                    } 
                    // 
                    // If this is an RTL glyph run, xPosition will already be negative. We still need to subtract
                    // the AdvanceWidth for the glyph though. For regular bitmap rendering, this happens in 
                    // CGlyphRunMaker::CalculateGlyphPositions()
                    //
                    float xOffset = (xPosition - (float)(IsLeftToRight ? 0 : glyphTypeface.GetAdvanceWidth(glyphIndex))) * faceId._renderingEmSize + fBaseLineX;
                    float yOffset = yPosition * faceId._renderingEmSize + fBaseLineY; 
                    glyphGeometry.Transform = new TranslateTransform(xOffset, yOffset);
                } 
 
                if (accumulatedGeometry == null)
                { 
                    accumulatedGeometry = new GeometryGroup();
                    accumulatedGeometry.FillRule = FillRule.Nonzero;
                }
 
                accumulatedGeometry.Children.Add(glyphGeometry.GetOutlinedPathGeometry(GlyphRun.RelativeFlatteningTolerance,
                                                                                   ToleranceType.Relative)); 
                } 
            // Make sure to always return Geometry.Empty from public methods for empty geometries.
            if (accumulatedGeometry == null || accumulatedGeometry.IsEmpty()) 
                return Geometry.Empty;
            return accumulatedGeometry;
        }
 

        ///  
        /// Critical - as this accesses critical data and calls GetBitmaps which is Critical. 
        /// 
        [SecurityCritical] 
        private unsafe void CreateGlyphBitmapsHelper(
            IntPtr nativeGlyphCache,
            FontFaceID faceId,
            ushort[] glyphIndices, 
            uint faceHandle
            ) 
        { 
            Debug.Assert(glyphIndices.Length > 0);  // Should not pInvoke here when no glyphs are missing
 
            void*[] glyphBitmaps = new void*[glyphIndices.Length];

            GetBitmaps(
                faceId._fontFileName.Value, 
                faceId._faceIndex,
                faceId._scaleX, 
                faceId._scaleY, 
                (ushort)faceId._renderingEmSize,
                (faceId._flags & (uint)MilGlyphRun.ForceVAA) != 0 
                ? (ushort)MS.Internal.FontRasterization.OverscaleMode.OverscaleXandY
                : (ushort)MS.Internal.FontRasterization.OverscaleMode.OverscaleX, //renderingMode
                (ushort)(faceId._flags & _fontCacheFlagMask), //renderingFlags,
                glyphIndices.Length, 
                glyphIndices,
                /*OUT*/ glyphBitmaps 
                ); 

            bool needDropOut = (faceId._flags & (uint)MilGlyphRun.VerticalDropOut) != 0; 

            AddBitmapsToNativeCacheAtRenderTime(nativeGlyphCache,
                                                faceHandle,
                                                glyphBitmaps, 
                                                glyphIndices,
                                                faceId._flags, 
                                                needDropOut); 
        }
 
        /// 
        /// Critical - as this accesses unsafe code blocks.
        /// 
        [SecurityCritical] 
        private unsafe void AddBitmapsToNativeCacheAtRenderTime(IntPtr nativeGlyphCache,
                                                                uint faceHandle, 
                                                                void*[] glyphBitmaps, 
                                                                ushort[] glyphIndices,
                                                                ushort faceFlags, 
                                                                bool needDropOut)
        {
            Debug.Assert(glyphBitmaps != null);
            Debug.Assert(glyphBitmaps.Length != 0); 

            DUCE.MILCMD_GLYPHCACHE_ADDBITMAPS command; 
 
            try
            { 
                command.Type = MILCMD.MilCmdGlyphCacheAddBitmaps;
                command.FontFaceHandle = faceHandle;
                command.FaceFlags = faceFlags;
                command.GlyphCount = checked((UInt16)glyphIndices.Length); 
                command.Handle = DUCE.ResourceHandle.Null;  // Unused - MIL resource handle - bypassing DUCE channels
 
                // Precalculate size of command data buffer 
                // The uint is used up by the MemWriter
                int dataSize = checked(sizeof(uint) + glyphIndices.Length * sizeof(ushort)); 

                // Count the total size of the bitmaps.
                if (!needDropOut)
                { 
                    for (int i = 0; i < glyphIndices.Length; i++)
                    { 
                        int blockSize = GetBitmapTransferSize((GlyphBitmap*)glyphBitmaps[i]); 
                        dataSize = checked(dataSize + blockSize);
                    } 
                }
                else
                {
                    for (int i = 0; i < glyphIndices.Length; i++) 
                    {
                        int blockSize = GetTransformedBitmapTransferSize((GlyphBitmap*)glyphBitmaps[i]); 
                        dataSize = checked(dataSize + blockSize); 
                    }
                } 

                // Talk directly to native GlyphCache object
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_BeginCommandAtRenderTime(
                    nativeGlyphCache, 
                    (byte*)&command,
                    (UInt32)sizeof(DUCE.MILCMD_GLYPHCACHE_ADDBITMAPS), 
                    (UInt32)dataSize 
                    ));
 
            }
            catch (System.OverflowException e)
            {
                // re-throw more readable exception 
                throw new OutOfMemoryException(SR.Get(SRID.TooManyGlyphRuns), e);
            } 
 
            // Write the bitmaps if needed.
            // Bitmaps should go first because of aligning. 
            if (!needDropOut)
            {
                for (int i = 0; i < glyphIndices.Length; i++)
                { 
                    TransferBitmapAtRenderTime(nativeGlyphCache, (GlyphBitmap*)glyphBitmaps[i]);
                } 
            } 
            else
            { 
                for (int i = 0; i < glyphIndices.Length; i++)
                {
                    TransferTransformedBitmapAtRenderTime(nativeGlyphCache, (GlyphBitmap*)glyphBitmaps[i]);
                } 
            }
 
            // Write the glyph indices. 
            fixed (ushort* pData = glyphIndices)
            { 
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime(
                    nativeGlyphCache,
                    (byte*)pData,
                    (uint)(glyphIndices.Length * sizeof(ushort)))); 
            }
 
            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_EndCommandAtRenderTime( 
                    nativeGlyphCache
                    )); 
        }

        /// 
        /// Compose and transfer a piece of MILCMD_GLYPHCACHE_ADDBITMAPS command 
        /// that represents given glyph bitmap.
        ///  
        ///  
        /// Critical - as this accesses unsafe code blocks.
        ///  
        [SecurityCritical]
        private unsafe void TransferBitmapAtRenderTime(IntPtr nativeGlyphCache, GlyphBitmap* pBitmap)
        {
            if (pBitmap == null) 
            {
                TransferStubAtRenderTime(nativeGlyphCache); 
                return; 
            }
 
            DUCE.MILCMD_GLYPHBITMAP bitmap = new DUCE.MILCMD_GLYPHBITMAP();
            bitmap.horOriginX = checked((Int16)(pBitmap->horOriginX));
            bitmap.horOriginY = checked((Int16)(pBitmap->horOriginY));
            bitmap.horAdvance = checked((Int16)(pBitmap->horAdvance)); 
            bitmap.verOriginX = checked((Int16)(pBitmap->verOriginX));
            bitmap.verOriginY = checked((Int16)(pBitmap->verOriginY)); 
            bitmap.width = checked((UInt16)(pBitmap->width)); 
            bitmap.height = checked((UInt16)(pBitmap->height));
            bitmap.stride = checked((UInt16)(pBitmap->stride)); 

            int cbDataSize = (int)bitmap.height * (int)bitmap.stride;

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                nativeGlyphCache,
                (byte*)&bitmap, 
                (uint)sizeof(DUCE.MILCMD_GLYPHBITMAP))); 

            if (cbDataSize != 0) 
            {
                byte* pData = (byte*)pBitmap + sizeof(GlyphBitmap);
                // Write directly to slave GlyphCache
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                    nativeGlyphCache,
                    pData, 
                    (uint)cbDataSize)); 
            }
        } 


        /// 
        /// This routine is for seldom circumstances, when 
        /// font cache unabled supply particular glyph bitmap.
        /// When happened so we'll replace glyph with special shape 
        /// (currently empty) 
        /// 
        ///  
        /// Critical - as this accesses unsafe code blocks.
        /// 
        [SecurityCritical]
        private unsafe void TransferStubAtRenderTime(IntPtr nativeGlyphCache) 
        {
            // create empty struct GlyphBitmap in stack frame 
            DUCE.MILCMD_GLYPHBITMAP bitmap = new DUCE.MILCMD_GLYPHBITMAP(); 

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                nativeGlyphCache,
                (byte*)&bitmap,
                (uint)sizeof(DUCE.MILCMD_GLYPHBITMAP)));
        } 

        /// 
        /// Pass the GlyphBitmap to command buffer, along the way 
        /// making horizontal strokes *a little* thicker than given
        /// GlyphBitmap has. 
        ///
        /// This thickening algorythm (also referred to as "virtual
        /// drop out control") is completely heuristic. It was
        /// initially proposed by Beat Stamm (beats). This version 
        /// differs much from the initial. It thickens only
        /// horizontal strokes, increasing stroke width up to 2 virtual 
        /// pixels. Heuristic prohibits thickening if it cause 
        /// the stroke to bleed through pixel boundary, and also if
        /// next stroke is too close to given. 
        /// 
        /// 
        /// Critical - as this accesses unsafe code blocks.
        ///  
        [SecurityCritical]
        private unsafe void TransferTransformedBitmapAtRenderTime(IntPtr slaveGlyphCache, GlyphBitmap* pBitmap) 
        { 
            if (pBitmap == null)
            { 
                TransferStubAtRenderTime(slaveGlyphCache);
                return;
            }
 
            // Vertical drop out needs glyph bitmap (that's ovescaled 5 times by Y axis)
            // to be vertically aligned to physycal pixel grid. 
            // We may need to allocate extra rows above and below 
            // original image.
            int bitmapTop = -pBitmap->horOriginY; 
            int bitmapBottom = bitmapTop + pBitmap->height;
            int pixelTop = bitmapTop >= 0 ? bitmapTop / 5 : -((4 - bitmapTop) / 5);
            int pixelBottom = bitmapBottom >= 0 ? (bitmapBottom + 4) / 5 : -((-bitmapBottom) / 5);
            int rowsAbove = bitmapTop - pixelTop * 5; 
            int rowsBelow = pixelBottom * 5 - bitmapBottom;
            Debug.Assert(rowsAbove >= 0 && rowsAbove < 5); 
            Debug.Assert(rowsBelow >= 0 && rowsBelow < 5); 
            int newSize = checked(
                sizeof(DUCE.MILCMD_GLYPHBITMAP) 
                + (pBitmap->height + rowsBelow + rowsAbove) * pBitmap->stride
                );

            byte* pData = stackalloc byte[newSize]; 
            DUCE.MILCMD_GLYPHBITMAP* pNewBitmap = (DUCE.MILCMD_GLYPHBITMAP*)pData;
 
            // fill bitmap header 
            pNewBitmap->horOriginX = checked((Int16)(pBitmap->horOriginX));
            pNewBitmap->horOriginY = checked((Int16)(pBitmap->horOriginY + rowsAbove)); 
            pNewBitmap->horAdvance = checked((Int16)(pBitmap->horAdvance));
            pNewBitmap->verOriginX = checked((Int16)(pBitmap->verOriginX - rowsAbove));
            pNewBitmap->verOriginY = checked((Int16)(pBitmap->verOriginY));
            pNewBitmap->width = checked((UInt16)(pBitmap->width)); 
            pNewBitmap->height = checked((UInt16)(pBitmap->height + rowsAbove + rowsBelow));
            pNewBitmap->stride = checked((UInt16)(pBitmap->stride)); 
 
            UInt32* pSrc = (UInt32*)((byte*)pBitmap + sizeof(GlyphBitmap));
            UInt32* pDst = (UInt32*)(pData + sizeof(DUCE.MILCMD_GLYPHBITMAP)); 
            int stride32 = pBitmap->stride >> 2;

            // fill added rows above with zeros
            UInt32* pDstAbove = pDst; 
            int sizeAbove = rowsAbove * stride32;
            for (int i = sizeAbove; --i >= 0; ) 
                pDst[i] = 0; 

            // copy bitmap bits 
            UInt32* pDstOrigin = pDstAbove + sizeAbove;
            int sizeOrigin = stride32 * pBitmap->height;
            for (int i = sizeOrigin; --i >= 0; )
                pDstOrigin[i] = pSrc[i]; 

            // fill added rows above with zeros 
            UInt32* pDstBelow = pDstOrigin + sizeOrigin; 
            int sizeBelow = rowsBelow * stride32;
            for (int i = sizeBelow; --i >= 0; ) 
                pDstBelow[i] = 0;

            UInt32* pColon = pDst;
 
            int bandsCount = pixelBottom - pixelTop;
            int colonsCount = (int)((pNewBitmap->width + 31) >> 5); 
            Debug.Assert(colonsCount <= stride32); 

            if (bandsCount == 1) 
            {
                for (int i = 0; i < colonsCount; i++, pColon++)
                {
                    UInt32* p0 = pColon; 
                    UInt32* p1 = p0 + stride32;
                    UInt32* p2 = p1 + stride32; 
                    UInt32* p3 = p2 + stride32; 
                    UInt32* p4 = p3 + stride32;
                    // bleeding up: set the bit if there is "one" 
                    // on next row but not two previous and second next.
                    // The magic code below actually repeats many times
                    // the same formula:
                    // bit |= nextBit & ~next2Bit & ~previousBit & ~previous2Bit 
                    // where some members are removed if we are close to the
                    // edge so some "next" and "previous" are missed. 
 
                    *p0 |= *p1 & ~*p2;
                    *p1 |= ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                    *p3 |= ~*p1 & ~*p2 & *p4;
                    // bleed down: same as bleeding up but Y direction is reversed
                    *p4 |= ~*p2 & *p3; 
                    *p3 |= ~*p1 & *p2 & ~*p4;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4; 
                    *p1 |= *p0 & ~*p2 & ~*p3; 
                }
            } 
            else
            {   // there are two or more bands
                for (int i = 0; i < colonsCount; i++, pColon++)
                { 
                    UInt32* p0 = pColon;
                    UInt32* p1 = p0 + stride32; 
                    UInt32* p2 = p1 + stride32; 
                    UInt32* p3 = p2 + stride32;
                    UInt32* p4 = p3 + stride32; 
                    UInt32* p5 = p4 + stride32;
                    UInt32* p6 = p5 + stride32;

                    // Handle first band 
                    // bleed up
                    *p0 |= *p1 & ~*p2; 
                    *p1 |= ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                    *p3 |= ~*p1 & ~*p2 & *p4 & ~*p5; 
                    // bleed down
                    *p4 |= ~*p2 & *p3 & ~*p5 & ~*p6;
                    *p3 |= ~*p1 & *p2 & ~*p4 & ~*p5;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4; 
                    *p1 |= *p0 & ~*p2 & ~*p3;
 
                    UInt32* q1 = p4; 
                    UInt32* q2 = p3;
 
                    // Handle middle bands
                    for (int b = bandsCount - 2; --b >= 0; )
                    {
                        p0 = q1 + stride32; 
                        p1 = p0 + stride32;
                        p2 = p1 + stride32; 
                        p3 = p2 + stride32; 
                        p4 = p3 + stride32;
                        p5 = p4 + stride32; 
                        p6 = p5 + stride32;
                        // bleed up
                        *p0 |= ~*q2 & ~*q1 & *p1 & ~*p2;
                        *p1 |= ~*q1 & ~*p0 & *p2 & ~*p3; 
                        *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                        *p3 |= ~*p1 & ~*p2 & *p4 & ~*p5; 
                        // bleed down 
                        *p4 |= ~*p2 & *p3 & ~*p5 & ~*p6;
                        *p3 |= ~*p1 & *p2 & ~*p4 & ~*p5; 
                        *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4;
                        *p1 |= ~*q1 & *p0 & ~*p2 & ~*p3;
                        q1 = p4;
                        q2 = p3; 
                    }
 
                    // Handle last band 
                    p0 = q1 + stride32;
                    p1 = p0 + stride32; 
                    p2 = p1 + stride32;
                    p3 = p2 + stride32;
                    p4 = p3 + stride32;
                    // bleed up 
                    *p0 |= ~*q2 & ~*q1 & *p1 & ~*p2;
                    *p1 |= ~*q1 & ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4; 
                    *p3 |= ~*p1 & ~*p2 & *p4;
                    // bleed down 
                    *p4 |= ~*p2 & *p3;
                    *p3 |= ~*p1 & *p2 & ~*p4;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4;
                    *p1 |= ~*q1 & *p0 & ~*p2 & ~*p3; 
                }
 
            } 

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                slaveGlyphCache,
                (byte*)pData,
                (uint)newSize));
        } 

        ///  
        /// Calculate the size in command buffer, required for transferring 
        /// given bitmap to rendering machine.
        ///  
        /// 
        /// size, in bytes
        /// 
        /// Critical - as this accesses unsafe code blocks. 
        /// 
        [SecurityCritical] 
        private static unsafe int GetBitmapTransferSize(GlyphBitmap* pBitmap) 
        {
            int cbSize = sizeof(DUCE.MILCMD_GLYPHBITMAP); 
            if (pBitmap != null)
            {
                cbSize += pBitmap->height * pBitmap->stride;
            } 

            return cbSize; 
        } 

        /// 
        /// Precalculate the size of MILCMD_GLYPHCACHE_ADDBITMAPS command segment
        /// that will be used by TransferTransformedBitmap
        /// 
        /// given glyph bitmap 
        /// size, in bytes
        ///  
        /// Critical: accepts a pointer and processes it with no validation 
        /// 
        [SecurityCritical] 
        private static unsafe int GetTransformedBitmapTransferSize(GlyphBitmap* pBitmap)
        {
            int cbSize = sizeof(DUCE.MILCMD_GLYPHBITMAP);
            if (pBitmap != null) 
            {
                // Vertical drop out needs glyph bitmap (that's ovescaled 5 times by Y axis) 
                // to be vertically aligned to physycal pixel grid. 
                // We may need to allocate extra rows above and below
                // original image. 
                int bitmapTop = -pBitmap->horOriginY;
                int bitmapBottom = bitmapTop + pBitmap->height;
                int pixelTop = bitmapTop >= 0 ? bitmapTop / 5 : -((4 - bitmapTop) / 5);
                int pixelBottom = bitmapBottom >= 0 ? (bitmapBottom + 4) / 5 : -((-bitmapBottom) / 5); 
                int rowsAbove = bitmapTop - pixelTop * 5;
                int rowsBelow = pixelBottom * 5 - bitmapBottom; 
 
                Debug.Assert(rowsAbove >= 0 && rowsAbove < 5);
                Debug.Assert(rowsBelow >= 0 && rowsBelow < 5); 

                cbSize += (pBitmap->height + rowsBelow + rowsAbove) * pBitmap->stride;
            }
 
            return cbSize;
        } 
 

        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,
            /*OUT*/ 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, 
            IList glyphIndices,
            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.
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 System.Windows.Media; 

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;
using UnsafeNativeMethods = MS.Win32.PresentationCore.UnsafeNativeMethods;
 
// 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)MilGlyphRun.IsTrueType) != 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); 
                    }

                    if (glyphMetrics.width > (glyphBitmap.stride * 8))
                    { 
                        throw new System.ArgumentException("Rasterizer produced an invalid width", "glyphMetrics.width");
                    } 
                } 
                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;

        private class FontFaceID 
        {
            // 
            // The font file name should not be accessible outside of SecurityCritical 
            // functions.
            // 
            internal SecurityCriticalData _fontFileName;
            internal int _faceIndex;
            internal int _scaleX;
            internal int _scaleY; 
            internal ushort _flags;
            internal float _renderingEmSize; 
 
            /// 
            /// Helper function: wraps FontFace information into a FontFaceID struct 
            /// 
            internal FontFaceID(SecurityCriticalData fontFileName,
                                             int fontFaceIndex,
                                             uint scaleX, 
                                             uint scaleY,
                                             ushort glyphRunFlags, 
                                             float emSize) 
            {
                _fontFileName = fontFileName; 
                _faceIndex = fontFaceIndex;
                _scaleX = (int)scaleX;
                _scaleY = (int)scaleY;
                _flags = glyphRunFlags; 
                _renderingEmSize = emSize;
 
                if (_scaleY > _verticalAntialiasingThreashold) 
                {
                    // we are using VAA (vertical anti aliasing, that means 6*5 overscaled 
                    // bitmaps instead of regular 6*1) if font size is big, or if VAA
                    // is forced by user
                    _flags |= (ushort)MilGlyphRun.ForceVAA;
                } 
            }
        } 
 
        private const ushort _fontCacheFlagMask
            = (ushort)MilGlyphRun.Hinting 
            | (ushort)MilGlyphRun.BoldSimulation
            | (ushort)MilGlyphRun.ItalicSimulation
            | (ushort)MilGlyphRun.Sideways
            | (ushort)MilGlyphRun.IsTrueType; 

        private const ushort _faceFlagMask 
            = _fontCacheFlagMask 
            | (ushort)MilGlyphRun.ForceVAA
            | (ushort)MilGlyphRun.VerticalDropOut; 

        private const uint _verticalAntialiasingThreashold = 20 * 0x10000;

        // Matches GLYPH_BASE_CREATE_REQUEST in native code 
        unsafe private struct GLYPH_BASE_CREATE_REQUEST
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok 
            public uint         uFontFaceIndex;     // IN font typeface index
 
            public ushort       usGlyphRunFlags;    // IN GlyphRun flags

            public uint         dScaleX;
            public uint         dScaleY; 

            public float        muSize; 
 
            //
            //  
            // Validation has already been done on the font filename, so we protect it
            // here.
            // 
            // 
            [SecurityCritical]
            public char *       pszFontFileName;    // IN font filename string 
 
            public ushort       usGlyphCount;       // IN number of glyphs in a glyph run
 
            public ushort *     pusGlyphIndices;    // IN glyph indices in a glyph run
                                                    // (caller responsible for alloc/free)
#pragma warning restore 649
        } 

        unsafe private struct GLYPH_GEOMETRY_CREATE_REQUEST 
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok
#pragma warning disable 169  // baseRequest is not used directly, but is required for casting 
            GLYPH_BASE_CREATE_REQUEST baseRequest;

            public float        fBaseLineX;
            public float        fBaseLineY; 

            public float *      pfGlyphPositions; 
#pragma warning restore 169 
#pragma warning restore 649
        } 

        // Matches GLYPH_BITMAP_CREATE_REQUEST in native code
        unsafe private struct GLYPH_BITMAP_CREATE_REQUEST
        { 
#pragma warning disable 649  // These fields might not be initialized from managed code, but that's ok
#pragma warning disable 169  // baseRequest is not used directly, but is required for casting 
            GLYPH_BASE_CREATE_REQUEST baseRequest; 

            public uint         faceHandle;         // IN internal font face identifier 

#pragma warning restore 169
#pragma warning restore 649
        } 

        ///  
        /// Callback entry point for unmanaged code to ask for glyph realizations. 
        /// 
        ///  
        /// Critical - calls critical code
        ///
        [SecurityCritical]
        internal static int CreateGlyphsCallback(IntPtr /*CMilSlaveGlyphCache* */ nativeObject, 
                                                 IntPtr /*GLYPH_BITMAP_CREATE_REQUEST | GLYPH_GEOMETRY_CREATE_REQUEST* */ request,
                                                 ushort       isGeometryRequest) 
        { 
            try
            { 
                FontCacheAccessor fontCacheAccessor = new FontCacheAccessor();

                fontCacheAccessor.CreateGlyphsAtRenderTime(nativeObject, request, isGeometryRequest);
            } 
            catch (Exception e)
            { 
                // 
                // Need to catch all exceptions at this entry point and convert them into a
                // HRESULT that managed code can understand and handle. 
                //
                e.ToString();
                return HRESULT.E_FAIL;
            } 
            return HRESULT.S_OK;
        } 
 
        /// 
        /// Marshals glyph requests 
        /// 
        /// 
        /// Critical - calls critical code
        /// 
        [SecurityCritical]
        private unsafe void CreateGlyphsAtRenderTime(IntPtr /*CMilSlaveGlyphCache* */ nativeObject, 
                                                     IntPtr /*GLYPH_BITMAP_CREATE_REQUEST | GLYPH_GEOMETRY_CREATE_REQUEST* */ request, 
                                                     ushort       isGeometryRequest)
        { 
            GLYPH_BASE_CREATE_REQUEST* pRequest = (GLYPH_BASE_CREATE_REQUEST*)request;

            string fontFileName = new String(pRequest->pszFontFileName);
 
            FontFaceID faceId = new FontFaceID(new SecurityCriticalData(fontFileName),
                                                  (int)pRequest->uFontFaceIndex, 
                                                  pRequest->dScaleX, 
                                                  pRequest->dScaleY,
                                                  pRequest->usGlyphRunFlags, 
                                                  pRequest->muSize);

            ushort[] glyphIndices = new ushort[pRequest->usGlyphCount];
 
            int glyphCount = checked((int)pRequest->usGlyphCount);
 
            // Put Marshal.CopyArray or something in here 
            for (uint n = 0; n < pRequest->usGlyphCount; n++)
            { 
                glyphIndices[n] = pRequest->pusGlyphIndices[n];
            }

            if (isGeometryRequest == 0) 
            {
                GLYPH_BITMAP_CREATE_REQUEST* pRequestAsBitmap = (GLYPH_BITMAP_CREATE_REQUEST*)request; 
 
                // Realize and send bitmaps
                CreateGlyphBitmapsHelper( 
                    nativeObject,
                    faceId,
                    glyphIndices,
                    pRequestAsBitmap->faceHandle 
                    );
            } 
            else 
            {
                GLYPH_GEOMETRY_CREATE_REQUEST* pRequestAsGlyphs = (GLYPH_GEOMETRY_CREATE_REQUEST*)request; 

                // Realize and send geometry
                CreateGlyphGeometryHelper(
                    nativeObject, 
                    faceId,
                    glyphIndices, 
                    pRequestAsGlyphs->pfGlyphPositions, 
                    pRequestAsGlyphs->fBaseLineX,
                    pRequestAsGlyphs->fBaseLineY 
                    );
            }
        }
 
        /// 
        /// Critical - as this accesses critical data and calls critical code 
        ///  
        [SecurityCritical]
        private unsafe void CreateGlyphGeometryHelper( 
            IntPtr nativeGlyphRun,
            FontFaceID faceId,
            ushort[] glyphIndices,
            float *pGlyphPositions, 
            float fBaseLineX,
            float fBaseLineY 
            ) 
        {
            Debug.Assert(glyphIndices.Length > 0); 

            Geometry glyphRunGeometry = BuildGeometry(faceId, glyphIndices, pGlyphPositions, fBaseLineX, fBaseLineY);

            if (glyphRunGeometry.IsEmpty()) 
            {
                return; 
            } 

            // If glyphRunGeometry is non empty, it is of type GeometryGroup, and all the 
            // geometries inside are of type PathGeometry
            GeometryGroup glyphRunGroup = (GeometryGroup)glyphRunGeometry;

            Geometry.PathGeometryData glyphRunPathData = glyphRunGroup.GetAsPathGeometry().GetPathGeometryData(); 

            // Packet layout is: 
            //   MILCMD_GLYPHRUN_SETRENDERGEOMETRY 
            //   MILCMD_PATHGEOMETRY
            //   PathFigure data block (glyphRunPathData.SerializedData) 

            // Allocate sufficient memory
            uint pathGeometrySize = (uint)sizeof(DUCE.MILCMD_PATHGEOMETRY);
            uint dataLength = (uint)glyphRunPathData.SerializedData.Length; 

            uint packetSize = checked(pathGeometrySize + dataLength); 
 
            byte[] packetBlock = new byte[packetSize];
 
            fixed (byte* packet = packetBlock)
            {
                DUCE.MILCMD_PATHGEOMETRY *pathGeometryPacket = (DUCE.MILCMD_PATHGEOMETRY *)(packet);
                pathGeometryPacket->Type = MILCMD.MilCmdPathGeometry; 
                //pathGeometryPacket->Transform = 0;
                pathGeometryPacket->FillRule = glyphRunGroup.FillRule; 
                pathGeometryPacket->FiguresSize = glyphRunPathData.Size; 

                byte* pathData = (byte *)(packet + pathGeometrySize); 
                Marshal.Copy(glyphRunPathData.SerializedData, 0, (IntPtr)pathData, glyphRunPathData.SerializedData.Length);

                // Send packet
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphRun_SetGeometryAtRenderTime( 
                    nativeGlyphRun,
                    (byte *)packet, 
                    packetSize 
                    ));
            } 
        }

        /// 
        /// Obtains geometry for the glyph run. 
        /// 
        /// The geometry returned contains the combined geometry of all glyphs in the glyph run. 
        /// Overlapping contours are merged by performing a Boolean union operation. 
        /// 
        /// Critical - performs unsafe operations 
        /// 
        [SecurityCritical]
        private unsafe Geometry BuildGeometry(
            FontFaceID faceId, 
            ushort[] glyphIndices,
            float *pPositions, 
            float fBaseLineX, 
            float fBaseLineY
            ) 
        {
            GeometryGroup accumulatedGeometry = null;

            Uri fontURI = new Uri(faceId._fontFileName.Value, UriKind.Absolute); 

            bool IsSideways = ((faceId._flags & (UInt16)MilGlyphRun.Sideways)  != 0); 
            bool IsLeftToRight = ((faceId._flags & (UInt16)MilGlyphRun.IsLeftToRight) != 0); 

            // If there are Y positions the array is packed as positions XYXYXY etc, if there 
            // are no Y positions, it's just XXX and Y is assumed to be 0.
            bool HasYPositions = ((faceId._flags & (UInt16)MilGlyphRun.HasYPositions) != 0);

            StyleSimulations style = StyleSimulations.None; 
            if ((faceId._flags & (UInt16)MilGlyphRun.BoldSimulation) != 0)
            { 
                style |= StyleSimulations.BoldSimulation; 
            }
            if ((faceId._flags & (UInt16)MilGlyphRun.ItalicSimulation) != 0) 
            {
                style |= StyleSimulations.ItalicSimulation;
            }
 
            GlyphTypeface glyphTypeface = new GlyphTypeface(fontURI, style, false);
 
            for (int i = 0; i < glyphIndices.Length; i++) 
            {
                ushort glyphIndex = glyphIndices[i]; 

                Geometry glyphGeometry = glyphTypeface.ComputeGlyphOutline(glyphIndex, IsSideways, faceId._renderingEmSize);
                if (glyphGeometry.IsEmpty())
                    continue; 

                // transform glyphGeometry to the glyph origin 
                unsafe { 
                    float xPosition;
                    float yPosition; 
                    if (HasYPositions)
                    {
                        xPosition = ((float*)pPositions)[2*i];
                        yPosition = ((float*)pPositions)[2 * i + 1]; 
                    }
                    else 
                    { 
                        //
                        // If there are no Y positions, the first X position is always assumed to be 0 and is 
                        // ommitted, making the array one element smaller. If there are Y positions, all X
                        // and Y positions are fully specified
                        //
                        xPosition = (i == 0) ? 0 : ((float*)pPositions)[i-1]; 
                        yPosition = 0;
                    } 
                    // 
                    // If this is an RTL glyph run, xPosition will already be negative. We still need to subtract
                    // the AdvanceWidth for the glyph though. For regular bitmap rendering, this happens in 
                    // CGlyphRunMaker::CalculateGlyphPositions()
                    //
                    float xOffset = (xPosition - (float)(IsLeftToRight ? 0 : glyphTypeface.GetAdvanceWidth(glyphIndex))) * faceId._renderingEmSize + fBaseLineX;
                    float yOffset = yPosition * faceId._renderingEmSize + fBaseLineY; 
                    glyphGeometry.Transform = new TranslateTransform(xOffset, yOffset);
                } 
 
                if (accumulatedGeometry == null)
                { 
                    accumulatedGeometry = new GeometryGroup();
                    accumulatedGeometry.FillRule = FillRule.Nonzero;
                }
 
                accumulatedGeometry.Children.Add(glyphGeometry.GetOutlinedPathGeometry(GlyphRun.RelativeFlatteningTolerance,
                                                                                   ToleranceType.Relative)); 
                } 
            // Make sure to always return Geometry.Empty from public methods for empty geometries.
            if (accumulatedGeometry == null || accumulatedGeometry.IsEmpty()) 
                return Geometry.Empty;
            return accumulatedGeometry;
        }
 

        ///  
        /// Critical - as this accesses critical data and calls GetBitmaps which is Critical. 
        /// 
        [SecurityCritical] 
        private unsafe void CreateGlyphBitmapsHelper(
            IntPtr nativeGlyphCache,
            FontFaceID faceId,
            ushort[] glyphIndices, 
            uint faceHandle
            ) 
        { 
            Debug.Assert(glyphIndices.Length > 0);  // Should not pInvoke here when no glyphs are missing
 
            void*[] glyphBitmaps = new void*[glyphIndices.Length];

            GetBitmaps(
                faceId._fontFileName.Value, 
                faceId._faceIndex,
                faceId._scaleX, 
                faceId._scaleY, 
                (ushort)faceId._renderingEmSize,
                (faceId._flags & (uint)MilGlyphRun.ForceVAA) != 0 
                ? (ushort)MS.Internal.FontRasterization.OverscaleMode.OverscaleXandY
                : (ushort)MS.Internal.FontRasterization.OverscaleMode.OverscaleX, //renderingMode
                (ushort)(faceId._flags & _fontCacheFlagMask), //renderingFlags,
                glyphIndices.Length, 
                glyphIndices,
                /*OUT*/ glyphBitmaps 
                ); 

            bool needDropOut = (faceId._flags & (uint)MilGlyphRun.VerticalDropOut) != 0; 

            AddBitmapsToNativeCacheAtRenderTime(nativeGlyphCache,
                                                faceHandle,
                                                glyphBitmaps, 
                                                glyphIndices,
                                                faceId._flags, 
                                                needDropOut); 
        }
 
        /// 
        /// Critical - as this accesses unsafe code blocks.
        /// 
        [SecurityCritical] 
        private unsafe void AddBitmapsToNativeCacheAtRenderTime(IntPtr nativeGlyphCache,
                                                                uint faceHandle, 
                                                                void*[] glyphBitmaps, 
                                                                ushort[] glyphIndices,
                                                                ushort faceFlags, 
                                                                bool needDropOut)
        {
            Debug.Assert(glyphBitmaps != null);
            Debug.Assert(glyphBitmaps.Length != 0); 

            DUCE.MILCMD_GLYPHCACHE_ADDBITMAPS command; 
 
            try
            { 
                command.Type = MILCMD.MilCmdGlyphCacheAddBitmaps;
                command.FontFaceHandle = faceHandle;
                command.FaceFlags = faceFlags;
                command.GlyphCount = checked((UInt16)glyphIndices.Length); 
                command.Handle = DUCE.ResourceHandle.Null;  // Unused - MIL resource handle - bypassing DUCE channels
 
                // Precalculate size of command data buffer 
                // The uint is used up by the MemWriter
                int dataSize = checked(sizeof(uint) + glyphIndices.Length * sizeof(ushort)); 

                // Count the total size of the bitmaps.
                if (!needDropOut)
                { 
                    for (int i = 0; i < glyphIndices.Length; i++)
                    { 
                        int blockSize = GetBitmapTransferSize((GlyphBitmap*)glyphBitmaps[i]); 
                        dataSize = checked(dataSize + blockSize);
                    } 
                }
                else
                {
                    for (int i = 0; i < glyphIndices.Length; i++) 
                    {
                        int blockSize = GetTransformedBitmapTransferSize((GlyphBitmap*)glyphBitmaps[i]); 
                        dataSize = checked(dataSize + blockSize); 
                    }
                } 

                // Talk directly to native GlyphCache object
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_BeginCommandAtRenderTime(
                    nativeGlyphCache, 
                    (byte*)&command,
                    (UInt32)sizeof(DUCE.MILCMD_GLYPHCACHE_ADDBITMAPS), 
                    (UInt32)dataSize 
                    ));
 
            }
            catch (System.OverflowException e)
            {
                // re-throw more readable exception 
                throw new OutOfMemoryException(SR.Get(SRID.TooManyGlyphRuns), e);
            } 
 
            // Write the bitmaps if needed.
            // Bitmaps should go first because of aligning. 
            if (!needDropOut)
            {
                for (int i = 0; i < glyphIndices.Length; i++)
                { 
                    TransferBitmapAtRenderTime(nativeGlyphCache, (GlyphBitmap*)glyphBitmaps[i]);
                } 
            } 
            else
            { 
                for (int i = 0; i < glyphIndices.Length; i++)
                {
                    TransferTransformedBitmapAtRenderTime(nativeGlyphCache, (GlyphBitmap*)glyphBitmaps[i]);
                } 
            }
 
            // Write the glyph indices. 
            fixed (ushort* pData = glyphIndices)
            { 
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime(
                    nativeGlyphCache,
                    (byte*)pData,
                    (uint)(glyphIndices.Length * sizeof(ushort)))); 
            }
 
            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_EndCommandAtRenderTime( 
                    nativeGlyphCache
                    )); 
        }

        /// 
        /// Compose and transfer a piece of MILCMD_GLYPHCACHE_ADDBITMAPS command 
        /// that represents given glyph bitmap.
        ///  
        ///  
        /// Critical - as this accesses unsafe code blocks.
        ///  
        [SecurityCritical]
        private unsafe void TransferBitmapAtRenderTime(IntPtr nativeGlyphCache, GlyphBitmap* pBitmap)
        {
            if (pBitmap == null) 
            {
                TransferStubAtRenderTime(nativeGlyphCache); 
                return; 
            }
 
            DUCE.MILCMD_GLYPHBITMAP bitmap = new DUCE.MILCMD_GLYPHBITMAP();
            bitmap.horOriginX = checked((Int16)(pBitmap->horOriginX));
            bitmap.horOriginY = checked((Int16)(pBitmap->horOriginY));
            bitmap.horAdvance = checked((Int16)(pBitmap->horAdvance)); 
            bitmap.verOriginX = checked((Int16)(pBitmap->verOriginX));
            bitmap.verOriginY = checked((Int16)(pBitmap->verOriginY)); 
            bitmap.width = checked((UInt16)(pBitmap->width)); 
            bitmap.height = checked((UInt16)(pBitmap->height));
            bitmap.stride = checked((UInt16)(pBitmap->stride)); 

            int cbDataSize = (int)bitmap.height * (int)bitmap.stride;

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                nativeGlyphCache,
                (byte*)&bitmap, 
                (uint)sizeof(DUCE.MILCMD_GLYPHBITMAP))); 

            if (cbDataSize != 0) 
            {
                byte* pData = (byte*)pBitmap + sizeof(GlyphBitmap);
                // Write directly to slave GlyphCache
                HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                    nativeGlyphCache,
                    pData, 
                    (uint)cbDataSize)); 
            }
        } 


        /// 
        /// This routine is for seldom circumstances, when 
        /// font cache unabled supply particular glyph bitmap.
        /// When happened so we'll replace glyph with special shape 
        /// (currently empty) 
        /// 
        ///  
        /// Critical - as this accesses unsafe code blocks.
        /// 
        [SecurityCritical]
        private unsafe void TransferStubAtRenderTime(IntPtr nativeGlyphCache) 
        {
            // create empty struct GlyphBitmap in stack frame 
            DUCE.MILCMD_GLYPHBITMAP bitmap = new DUCE.MILCMD_GLYPHBITMAP(); 

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                nativeGlyphCache,
                (byte*)&bitmap,
                (uint)sizeof(DUCE.MILCMD_GLYPHBITMAP)));
        } 

        /// 
        /// Pass the GlyphBitmap to command buffer, along the way 
        /// making horizontal strokes *a little* thicker than given
        /// GlyphBitmap has. 
        ///
        /// This thickening algorythm (also referred to as "virtual
        /// drop out control") is completely heuristic. It was
        /// initially proposed by Beat Stamm (beats). This version 
        /// differs much from the initial. It thickens only
        /// horizontal strokes, increasing stroke width up to 2 virtual 
        /// pixels. Heuristic prohibits thickening if it cause 
        /// the stroke to bleed through pixel boundary, and also if
        /// next stroke is too close to given. 
        /// 
        /// 
        /// Critical - as this accesses unsafe code blocks.
        ///  
        [SecurityCritical]
        private unsafe void TransferTransformedBitmapAtRenderTime(IntPtr slaveGlyphCache, GlyphBitmap* pBitmap) 
        { 
            if (pBitmap == null)
            { 
                TransferStubAtRenderTime(slaveGlyphCache);
                return;
            }
 
            // Vertical drop out needs glyph bitmap (that's ovescaled 5 times by Y axis)
            // to be vertically aligned to physycal pixel grid. 
            // We may need to allocate extra rows above and below 
            // original image.
            int bitmapTop = -pBitmap->horOriginY; 
            int bitmapBottom = bitmapTop + pBitmap->height;
            int pixelTop = bitmapTop >= 0 ? bitmapTop / 5 : -((4 - bitmapTop) / 5);
            int pixelBottom = bitmapBottom >= 0 ? (bitmapBottom + 4) / 5 : -((-bitmapBottom) / 5);
            int rowsAbove = bitmapTop - pixelTop * 5; 
            int rowsBelow = pixelBottom * 5 - bitmapBottom;
            Debug.Assert(rowsAbove >= 0 && rowsAbove < 5); 
            Debug.Assert(rowsBelow >= 0 && rowsBelow < 5); 
            int newSize = checked(
                sizeof(DUCE.MILCMD_GLYPHBITMAP) 
                + (pBitmap->height + rowsBelow + rowsAbove) * pBitmap->stride
                );

            byte* pData = stackalloc byte[newSize]; 
            DUCE.MILCMD_GLYPHBITMAP* pNewBitmap = (DUCE.MILCMD_GLYPHBITMAP*)pData;
 
            // fill bitmap header 
            pNewBitmap->horOriginX = checked((Int16)(pBitmap->horOriginX));
            pNewBitmap->horOriginY = checked((Int16)(pBitmap->horOriginY + rowsAbove)); 
            pNewBitmap->horAdvance = checked((Int16)(pBitmap->horAdvance));
            pNewBitmap->verOriginX = checked((Int16)(pBitmap->verOriginX - rowsAbove));
            pNewBitmap->verOriginY = checked((Int16)(pBitmap->verOriginY));
            pNewBitmap->width = checked((UInt16)(pBitmap->width)); 
            pNewBitmap->height = checked((UInt16)(pBitmap->height + rowsAbove + rowsBelow));
            pNewBitmap->stride = checked((UInt16)(pBitmap->stride)); 
 
            UInt32* pSrc = (UInt32*)((byte*)pBitmap + sizeof(GlyphBitmap));
            UInt32* pDst = (UInt32*)(pData + sizeof(DUCE.MILCMD_GLYPHBITMAP)); 
            int stride32 = pBitmap->stride >> 2;

            // fill added rows above with zeros
            UInt32* pDstAbove = pDst; 
            int sizeAbove = rowsAbove * stride32;
            for (int i = sizeAbove; --i >= 0; ) 
                pDst[i] = 0; 

            // copy bitmap bits 
            UInt32* pDstOrigin = pDstAbove + sizeAbove;
            int sizeOrigin = stride32 * pBitmap->height;
            for (int i = sizeOrigin; --i >= 0; )
                pDstOrigin[i] = pSrc[i]; 

            // fill added rows above with zeros 
            UInt32* pDstBelow = pDstOrigin + sizeOrigin; 
            int sizeBelow = rowsBelow * stride32;
            for (int i = sizeBelow; --i >= 0; ) 
                pDstBelow[i] = 0;

            UInt32* pColon = pDst;
 
            int bandsCount = pixelBottom - pixelTop;
            int colonsCount = (int)((pNewBitmap->width + 31) >> 5); 
            Debug.Assert(colonsCount <= stride32); 

            if (bandsCount == 1) 
            {
                for (int i = 0; i < colonsCount; i++, pColon++)
                {
                    UInt32* p0 = pColon; 
                    UInt32* p1 = p0 + stride32;
                    UInt32* p2 = p1 + stride32; 
                    UInt32* p3 = p2 + stride32; 
                    UInt32* p4 = p3 + stride32;
                    // bleeding up: set the bit if there is "one" 
                    // on next row but not two previous and second next.
                    // The magic code below actually repeats many times
                    // the same formula:
                    // bit |= nextBit & ~next2Bit & ~previousBit & ~previous2Bit 
                    // where some members are removed if we are close to the
                    // edge so some "next" and "previous" are missed. 
 
                    *p0 |= *p1 & ~*p2;
                    *p1 |= ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                    *p3 |= ~*p1 & ~*p2 & *p4;
                    // bleed down: same as bleeding up but Y direction is reversed
                    *p4 |= ~*p2 & *p3; 
                    *p3 |= ~*p1 & *p2 & ~*p4;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4; 
                    *p1 |= *p0 & ~*p2 & ~*p3; 
                }
            } 
            else
            {   // there are two or more bands
                for (int i = 0; i < colonsCount; i++, pColon++)
                { 
                    UInt32* p0 = pColon;
                    UInt32* p1 = p0 + stride32; 
                    UInt32* p2 = p1 + stride32; 
                    UInt32* p3 = p2 + stride32;
                    UInt32* p4 = p3 + stride32; 
                    UInt32* p5 = p4 + stride32;
                    UInt32* p6 = p5 + stride32;

                    // Handle first band 
                    // bleed up
                    *p0 |= *p1 & ~*p2; 
                    *p1 |= ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                    *p3 |= ~*p1 & ~*p2 & *p4 & ~*p5; 
                    // bleed down
                    *p4 |= ~*p2 & *p3 & ~*p5 & ~*p6;
                    *p3 |= ~*p1 & *p2 & ~*p4 & ~*p5;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4; 
                    *p1 |= *p0 & ~*p2 & ~*p3;
 
                    UInt32* q1 = p4; 
                    UInt32* q2 = p3;
 
                    // Handle middle bands
                    for (int b = bandsCount - 2; --b >= 0; )
                    {
                        p0 = q1 + stride32; 
                        p1 = p0 + stride32;
                        p2 = p1 + stride32; 
                        p3 = p2 + stride32; 
                        p4 = p3 + stride32;
                        p5 = p4 + stride32; 
                        p6 = p5 + stride32;
                        // bleed up
                        *p0 |= ~*q2 & ~*q1 & *p1 & ~*p2;
                        *p1 |= ~*q1 & ~*p0 & *p2 & ~*p3; 
                        *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4;
                        *p3 |= ~*p1 & ~*p2 & *p4 & ~*p5; 
                        // bleed down 
                        *p4 |= ~*p2 & *p3 & ~*p5 & ~*p6;
                        *p3 |= ~*p1 & *p2 & ~*p4 & ~*p5; 
                        *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4;
                        *p1 |= ~*q1 & *p0 & ~*p2 & ~*p3;
                        q1 = p4;
                        q2 = p3; 
                    }
 
                    // Handle last band 
                    p0 = q1 + stride32;
                    p1 = p0 + stride32; 
                    p2 = p1 + stride32;
                    p3 = p2 + stride32;
                    p4 = p3 + stride32;
                    // bleed up 
                    *p0 |= ~*q2 & ~*q1 & *p1 & ~*p2;
                    *p1 |= ~*q1 & ~*p0 & *p2 & ~*p3; 
                    *p2 |= ~*p0 & ~*p1 & *p3 & ~*p4; 
                    *p3 |= ~*p1 & ~*p2 & *p4;
                    // bleed down 
                    *p4 |= ~*p2 & *p3;
                    *p3 |= ~*p1 & *p2 & ~*p4;
                    *p2 |= ~*p0 & *p1 & ~*p3 & ~*p4;
                    *p1 |= ~*q1 & *p0 & ~*p2 & ~*p3; 
                }
 
            } 

            HRESULT.Check(UnsafeNativeMethods.MilCoreApi.MilGlyphCache_AppendCommandDataAtRenderTime( 
                slaveGlyphCache,
                (byte*)pData,
                (uint)newSize));
        } 

        ///  
        /// Calculate the size in command buffer, required for transferring 
        /// given bitmap to rendering machine.
        ///  
        /// 
        /// size, in bytes
        /// 
        /// Critical - as this accesses unsafe code blocks. 
        /// 
        [SecurityCritical] 
        private static unsafe int GetBitmapTransferSize(GlyphBitmap* pBitmap) 
        {
            int cbSize = sizeof(DUCE.MILCMD_GLYPHBITMAP); 
            if (pBitmap != null)
            {
                cbSize += pBitmap->height * pBitmap->stride;
            } 

            return cbSize; 
        } 

        /// 
        /// Precalculate the size of MILCMD_GLYPHCACHE_ADDBITMAPS command segment
        /// that will be used by TransferTransformedBitmap
        /// 
        /// given glyph bitmap 
        /// size, in bytes
        ///  
        /// Critical: accepts a pointer and processes it with no validation 
        /// 
        [SecurityCritical] 
        private static unsafe int GetTransformedBitmapTransferSize(GlyphBitmap* pBitmap)
        {
            int cbSize = sizeof(DUCE.MILCMD_GLYPHBITMAP);
            if (pBitmap != null) 
            {
                // Vertical drop out needs glyph bitmap (that's ovescaled 5 times by Y axis) 
                // to be vertically aligned to physycal pixel grid. 
                // We may need to allocate extra rows above and below
                // original image. 
                int bitmapTop = -pBitmap->horOriginY;
                int bitmapBottom = bitmapTop + pBitmap->height;
                int pixelTop = bitmapTop >= 0 ? bitmapTop / 5 : -((4 - bitmapTop) / 5);
                int pixelBottom = bitmapBottom >= 0 ? (bitmapBottom + 4) / 5 : -((-bitmapBottom) / 5); 
                int rowsAbove = bitmapTop - pixelTop * 5;
                int rowsBelow = pixelBottom * 5 - bitmapBottom; 
 
                Debug.Assert(rowsAbove >= 0 && rowsAbove < 5);
                Debug.Assert(rowsBelow >= 0 && rowsBelow < 5); 

                cbSize += (pBitmap->height + rowsBelow + rowsAbove) * pBitmap->stride;
            }
 
            return cbSize;
        } 
 

        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,
            /*OUT*/ 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, 
            IList glyphIndices,
            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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK