GlyphElement.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / FontCache / GlyphElement.cs / 1 / GlyphElement.cs

                            using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security; 
using System.Security.Permissions;
using System.Runtime.CompilerServices; 
using System.Runtime.InteropServices; 
using System.Windows;
 
using MS.Internal;
using MS.Internal.FontFace;
using MS.Utility;
 
using MS.Internal.FontRasterization;
 
using Adobe.CffRasterizer; 

using System.Windows.Media.Composition; 

using MS.Internal.PresentationCore;

// Since we disable PreSharp warnings in this file, we first need to disable warnings about unknown message numbers and unknown pragmas. 
#pragma warning disable 1634, 1691
 
namespace MS.Internal.FontCache 
{
    ///  
    /// Glyph element class.
    /// Layout is:
    /// glyph block structure | file name string
    ///  
    [FriendAccessAllowed]
    internal abstract class BaseGlyphElement : IFontCacheElement, IDisposable 
    { 
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct GlyphBlock 
        {
            internal int faceIndex;
            internal int cbFileNameLength;
            internal ushort renderingFlags; 
            internal ushort baseglyphIndex;
 
 
            /// 
            /// Critical - as this accesses unsafe code blocks 
            /// TreatAsSafe - as this does not return any unsafe pointers and is used to compare two blocks
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            internal unsafe bool Equal(GlyphBlock* rhs) 
            {
                Invariant.Assert(rhs != null); 
                return 
                    this.faceIndex == rhs->faceIndex &&
                    this.cbFileNameLength == rhs->cbFileNameLength && 
                    this.baseglyphIndex == rhs->baseglyphIndex &&
                    this.renderingFlags == rhs->renderingFlags;
            }
        } 

        protected BaseGlyphElement(int glyphsPerBlock) 
        { 
            _glyphsPerBlock = glyphsPerBlock;
            Reset(); 
            Debug.Assert(_key.baseglyphIndex != GetBaseGlyph(_key.baseglyphIndex));
        }

        ///  
        /// Critical - as this calls GetUriString
        /// TreatAsSafe - as this does not uses the result only to compute the string length. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected BaseGlyphElement(int glyphsPerBlock, int faceIndex, FontSource fontSource, ushort renderingFlags) 
            : this(glyphsPerBlock)
        {
            _fontSource = fontSource;
            _key.renderingFlags = renderingFlags; 
            _key.faceIndex = faceIndex;
            unsafe { _key.cbFileNameLength = FontSource.GetUriString().Length * sizeof(char); } 
        } 

        ///  
        /// Critical as this calls _fontStream.Close(), which is a file operation.
        /// TreatAsSafe as it only releases the file handle.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public void Dispose()
        { 
            if (_rasterizer != null) 
            {
                _rasterizer.Dispose(); 
                _rasterizer = null;
            }

            if (_fontStream != null) 
            {
                _fontStream.Close(); 
                _fontStream = null; 
            }
        } 

        /// 
        /// Critical - as this accesses _glyphdata which is a pointer
        /// TreatAsSafe: This does not expose the data and simply resets the stream 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void Reset() 
        {
            unsafe { _glyphData = null; } 
            _cacher = null;
            _key.baseglyphIndex = 1;
        }
 
        internal FontSource FontSource
        { 
            get 
            {
                return _fontSource; 
            }
        }

        internal int FaceIndex 
        {
            get 
            { 
                return _key.faceIndex;
            } 
        }

        internal RenderingFlags RenderingFlags
        { 
            get
            { 
                return (RenderingFlags)_key.renderingFlags; 
            }
        } 

        internal bool IsTrueType
        {
            get 
            {
                return (_key.renderingFlags & (ushort)MIL_GLYPHRUN_FLAGS.MilGlyphRunIsTrueType) != 0; 
            } 
        }
 
        /// 
        /// Prevent JIT from inlining this method, so that PresentationCFFRasterizer.dll and PresentationCFFRasterizerNative.dll are loaded on demand.
        /// 
        ///  
        /// Critical - This method calls critical code (OTFRasterizer())
        /// Safe     - This method doesn't expose any ciritical information. 
        ///  
        [MethodImpl(MethodImplOptions.NoInlining)]
        [SecurityCritical, SecurityTreatAsSafe] 
        protected void CreateOtfRasterizer()
        {
            _rasterizer = new OTFRasterizer();
        } 
        /// 
        /// Critical - as this accesses unsafe code blocks and allocates an object that can hold unmanaged code and returns it 
        ///  
        [SecurityCritical]
        protected unsafe void* Allocate(int size) 
        {
            int newOffset = _cacher.Alloc(size);
            return _cacher[newOffset];
        } 

