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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InvokerUtil.cs
- MatrixTransform.cs
- CalendarItem.cs
- CompilerParameters.cs
- FontCollection.cs
- PropertyGridView.cs
- DescriptionAttribute.cs
- StructuredTypeInfo.cs
- CodePageUtils.cs
- FacetEnabledSchemaElement.cs
- SignatureToken.cs
- TextSelectionHighlightLayer.cs
- SchemaImporter.cs
- ReflectEventDescriptor.cs
- HttpModuleAction.cs
- TextElementEditingBehaviorAttribute.cs
- PrivilegedConfigurationManager.cs
- HMACRIPEMD160.cs
- XmlExpressionDumper.cs
- CollectionChangeEventArgs.cs
- ImportFileRequest.cs
- CompleteWizardStep.cs
- DifferencingCollection.cs
- ValidationErrorEventArgs.cs
- QilValidationVisitor.cs
- XmlMembersMapping.cs
- MenuDesigner.cs
- SchemaObjectWriter.cs
- OleDbFactory.cs
- ResourceSet.cs
- SiteIdentityPermission.cs
- IOThreadScheduler.cs
- ConfigurationStrings.cs
- PathFigure.cs
- XmlQueryCardinality.cs
- ViewPort3D.cs
- JournalEntryListConverter.cs
- _NegotiateClient.cs
- FontInfo.cs
- TypeDependencyAttribute.cs
- StylusTouchDevice.cs
- WaitHandleCannotBeOpenedException.cs
- SemanticBasicElement.cs
- FormViewDeletedEventArgs.cs
- ZoneButton.cs
- LogAppendAsyncResult.cs
- Main.cs
- ConfigurationStrings.cs
- DesignerOptionService.cs
- VersionPair.cs
- ButtonRenderer.cs
- Parameter.cs
- DependencySource.cs
- IgnoreDataMemberAttribute.cs
- ByteStorage.cs
- GridViewEditEventArgs.cs
- HttpHandlersSection.cs
- Html32TextWriter.cs
- webbrowsersite.cs
- MemberAssignment.cs
- CompositeDuplexElement.cs
- File.cs
- HttpException.cs
- TrackingDataItem.cs
- InputMethod.cs
- InkSerializer.cs
- BooleanConverter.cs
- WebPartCollection.cs
- MimeFormatter.cs
- DesignerActionUIStateChangeEventArgs.cs
- TemplateField.cs
- RepeatBehavior.cs
- IconConverter.cs
- WS2007HttpBinding.cs
- ButtonStandardAdapter.cs
- RIPEMD160.cs
- XmlSchemaValidator.cs
- ItemContainerGenerator.cs
- AnnouncementSendsAsyncResult.cs
- EventWaitHandleSecurity.cs
- XmlIlTypeHelper.cs
- Membership.cs
- BitmapEffectDrawingContextState.cs
- SqlMethodCallConverter.cs
- BufferedReadStream.cs
- InputQueueChannel.cs
- SemanticResolver.cs
- bindurihelper.cs
- InfiniteTimeSpanConverter.cs
- DbConnectionPoolGroup.cs
- ResourceDescriptionAttribute.cs
- WindowCollection.cs
- HttpResponseHeader.cs
- XmlIlGenerator.cs
- InfoCardRSAPKCS1SignatureDeformatter.cs
- QualifiedCellIdBoolean.cs
- ArrayTypeMismatchException.cs
- XmlMemberMapping.cs
- WebPartEditorCancelVerb.cs
- EdmProviderManifest.cs