// "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 } }