// "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 TheArtOfDev.HtmlRenderer.Adapters;
using TheArtOfDev.HtmlRenderer.Adapters.Entities;
using TheArtOfDev.HtmlRenderer.Core.Dom;
namespace TheArtOfDev.HtmlRenderer.Core.Utils
{
///
/// Provides some drawing functionality
///
internal static class RenderUtils
{
///
/// Check if the given color is visible if painted (has alpha and color values)
///
/// the color to check
/// true - visible, false - not visible
public static bool IsColorVisible(RColor color)
{
return color.A > 0;
}
///
/// Clip the region the graphics will draw on by the overflow style of the containing block.
/// Recursively travel up the tree to find containing block that has overflow style set to hidden. if not
/// block found there will be no clipping and null will be returned.
///
/// the graphics to clip
/// the box that is rendered to get containing blocks
/// true - was clipped, false - not clipped
public static bool ClipGraphicsByOverflow(RGraphics g, CssBox box)
{
var containingBlock = box.ContainingBlock;
while (true)
{
if (containingBlock.Overflow == CssConstants.Hidden)
{
var prevClip = g.GetClip();
var rect = box.ContainingBlock.ClientRectangle;
rect.X -= 2; // TODO:a find better way to fix it
rect.Width += 2;
rect.Offset(box.HtmlContainer.ScrollOffset);
rect.Intersect(prevClip);
g.PushClip(rect);
return true;
}
else
{
var cBlock = containingBlock.ContainingBlock;
if (cBlock == containingBlock)
return false;
containingBlock = cBlock;
}
}
}
///
/// Draw image loading icon.
///
/// the device to draw into
///
/// the rectangle to draw icon in
public static void DrawImageLoadingIcon(RGraphics g, HtmlContainerInt htmlContainer, RRect r)
{
g.DrawRectangle(g.GetPen(RColor.LightGray), r.Left + 3, r.Top + 3, 13, 14);
var image = htmlContainer.Adapter.GetLoadingImage();
g.DrawImage(image, new RRect(r.Left + 4, r.Top + 4, image.Width, image.Height));
}
///
/// Draw image failed to load icon.
///
/// the device to draw into
///
/// the rectangle to draw icon in
public static void DrawImageErrorIcon(RGraphics g, HtmlContainerInt htmlContainer, RRect r)
{
g.DrawRectangle(g.GetPen(RColor.LightGray), r.Left + 2, r.Top + 2, 15, 15);
var image = htmlContainer.Adapter.GetLoadingFailedImage();
g.DrawImage(image, new RRect(r.Left + 3, r.Top + 3, image.Width, image.Height));
}
///
/// Creates a rounded rectangle using the specified corner radius
/// NW-----NE
/// | |
/// | |
/// SW-----SE
///
/// the device to draw into
/// Rectangle to round
/// Radius of the north east corner
/// Radius of the north west corner
/// Radius of the south east corner
/// Radius of the south west corner
/// GraphicsPath with the lines of the rounded rectangle ready to be painted
public static RGraphicsPath GetRoundRect(RGraphics g, RRect rect, double nwRadius, double neRadius, double seRadius, double swRadius)
{
var path = g.GetGraphicsPath();
path.Start(rect.Left + nwRadius, rect.Top);
path.LineTo(rect.Right - neRadius, rect.Y);
if (neRadius > 0f)
path.ArcTo(rect.Right, rect.Top + neRadius, neRadius, RGraphicsPath.Corner.TopRight);
path.LineTo(rect.Right, rect.Bottom - seRadius);
if (seRadius > 0f)
path.ArcTo(rect.Right - seRadius, rect.Bottom, seRadius, RGraphicsPath.Corner.BottomRight);
path.LineTo(rect.Left + swRadius, rect.Bottom);
if (swRadius > 0f)
path.ArcTo(rect.Left, rect.Bottom - swRadius, swRadius, RGraphicsPath.Corner.BottomLeft);
path.LineTo(rect.Left, rect.Top + nwRadius);
if (nwRadius > 0f)
path.ArcTo(rect.Left + nwRadius, rect.Top, nwRadius, RGraphicsPath.Corner.TopLeft);
return path;
}
}
}