        ///  
        ///     Critical: This code acceses unsafe code and is used to allocate memory. It returns a pointer 
        /// 
        [SecurityCritical] 
        protected unsafe void* AllocateNoThrow(int size)
        {
            try
            { 
                return Allocate(size);
            } 
            catch (FontCacheFullException) 
            {
                return null; 
            }
        }

        ///  
        /// Obtains a base glyph index for this cache element
        ///  
        /// The base glyph index 
        internal ushort GetBaseGlyph()
        { 
            return _key.baseglyphIndex;
        }

        internal void SetBaseGlyph(ushort glyphIndex) 
        {
            Debug.Assert(glyphIndex == GetBaseGlyph(glyphIndex)); 
            _key.baseglyphIndex = glyphIndex; 
        }
 
        internal ushort GetBaseGlyph(ushort glyphIndex)
        {
            return (ushort)(glyphIndex - glyphIndex % _glyphsPerBlock);
        } 

        ///  
        /// Critical - as this gives out glyphstream 
        /// 
        [SecurityCritical] 
        protected unsafe int* GlyphEntry(ushort glyphIndex)
        {
            Invariant.Assert(GetBaseGlyph(glyphIndex) == _key.baseglyphIndex);
            return _glyphData + (glyphIndex - _key.baseglyphIndex); 
        }
 
        ///  
        /// Returns whether a given glyph is cached
        ///  
        /// Glyph index
        /// true if the glyph is cached, false otherwise
        /// 
        /// Critical - as this accesses unsafe code blocks 
        /// TreatAsSafe - as this does not return the stream
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal bool IsGlyphCached(ushort glyphIndex)
        { 
            unsafe
            {
                return *GlyphEntry(glyphIndex) != Util.nullOffset;
            } 
        }
        ///  
        /// Critical - as this accesses unsafe code blocks and returns a glyph pointer 
        /// 
        [SecurityCritical] 
        internal unsafe void* GetGlyph(ushort glyphIndex)
        {
            Invariant.Assert(IsGlyphCached(glyphIndex));
            int offset = *GlyphEntry(glyphIndex); 
            return _cacher[offset];
        } 
 
