RaUI/Source/ryControls/HtmlRenderer/Adapters/RAdapter.cs
zilinsoft 3262955f2f ### 2023-11-07更新
------
#### RaUIV4    V4.0.2311.0701
- *.[全新]整合了MyDb、ryControls、MyDb_MySQL等dll文件到RaUI一个项目。
- *.[新增]新增ApkOp类,可以轻松获取APK信息。
- *.[新增]新增JsonExt扩展类,让Json操作更简单。
- *.[新增]新增WebP类,可以支持webp格式的图片。
- *.[改进]ryQuickSQL中的AddField方法改为自动替换已存在的同名值。
- *.[修复]ryQuickSQL中的AddFieldCalc方法无法正常计算的BUG。
2023-11-07 16:37:53 +08:00

459 lines
18 KiB
C#

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