OK so I made the changes. They work great. I ended up using a factory pattern as it was more flexible, and allowed me to only have to change two lines of existing code:
In CssUtils.GetCachedFont() change the creation line to:
Let me know if any question.
Thanks,
Ryan
In CssUtils.GetCachedFont() change the creation line to:
font = CssFontFactory.Instance.Create(family, size, style);
// font = new Font(family, size, style); <-- this is the old line
In CssUtils IsFontExists() change the return line to: return CssFontFactory.Instance.Contains(fontFamily) || _existingFonts.ContainsKey(fontFamily);
// return _existingFonts.ContainsKey(fontFamily); <-- this is the old line
And then simply add the new class CssFontFactory which is as follows:// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they bagin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
//
// - Sun Tsu,
// "The Art of War"
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Text;
using System.Runtime.InteropServices;
namespace HtmlRenderer
{
/// <summary>
/// Global public singleton for creating fonts from in-memory FontFamiliy instances or from installed system fonts.
/// FontFamily instances may be added through one of several Add overloads.
/// The Font instance is created from the Create method which will use the FontFamily if found, or the system fonts if not.
/// </summary>
public class CssFontFactory
{
// static members
private static volatile CssFontFactory _instance = null;
private static object _syncRoot = new Object();
// instance members
private Dictionary<string, FontFamily> _fontFamilies;
/// <summary>
/// Instace method for retrieving the singleton font factory.
/// </summary>
public static CssFontFactory Instance
{
get
{
if (_instance == null)
{
lock (_syncRoot)
{
if (_instance == null)
{
_instance = new CssFontFactory();
}
}
}
return _instance;
}
}
/// <summary>
/// Constructor for the font factory. This is private and only created from the Instance property get.
/// </summary>
private CssFontFactory()
{
_fontFamilies = new Dictionary<string, FontFamily>();
}
/// <summary>
/// Attempts to create and returns the Font with the specified family, size, and style.
/// If a matching FontFamily has previously been added via AddFontFamily, then it will be used for creating the Font.
/// Othewise the font will be created directly from the installed system fonts if the Font is installed
/// If the font is not found in that case, .Net will return MS Sans Serif as the Font.
/// </summary>
/// <param name="family">The font family name of the font to create.</param>
/// <param name="size">The point size of the font to create.</param>
/// <param name="style">The style of the font to create.</param>
/// <returns></returns>
public Font Create(string family, float size, FontStyle style)
{
Debug.WriteLine("[CssFontFactory] Looking up font family: " + family);
family = family.ToLower();
FontFamily foundFamily;
_fontFamilies.TryGetValue(family, out foundFamily);
if (foundFamily != null)
{
Debug.WriteLine("[CssFontFactory] Family found: " + family);
return new Font(foundFamily, size, style);
}
else
{
Debug.WriteLine("[CssFontFactory] Family NOT found: " + family);
return new Font(family, size, style);
}
}
/// <summary>
/// Used to determine if a particular font family has been added to the factory.
/// </summary>
/// <param name="family">The font family name to search for.</param>
/// <returns> Returns true if the font family has been added, false otherwise.</returns>
public bool Contains(string family)
{
family = family.ToLower();
return _fontFamilies.ContainsKey(family);
}
/// <summary>
/// Adds a single font family to the factory.
/// </summary>
/// <param name="fontFamily">The font family to add.</param>
public void Add(FontFamily fontFamily)
{
if (fontFamily == null) throw new ArgumentNullException("fontFamily may not be null");
_fontFamilies[fontFamily.Name.ToLower()] = fontFamily; // overwrite if already in the dictionary
Debug.WriteLine("[CssFontFactory] Added font family: " + fontFamily.Name);
}
/// <summary>
/// Adds an array of font families to the factory.
/// </summary>
/// <param name="fontFamilies"></param>
private void Add(FontFamily[] fontFamilies)
{
if (fontFamilies == null) throw new ArgumentNullException("fontFamilies may not be null");
for (int i = 0; i < fontFamilies.Length; i++)
{
Add(fontFamilies[i]);
}
}
/// <summary>
/// Adds all font families contained in the PrivateFontCollection to the factory.
/// </summary>
/// <param name="collection"></param>
public void Add(PrivateFontCollection collection)
{
if (collection == null) throw new ArgumentNullException("collection may not be null");
Add(collection.Families);
}
}
}
That's it! Now any class can simply pass their own PrivateFontCollecion into CssFontFactory.Instance.Add() and from that point forward, all private fonts used by the application will now be used by HtmlRenderer as well.Let me know if any question.
Thanks,
Ryan