        /// 
        /// Critical - as this accesses unsafe code blocks and sets data from a pointer 
        /// 
        [SecurityCritical]
        protected unsafe void SetGlyph(ushort glyphIndex, void* data)
        { 
            *GlyphEntry(glyphIndex) = _cacher[(byte*)data];
            Debug.Assert(IsGlyphCached(glyphIndex)); 
 
        }
 

        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: The calls to probe is bounds checked 
        ///     and the usage of elementcacher and checkedpointer are tracked.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        protected void InitGlyphData(CheckedPointer p, ElementCacher cacher)
        { 
            unsafe
            {
                _glyphData = (int*)p.Probe(0, _glyphsPerBlock * sizeof(int));
                Util.FillMemory(_glyphData, _glyphsPerBlock * sizeof(int), Util.nullOffset); 
            }
            _cacher = cacher; 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: The calls to probe is bounds checked
        ///     and the usage of elementcacher and checkedpointer are tracked.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected void SetGlyphData(CheckedPointer p, ElementCacher cacher) 
        { 
            unsafe { _glyphData = (int*)p.Probe(0, _glyphsPerBlock * sizeof(int)); }
            _cacher = cacher; 
        }

        /// 
        /// Critical - as this gives out glyph data in the form of a pointer 
        /// 
        internal unsafe void* GlyphData 
        { 
            [SecurityCritical]
            get 
            {
                return _glyphData;
            }
        } 

        ///  
        /// Adds glyph to the cache 
        /// 
        /// Index of the glyph 
        /// Whether the glyph index was valid for this font.
        /// 
        /// Critical - as this results in the rasterizer accessing font stream.
        /// TreatAsSafe - as this results in obtaining glyph data that the client is supposed to see anyway. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal abstract bool AddGlyph(ushort glyphIndex); 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: Probe is bounds checked and validates pointer.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public virtual bool Match(CheckedPointer p)
        { 
            unsafe 
            {
                GlyphBlock* rhs = (GlyphBlock*)p.Probe(0, sizeof(GlyphBlock)); 
                if (!_key.Equal(rhs))
                    return false;
                return Util.StringEqualIgnoreCase(p + sizeof(GlyphBlock), FontSource.GetUriString());
            } 
        }
 
        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///  
        [SecurityCritical]
        public virtual void RetrieveKey(CheckedPointer m)
        {
            unsafe 
            {
                _key = *(GlyphBlock*)m.Probe(0, sizeof(GlyphBlock)); 
 
                // Validate the base glyph index now so that malformed miss reports
                // don't trip Invarient.Assert() later when we try to construct the element. 
                if (GetBaseGlyph(_key.baseglyphIndex) != _key.baseglyphIndex)
                    throw new ArgumentOutOfRangeException();

                // As the name size could come from arbitrary code 
                // sending miss reports to the font cache server,
                // we must validate it so that Util.StringCopy() doesn't 
                // call Invariant::Assert() if nameSize is invalid. 
                if ((_key.cbFileNameLength < 0) || ((_key.cbFileNameLength % 2) != 0))
                    throw new ArgumentOutOfRangeException(); 

                string fileName = Util.StringCopyFromCheckedPointer(m + sizeof(GlyphBlock), _key.cbFileNameLength);
                _fontSource = new FontSource(new Uri(fileName, UriKind.Absolute), false);
            } 
        }
 
 
        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks 
        ///     TreatAsSafe: Probe is type and bounds checked and this functionality is safe to expose
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void StoreKeyInternal(CheckedPointer d, out int realSize) 
        {
            realSize = InternalGetSize(); 
            unsafe 
            {
                GlyphBlock* glyphBlock = (GlyphBlock*)d.Probe(0, sizeof(GlyphBlock)); 
                *glyphBlock = _key;
                Util.StringCopyToCheckedPointer(d + sizeof(GlyphBlock), FontSource.GetUriString());
            }
        } 

        public virtual int Size 
        { 
            get
            { 
                return InternalGetSize();
            }
        }
 
        public virtual bool IsAppSpecific
        { 
            get 
            {
                return _fontSource.IsAppSpecific; 
            }
        }

        private int InternalGetSize() 
        {
            unsafe { return sizeof(GlyphBlock) + _key.cbFileNameLength; } 
        } 

        ///  
        ///     Critical: This code has unsafe code blocks which call into HasMemory.
        ///     TreatAsSafe: This code is safe to call , since the _key variable is always
        ///     pointing to a valid object and passing it to HashMemory which accepts a void pointer
        ///     is safe. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override int GetHashCode() 
        {
            int hash = 0; 
            unsafe
            {
                fixed (GlyphBlock* k = &_key)
                { 
                    hash = HashFn.HashMemory(k, sizeof(GlyphBlock), hash);
                } 
            } 
            hash = HashFn.HashMultiply(hash) + FontSource.GetHashCode();
            return hash; 
        }

        public abstract void GetData(CheckedPointer p, ElementCacher cacher);
        public abstract void AddToCache(CheckedPointer p, ElementCacher cacher); 
        public abstract int Type { get;}
        public abstract void StoreKey(CheckedPointer d, out int realSize); 
 
        /// 
        /// Cached TrueType rasterizer instance 
        /// 
        protected IFontRasterizer _rasterizer;

        ///  
        /// Critical - as this gives out UnmanagedMemoryStream content which is from a file.
        ///  
        [SecurityCritical] 
        protected UnmanagedMemoryStream _fontStream;
 
        /// 
        /// The total number of glyphs in the font
        /// 
        protected ushort _numberOfGlyphs; 

        private int _glyphsPerBlock; 
        ///  
        /// Critical - as this gives out glyph data in the form of a pointer
        ///  
        [SecurityCritical]
        private unsafe int* _glyphData;  // points to bitmap array in the cache
        private ElementCacher _cacher;
        private FontSource _fontSource; 
        private GlyphBlock _key;
    } 
 
    /// 
    /// This structure represents a black and white glyph bitmap. 
    /// In font cache the structure is immediately followed by height*stride bytes of pixel data.
    /// Empty bitmaps have zero height.
    /// 
    [StructLayout(LayoutKind.Sequential, Pack = 1)] 
    internal unsafe struct GlyphBitmap
    { 
        internal int horOriginX; // horizontal X origin of glyph bitmap 
        internal int horOriginY; // horizontal Y origin of glyph bitmap
        internal int horAdvance; // hinted advance width 
        internal int verOriginX; // vertical X origin of glyph bitmap
        internal int verOriginY; // vertical Y origin of glyph bitmap
        internal int verAdvance; // hinted advance height
        internal int width;      // bitmap width in pixels 
        internal int height;     // bitmap height in pixels
        internal int stride;     // number of bytes to store one pixel row 
    } 

