// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they begin 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.IO;
using TheArtOfDev.HtmlRenderer.Adapters.Entities;
using TheArtOfDev.HtmlRenderer.Core;
using TheArtOfDev.HtmlRenderer.Core.Entities;
using TheArtOfDev.HtmlRenderer.Core.Handlers;
using TheArtOfDev.HtmlRenderer.Core.Utils;
namespace TheArtOfDev.HtmlRenderer.Adapters
{
///
/// Platform adapter to bridge platform specific objects to HTML Renderer core library.
/// Core uses abstract renderer objects (RAdapter/RControl/REtc...) to access platform specific functionality, the concrete platforms
/// implements those objects to provide concrete platform implementation. Those allowing the core library to be platform agnostic.
///
/// Platforms: WinForms, WPF, Metro, PDF renders, etc.
/// Objects: UI elements(Controls), Graphics(Render context), Colors, Brushes, Pens, Fonts, Images, Clipboard, etc.
///
///
///
/// It is best to have a singleton instance of this class for concrete implementation!
/// This is because it holds caches of default CssData, Images, Fonts and Brushes.
///
public abstract class RAdapter
{
#region Fields/Consts
///
/// cache of brush color to brush instance
///
private readonly Dictionary _brushesCache = new Dictionary();
///
/// cache of pen color to pen instance
///
private readonly Dictionary _penCache = new Dictionary();
///
/// cache of all the font used not to create same font again and again
///
private readonly FontsHandler _fontsHandler;
///
/// default CSS parsed data singleton
///
private CssData _defaultCssData;
///
/// image used to draw loading image icon
///
private RImage _loadImage;
///
/// image used to draw error image icon
///
private RImage _errorImage;
#endregion
///
/// Init.
///
protected RAdapter()
{
_fontsHandler = new FontsHandler(this);
}
///
/// Get the default CSS stylesheet data.
///
public CssData DefaultCssData
{
get { return _defaultCssData ?? (_defaultCssData = CssData.Parse(this, CssDefaults.DefaultStyleSheet, false)); }
}
///
/// Resolve color value from given color name.
///
/// the color name
/// color value
public RColor GetColor(string colorName)
{
ArgChecker.AssertArgNotNullOrEmpty(colorName, "colorName");
return GetColorInt(colorName);
}
///
/// Get cached pen instance for the given color.
///
/// the color to get pen for
/// pen instance
public RPen GetPen(RColor color)
{
RPen pen;
if (!_penCache.TryGetValue(color, out pen))
{
_penCache[color] = pen = CreatePen(color);
}
return pen;
}
///
/// Get cached solid brush instance for the given color.
///
/// the color to get brush for
/// brush instance
public RBrush GetSolidBrush(RColor color)
{
RBrush brush;
if (!_brushesCache.TryGetValue(color, out brush))
{
_brushesCache[color] = brush = CreateSolidBrush(color);
}
return brush;
}
///
/// Get linear gradient color brush from to .
///
/// the rectangle to get the brush for
/// the start color of the gradient
/// the end color of the gradient
/// the angle to move the gradient from start color to end color in the rectangle
/// linear gradient color brush instance
public RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor color2, double angle)
{
return CreateLinearGradientBrush(rect, color1, color2, angle);
}
///
/// Convert image object returned from to .
///
/// the image returned from load event
/// converted image or null
public RImage ConvertImage(object image)
{
// TODO:a remove this by creating better API.
return ConvertImageInt(image);
}
///
/// Create an object from the given stream.
///
/// the stream to create image from
/// new image instance
public RImage ImageFromStream(Stream memoryStream)
{
return ImageFromStreamInt(memoryStream);
}
///
/// Check if the given font exists in the system by font family name.
///
/// the font name to check
/// true - font exists by given family name, false - otherwise
public bool IsFontExists(string font)
{
return _fontsHandler.IsFontExists(font);
}
///
/// Adds a font family to be used.
///
/// The font family to add.
public void AddFontFamily(RFontFamily fontFamily)
{
_fontsHandler.AddFontFamily(fontFamily);
}
///
/// Adds a font mapping from to iff the is not found.
/// When the font is used in rendered html and is not found in existing
/// fonts (installed or added) it will be replaced by .
///
/// the font family to replace
/// the font family to replace with
public void AddFontFamilyMapping(string fromFamily, string toFamily)
{
_fontsHandler.AddFontFamilyMapping(fromFamily, toFamily);
}
///
/// Get font instance by given font family name, size and style.
///
/// the font family name
/// font size
/// font style
/// font instance
public RFont GetFont(string family, double size, RFontStyle style)
{
return _fontsHandler.GetCachedFont(family, size, style);
}
///
/// Get image to be used while HTML image is loading.
///
public RImage GetLoadingImage()
{
if (_loadImage == null)
{
var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Core.Utils.ImageLoad.png");
if (stream != null)
_loadImage = ImageFromStream(stream);
}
return _loadImage;
}
///
/// Get image to be used if HTML image load failed.
///
public RImage GetLoadingFailedImage()
{
if (_errorImage == null)
{
var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Core.Utils.ImageError.png");
if (stream != null)
_errorImage = ImageFromStream(stream);
}
return _errorImage;
}
///
/// Get data object for the given html and plain text data.
/// The data object can be used for clipboard or drag-drop operation.
/// Not relevant for platforms that don't render HTML on UI element.
///
/// the html data
/// the plain text data
/// drag-drop data object
public object GetClipboardDataObject(string html, string plainText)
{
return GetClipboardDataObjectInt(html, plainText);
}
///
/// Set the given text to the clipboard
/// Not relevant for platforms that don't render HTML on UI element.
///
/// the text to set
public void SetToClipboard(string text)
{
SetToClipboardInt(text);
}
///
/// Set the given html and plain text data to clipboard.
/// Not relevant for platforms that don't render HTML on UI element.
///
/// the html data
/// the plain text data
public void SetToClipboard(string html, string plainText)
{
SetToClipboardInt(html, plainText);
}
///
/// Set the given image to clipboard.
/// Not relevant for platforms that don't render HTML on UI element.
///
/// the image object to set to clipboard
public void SetToClipboard(RImage image)
{
SetToClipboardInt(image);
}
///
/// Create a context menu that can be used on the control
/// Not relevant for platforms that don't render HTML on UI element.
///
/// new context menu
public RContextMenu GetContextMenu()
{
return CreateContextMenuInt();
}
///
/// Save the given image to file by showing save dialog to the client.
/// Not relevant for platforms that don't render HTML on UI element.
///
/// the image to save
/// the name of the image for save dialog
/// the extension of the image for save dialog
/// optional: the control to show the dialog on
public void SaveToFile(RImage image, string name, string extension, RControl control = null)
{
SaveToFileInt(image, name, extension, control);
}
///
/// Get font instance by given font family name, size and style.
///
/// the font family name
/// font size
/// font style
/// font instance
internal RFont CreateFont(string family, double size, RFontStyle style)
{
return CreateFontInt(family, size, style);
}
///
/// Get font instance by given font family instance, size and style.
/// Used to support custom fonts that require explicit font family instance to be created.
///
/// the font family instance
/// font size
/// font style
/// font instance
internal RFont CreateFont(RFontFamily family, double size, RFontStyle style)
{
return CreateFontInt(family, size, style);
}
#region Private/Protected methods
///
/// Resolve color value from given color name.
///
/// the color name
/// color value
protected abstract RColor GetColorInt(string colorName);
///
/// Get cached pen instance for the given color.
///
/// the color to get pen for
/// pen instance
protected abstract RPen CreatePen(RColor color);
///
/// Get cached solid brush instance for the given color.
///
/// the color to get brush for
/// brush instance
protected abstract RBrush CreateSolidBrush(RColor color);
///
/// Get linear gradient color brush from to .
///
/// the rectangle to get the brush for
/// the start color of the gradient
/// the end color of the gradient
/// the angle to move the gradient from start color to end color in the rectangle
/// linear gradient color brush instance
protected abstract RBrush CreateLinearGradientBrush(RRect rect, RColor color1, RColor color2, double angle);
///
/// Convert image object returned from to .
///
/// the image returned from load event
/// converted image or null
protected abstract RImage ConvertImageInt(object image);
///
/// Create an object from the given stream.
///
/// the stream to create image from
/// new image instance
protected abstract RImage ImageFromStreamInt(Stream memoryStream);
///
/// Get font instance by given font family name, size and style.
///
/// the font family name
/// font size
/// font style
/// font instance
protected abstract RFont CreateFontInt(string family, double size, RFontStyle style);
///
/// Get font instance by given font family instance, size and style.
/// Used to support custom fonts that require explicit font family instance to be created.
///
/// the font family instance
/// font size
/// font style
/// font instance
protected abstract RFont CreateFontInt(RFontFamily family, double size, RFontStyle style);
///
/// Get data object for the given html and plain text data.
/// The data object can be used for clipboard or drag-drop operation.
///
/// the html data
/// the plain text data
/// drag-drop data object
protected virtual object GetClipboardDataObjectInt(string html, string plainText)
{
throw new NotImplementedException();
}
///
/// Set the given text to the clipboard
///
/// the text to set
protected virtual void SetToClipboardInt(string text)
{
throw new NotImplementedException();
}
///
/// Set the given html and plain text data to clipboard.
///
/// the html data
/// the plain text data
protected virtual void SetToClipboardInt(string html, string plainText)
{
throw new NotImplementedException();
}
///
/// Set the given image to clipboard.
///
///
protected virtual void SetToClipboardInt(RImage image)
{
throw new NotImplementedException();
}
///
/// Create a context menu that can be used on the control
///
/// new context menu
protected virtual RContextMenu CreateContextMenuInt()
{
throw new NotImplementedException();
}
///
/// Save the given image to file by showing save dialog to the client.
///
/// the image to save
/// the name of the image for save dialog
/// the extension of the image for save dialog
/// optional: the control to show the dialog on
protected virtual void SaveToFileInt(RImage image, string name, string extension, RControl control = null)
{
throw new NotImplementedException();
}
#endregion
}
}