    ///  
    /// Glyph bitmap element class.
    /// Represents a block of glyph bitmaps
    /// Layout is:
    /// base glyph block | bitmap block | table of blockSize pointers to glyph data 
    /// 
    [FriendAccessAllowed] 
    internal sealed class GlyphBitmapElement : BaseGlyphElement 
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)] 
        internal unsafe struct BitmapBlock
        {
            internal int a00;
            internal int a01; 
            internal int a10;
            internal int a11; 
 
            internal ushort pointSize;
            internal ushort renderingMode; 
            /// 
            /// Critical - as this accesses unsafe code blocks
            /// TreatAsSafe - as this does not return unsafe information but is used to compare blocks
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            internal bool Equal(BitmapBlock* rhs) 
            { 
                Invariant.Assert(rhs != null);
                return 
                    this.a00 == rhs->a00 &&
                    this.a01 == rhs->a01 &&
                    this.a10 == rhs->a10 &&
                    this.a11 == rhs->a11 && 
                    this.pointSize == rhs->pointSize &&
                    this.renderingMode == rhs->renderingMode; 
            } 
        }
 
        /// 
        /// Critical -  Calls into the critical RetrieveKey method.
        /// 
        [SecurityCritical] 
        internal GlyphBitmapElement(CheckedPointer key)
            : base(BitmapsPerBlock) 
        { 
            RetrieveKey(key);
        } 

        internal GlyphBitmapElement(
            int faceIndex,
            int a00, 
            int a01,
            int a10, 
            int a11, 
            ushort pointSize,
            ushort renderingMode, 
            ushort renderingFlags,
            FontSource fontSource
            )
            : base(BitmapsPerBlock, faceIndex, fontSource, renderingFlags) 
        {
            _bitmapKey.a00 = a00; 
            _bitmapKey.a01 = a01; 
            _bitmapKey.a10 = a10;
            _bitmapKey.a11 = a11; 
            _bitmapKey.pointSize = pointSize;
            _bitmapKey.renderingMode = renderingMode;
        }
 
        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks 
        ///     TreatAsSafe: The call to probe is checked for boundaries and pointer validity. 
        ///     This code is safe to call.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        public override void StoreKey(CheckedPointer d, out int realSize)
        {
            Debug.Assert(!FontSource.IsAppSpecific); 

            int baseSize; 
            StoreKeyInternal(d, out baseSize); 
            baseSize = Util.Align4(baseSize);
 
            unsafe
            {
                realSize = baseSize + sizeof(BitmapBlock);
                void* dst = d.Probe(baseSize, sizeof(BitmapBlock)); 
                *(BitmapBlock*)dst = _bitmapKey;
            } 
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        /// 
        [SecurityCritical]
        public override void RetrieveKey(CheckedPointer m) 
        {
            base.RetrieveKey(m); 
            int baseSize = Util.Align4(base.Size); 
            unsafe
            { 
                BitmapBlock* s = (BitmapBlock*)m.Probe(baseSize, sizeof(BitmapBlock));
                _bitmapKey = *s;
            }
        } 
        /// 
        ///     Critical: This code has unsafe code blocks It calls into HasMemory 
        ///     TreatAsSafe: This function is safe to call 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override int GetHashCode()
        {
            int hash = base.GetHashCode();
            unsafe 
            {
                fixed (BitmapBlock* k = &_bitmapKey) 
                { 
                    hash = HashFn.HashMemory(k, sizeof(BitmapBlock), hash);
                } 
            }
            return HashFn.HashScramble(hash);
        }
 
        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks 
        ///     TreatAsSafe: CheckedPointer construction is tracked and probe checks for invalid conditions 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override bool Match(CheckedPointer p)
        {
            if (!base.Match(p))
                return false; 
            unsafe
            { 
                BitmapBlock* b = (BitmapBlock*)p.Probe(Util.Align4(base.Size), sizeof(BitmapBlock)); 
                return _bitmapKey.Equal(b);
            } 
        }

        public override void GetData(CheckedPointer p, ElementCacher cacher)
        { 
            unsafe { SetGlyphData(p + (Util.Align4(base.Size) + sizeof(BitmapBlock)), cacher); }
        } 
 
        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks 
        ///     TreatAsSafe: Checked Pointer and ElementCacher are safe to work with. Construction is
        ///     tracked for checkedpointer
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override void AddToCache(CheckedPointer p, ElementCacher cacher)
        { 
            int baseSize; 
            StoreKeyInternal(p, out baseSize);
            baseSize = Util.Align4(baseSize); 

            unsafe
            {
                BitmapBlock* b = (BitmapBlock*)p.Probe(baseSize, sizeof(BitmapBlock) + BitmapsPerBlock * sizeof(int)); 
                *b = _bitmapKey;
                InitGlyphData(p + (baseSize + sizeof(BitmapBlock)), cacher); 
            } 
        }
 
        public override int Size
        {
            get
            { 
                unsafe { return Util.Align4(base.Size) + sizeof(BitmapBlock) + BitmapsPerBlock * sizeof(int); }
            } 
        } 

        public override int Type 
        {
            get
            {
                return 1; 
            }
        } 
 
        /// 
        ///     Critical: This code calls into unsafe code blocks 
        ///     TreatAsSafe: This code allocates and returns an IntPtr that points to a bitmap.
        ///     The IntPtr will fail to support any unsafe operations.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private IntPtr AllocateBitmap(int size)
        { 
            unsafe 
            {
                // Reserve space to copy the bitmap header. 
                byte* buffer = (byte*)AllocateNoThrow(sizeof(GlyphBitmap) + size);
                if (buffer == null)
                    return IntPtr.Zero;
 
                // Pointer the rasterizer to the bitmap storage.
                return (IntPtr)(buffer + sizeof(GlyphBitmap)); 
            } 
        }
 
        //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647
        /// 
        /// Critical - as this results in the rasterizer accessing font stream.
        /// TreatAsSafe - as this results in obtaining glyph bitmaps that the client is supposed to see anyway. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override bool AddGlyph(ushort glyphIndex) 
        {
            try 
            {
                if (_rasterizer == null)
                {
                    if (IsTrueType) 
                        _rasterizer = new TrueTypeRasterizer();
                    else 
                        CreateOtfRasterizer(); 

                    _fontStream = FontSource.GetUnmanagedStream(); 
                    _numberOfGlyphs = _rasterizer.NewFont(_fontStream, FontSource.Uri, FaceIndex);
                    MS.Internal.FontRasterization.Transform tform = new MS.Internal.FontRasterization.Transform();
                    tform.a00 = _bitmapKey.a00;
                    tform.a01 = _bitmapKey.a01; 
                    tform.a10 = _bitmapKey.a10;
                    tform.a11 = _bitmapKey.a11; 
                    _rasterizer.NewTransform( 
                        _bitmapKey.pointSize,
                        tform, 
                        (OverscaleMode)_bitmapKey.renderingMode,
                        RenderingFlags);
                }
                if (glyphIndex >= _numberOfGlyphs) 
                    return false;
 
                MS.Internal.FontRasterization.GlyphBitmap glyphBitmap; 
                GlyphMetrics glyphMetrics;
                try 
                {
                    _rasterizer.NewGlyph(glyphIndex);
                    _rasterizer.GetBitmap(
                        AllocateBitmap,     // allocation delegate 
                        IntPtr.Zero,        // current buffer
                        -1,                 // sentinel value that forces the rasterizer to allocate memory even for empty glyphs 
                        // we use it to make sure glyph header is allocated 
                        out glyphBitmap,
                        out glyphMetrics 
                        );

                    // Check whether glyph bitmap coordinates overflow the 16 bit range that GlyphCache.cs relies on.
                    // Windows Client Task 50200 tracks a more complete solution to this issue that will ensure rasterizers 
                    // can display extremely large bitmaps without truncation.
                    if ((short)glyphMetrics.horizontalOrigin.x != glyphMetrics.horizontalOrigin.x || 
                        (short)glyphMetrics.horizontalOrigin.y != glyphMetrics.horizontalOrigin.y || 
                        (short)glyphMetrics.horizontalAdvance != glyphMetrics.horizontalAdvance ||
                        (short)glyphMetrics.verticalOrigin.x != glyphMetrics.verticalOrigin.x || 
                        (short)glyphMetrics.verticalOrigin.y != glyphMetrics.verticalOrigin.y ||
                        (short)glyphMetrics.verticalAdvance != glyphMetrics.verticalAdvance ||
                        (ushort)glyphMetrics.width != glyphMetrics.width ||
                        (ushort)glyphMetrics.height != glyphMetrics.height || 
                        (ushort)glyphBitmap.stride != glyphBitmap.stride
                        ) 
                    { 
                        throw new FileFormatException(FontSource.Uri);
                    } 
                }
                catch (FileFormatException)
                {
                    unsafe 
                    {
                        // Create empty bitmap with zero metrics for malformed glyph programs. 
                        GlyphBitmap* gb = (GlyphBitmap*)Allocate(sizeof(GlyphBitmap)); 

                        // Cache memory is zero initialized by default. 
                        Debug.Assert(gb->horOriginX == 0);
                        Debug.Assert(gb->height == 0);

                        SetGlyph(glyphIndex, gb); 
                        return true;
                    } 
                } 
                catch (OutOfMemoryException e)
                { 
                    object delegateError = e.Data["GetMemoryDelegateError"];
                    // In case the exception was raised due to the delegate failure,
                    // throw FontCacheFullException so that we have a chance to renew the cache and retry the request.
                    if (delegateError != null && (bool)delegateError) 
                        throw new FontCacheFullException();
 
                    throw; 
                }
 
                // Glyph rendering code requires stride to be a multiple of 4,
                // make sure glyph rasterizers do the same.

                Debug.Assert((glyphBitmap.stride & 3) == 0); 

                unsafe 
                { 
                    GlyphBitmap* gd = (GlyphBitmap*)((byte*)glyphBitmap.pixels - sizeof(GlyphBitmap));
 
                    gd->horOriginX = glyphMetrics.horizontalOrigin.x;
                    gd->horOriginY = glyphMetrics.horizontalOrigin.y;
                    gd->horAdvance = glyphMetrics.horizontalAdvance;
                    gd->verOriginX = glyphMetrics.verticalOrigin.x; 
                    gd->verOriginY = glyphMetrics.verticalOrigin.y;
                    gd->verAdvance = glyphMetrics.verticalAdvance; 
 
                    gd->stride = glyphBitmap.stride;
                    gd->width = glyphMetrics.width; 
                    gd->height = glyphMetrics.height;

                    SetGlyph(glyphIndex, gd);
                } 
                return true;
            } 
            catch (SEHException e) 
            {
                throw Util.ConvertInPageException(FontSource, e); 
            }
        }

        private BitmapBlock _bitmapKey; 

        private const int BitmapsPerBlock = 128; 
    }; 

    ///  
    /// Glyph path element class.
    /// Represents a block of glyph outlines
    /// Layout is:
    /// glyph block structure | file name string | usEmResolution | table of blockSize pointers to glyph data 
    /// 
    [FriendAccessAllowed] 
    internal sealed class GlyphPathElement : BaseGlyphElement 
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1)] 
        private unsafe struct OutlineBlock
        {
            internal ushort designEmHeight;
        } 

        ///  
        /// Outline data is prefixed by a header containing three integers. 
        ///
 

        private static readonly int GlyphOutlineHeaderSize = 3 * sizeof(int);

        ///  
        /// Create a GlyphPathElement for a specific font face
        ///  
        internal GlyphPathElement(int faceIndex, FontSource fontSource, ushort renderingFlags, ushort designEmHeight) 
            : base(OutlinesPerBlock, faceIndex, fontSource, renderingFlags)
        { 
            _outlineKey.designEmHeight = designEmHeight;
        }

        ///  
        /// Critical -  Calls into the critical RetrieveKey method.
        ///  
        [SecurityCritical] 
        internal GlyphPathElement(CheckedPointer key)
            : base(OutlinesPerBlock) 
        {
            RetrieveKey(key);
        }
 
        public override int GetHashCode()
        { 
            int hash = base.GetHashCode(); 
            return HashFn.HashScramble(hash);
        } 

        public override void GetData(CheckedPointer p, ElementCacher cacher)
        {
            unsafe 
            {
                SetGlyphData( 
                    p + (Util.Align4(base.Size) + Util.Align4(sizeof(OutlineBlock))), 
                    cacher);
            } 
        }


        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        ///     TreatAsSafe: ElementCacher and Checkedpointer are safe to work with 
        ///     Also adding this to cache is a safe operation 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public override void AddToCache(CheckedPointer p, ElementCacher cacher)
        {
            int baseSize;
            StoreKeyInternal(p, out baseSize); 
            baseSize = Util.Align4(baseSize);
 
            unsafe 
            {
                OutlineBlock* b = (OutlineBlock*)p.Probe(baseSize, Util.Align4(sizeof(OutlineBlock)) + OutlinesPerBlock * sizeof(int)); 
                *b = _outlineKey;
                InitGlyphData(p + (baseSize + Util.Align4(sizeof(OutlineBlock))), cacher);
            }
        } 

        ///  
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks 
        ///     TreatAsSafe: CheckedPointer is safe to work with. Probe does bounds checking and
        ///     pointer validation. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public override void StoreKey(CheckedPointer d, out int realSize)
        { 
            Debug.Assert(!FontSource.IsAppSpecific);
 
            int baseSize; 
            StoreKeyInternal(d, out baseSize);
            baseSize = Util.Align4(baseSize); 

            unsafe
            {
                realSize = baseSize + sizeof(OutlineBlock); 
                void* dst = d.Probe(baseSize, sizeof(OutlineBlock));
                *(OutlineBlock*)dst = _outlineKey; 
            } 
        }
 
        /// 
        ///     Critical: Calls into probe which is critical and also has unsafe code blocks
        /// 
        [SecurityCritical] 
        public override void RetrieveKey(CheckedPointer m)
        { 
            base.RetrieveKey(m); 
            int baseSize = Util.Align4(base.Size);
            unsafe 
            {
                OutlineBlock* s = (OutlineBlock*)m.Probe(baseSize, sizeof(OutlineBlock));
                _outlineKey = *s;
            } 
        }
 
        public override int Size 
        {
            get 
            {
                unsafe { return Util.Align4(base.Size) + Util.Align4(sizeof(OutlineBlock)) + OutlinesPerBlock * sizeof(int); }
            }
        } 

        public override int Type 
        { 
            get
            { 
                return 4;
            }
        }
 
        /// 
        ///     Critical: Allocates memory and calls into unsafe code. This code is also unsafe 
        ///     TreatAsSafe: This call returns an IntPtr which is safe to expose because if 
        ///     you try to do anything with it that is unsafe it will throw an exception
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private IntPtr AllocateOutline(int size)
        {
            unsafe 
            {
                // Allocate room for vertical origin, length and the outline itself. 
                byte* data = (byte*)AllocateNoThrow(GlyphOutlineHeaderSize + size); 
                if (data == null)
                    return IntPtr.Zero; 
                return (IntPtr)(data + GlyphOutlineHeaderSize);
            }
        }
 
        /// 
        /// Critical - as this results in the rasterizer accessing font stream. 
        /// TreatAsSafe - as this results in obtaining glyph outline that the client is supposed to see anyway. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override bool AddGlyph(ushort glyphIndex)
        {
            try
            { 
                if (_rasterizer == null)
                { 
                    if (IsTrueType) 
                        _rasterizer = new TrueTypeRasterizer();
                    else 
                        CreateOtfRasterizer();

                    _fontStream = FontSource.GetUnmanagedStream();
                    _numberOfGlyphs = _rasterizer.NewFont(_fontStream, FontSource.Uri, FaceIndex); 

                    // 
 

                    if (!IsTrueType) 
                    {
                        MS.Internal.FontRasterization.Transform tform = new MS.Internal.FontRasterization.Transform();
                        tform.a01 = tform.a10 = 0;
                        tform.a00 = tform.a11 = _outlineKey.designEmHeight * 0x10000; 

                        _rasterizer.NewTransform( 
                            12, 
                            tform,
                            OverscaleMode.None, 
                            RenderingFlags);
                    }
                    else
                    { 
                        unsafe { _pathAllocator = new TrueTypeRasterizer.Allocator(Allocate); }
                    } 
                } 
                if (glyphIndex >= _numberOfGlyphs)
                    return false; 

                if (IsGlyphCached(glyphIndex))
                {
                    // another thread already rasterized the glyph 
                    // so we can skip adding it
                    return true; 
                } 

                if (!IsTrueType) 
                {
                    _rasterizer.NewGlyph(glyphIndex);
                    GlyphMetrics glyphMetrics;
                    GlyphOutline glyphOutline; 
                    try
                    { 
                        _rasterizer.GetOutline( 
                            AllocateOutline,    // allocation delegate
                            IntPtr.Zero,        // current buffer 
                            -1,                 // sentinel value that forces the rasterizer to allocate memory even for empty glyphs
                            // we use it to make sure glyph header is allocated
                            out glyphOutline,
                            out glyphMetrics 
                            );
                    } 
                    catch (OutOfMemoryException e) 
                    {
                        object delegateError = e.Data["GetMemoryDelegateError"]; 
                        // In case the exception was raised due to the delegate failure,
                        // throw FontCacheFullException so that we have a chance to renew the cache and retry the request.
                        if (delegateError != null && (bool)delegateError)
                            throw new FontCacheFullException(); 

                        throw; 
                    } 

                    unsafe 
                    {
                        int* p = (int*)((byte*)glyphOutline.outline - GlyphOutlineHeaderSize);
                        p[0] = glyphMetrics.verticalOrigin.x;
                        p[1] = glyphMetrics.verticalOrigin.y; 
                        p[2] = glyphOutline.length;
 
                        SetGlyph(glyphIndex, p); 
                    }
                } 
                else
                {
                    unsafe
                    { 
                        GlyphPathData* gpd = ((TrueTypeRasterizer)_rasterizer).GetPath(_pathAllocator, RenderingFlags, glyphIndex);
                        SetGlyph(glyphIndex, gpd); 
                    } 
                }
                return true; 
            }
            catch (SEHException e)
            {
                throw Util.ConvertInPageException(FontSource, e); 
            }
        } 
 
        private TrueTypeRasterizer.Allocator _pathAllocator;
 
        private OutlineBlock _outlineKey;

        private const int OutlinesPerBlock = 128;
    }; 

    ///  
    /// Wrapper class for glyph cache access. Getting glyph bitmaps and outlines is more complex than 
    /// using other font cache elements because data for different glyphs can come from different caches.
    /// The caller should GC.KeepAlive an instance of FontCacheAccessor class while glyph data is being used, 
    /// otherwise there is risk of cache being garbage collected while bitmap data is used.
    /// 
    internal class FontCacheAccessor
    { 
        private List _nativeCaches;
 
        internal FontCacheAccessor() 
        {
            _nativeCaches = new List(2); 
        }

        /// 
        /// Critical - as this calls GetGlyphs() which is Critical and return font information 
        ///            via glyphBitmaps parameter.
        ///  
        [SecurityCritical] 
        internal unsafe void GetBitmaps(
            string fontFileName, 
            int faceIndex,
            int scaleX,
            int scaleY,
            ushort pointSize, 
            ushort renderingMode,
            ushort renderingFlags, 
            int glyphCount, 
            ushort[] glyphIndices,
            void*[] glyphBitmaps 
            )
        {
            try
            { 
                using (GlyphBitmapElement elem = new GlyphBitmapElement(
                    faceIndex, 
                    scaleX, 
                    0,
                    0, 
                    scaleY,
                    pointSize,
                    renderingMode,
                    renderingFlags, 
                    // We set skipDemand to true here because we should have validated
                    // whether the caller can access this font previously. 
                    // At this point we don't have context about the caller any more. 
                    new FontSource(new Uri(fontFileName, UriKind.Absolute), true)
                    )) 
                {
                    GetGlyphs(
                        elem,
                        new PartialList(glyphIndices, 0, glyphCount), 
                        glyphBitmaps
                        ); 
                } 
            }
            // Disable PreSharp warning about empty catch bodies, please see comments below. 
#pragma warning disable 6502
            // Don't fail because of malformed fonts, use empty glyph bitmap stubs.
            catch (FileFormatException)
            { } 
            // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs.
            catch (IOException) 
            { } 
            // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs.
            catch (UnauthorizedAccessException) 
            { }
            // Don't fail because of inaccessible fonts, use empty glyph bitmap stubs.
            catch (System.Net.WebException)
            { } 
#pragma warning restore 6502
            catch (ArgumentOutOfRangeException e) 
            { 
                if (e.ParamName != "transform")
                    throw; 
                // Don't fail because of invalid transformations, because they can frequently happen in the process of animating text.
            }
        }
 
        /// 
        /// Critical - as this calls the critical function GetServerCache() and exposes 
        ///            font cache data via glyphsArray parameter. 
        /// 
        [SecurityCritical] 
        internal unsafe void GetGlyphs(
            BaseGlyphElement element,
            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