using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Diagnostics;
namespace Svg
{
///
/// The class that all SVG elements should derive from when they are to be rendered.
///
public abstract partial class SvgVisualElement : SvgElement, ISvgStylable, ISvgClipable
{
private bool _dirty;
private bool _requiresSmoothRendering;
private Region _previousClip;
///
/// Gets the for this element.
///
public abstract GraphicsPath Path { get; protected set; }
///
/// Gets the bounds of the element.
///
/// The bounds.
public abstract RectangleF Bounds { get; }
///
/// Gets or sets a value indicating whether this element's is dirty.
///
///
/// true if the path is dirty; otherwise, false.
///
protected virtual bool IsPathDirty
{
get { return this._dirty; }
set { this._dirty = value; }
}
///
/// Gets the associated if one has been specified.
///
[SvgAttribute("clip-path")]
public virtual Uri ClipPath
{
get { return this.Attributes.GetAttribute("clip-path"); }
set { this.Attributes["clip-path"] = value; }
}
///
/// Gets or sets the algorithm which is to be used to determine the clipping region.
///
[SvgAttribute("clip-rule")]
public SvgClipRule ClipRule
{
get { return this.Attributes.GetAttribute("clip-rule", SvgClipRule.NonZero); }
set { this.Attributes["clip-rule"] = value; }
}
///
/// Gets the associated if one has been specified.
///
[SvgAttribute("filter")]
public virtual Uri Filter
{
get { return this.Attributes.GetAttribute("filter"); }
set { this.Attributes["filter"] = value; }
}
///
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
///
protected virtual bool RequiresSmoothRendering
{
get { return this._requiresSmoothRendering; }
}
///
/// Initializes a new instance of the class.
///
public SvgVisualElement()
{
this._dirty = true;
this._requiresSmoothRendering = false;
}
///
/// Renders the and contents to the specified object.
///
/// The object to render to.
protected override void Render(SvgRenderer renderer)
{
if (this.Path != null && this.Visible)
{
this.PushTransforms(renderer);
this.SetClip(renderer);
// If this element needs smoothing enabled turn anti-aliasing on
if (this.RequiresSmoothRendering)
{
renderer.SmoothingMode = SmoothingMode.AntiAlias;
}
this.RenderFill(renderer);
this.RenderStroke(renderer);
// Reset the smoothing mode
if (this.RequiresSmoothRendering && renderer.SmoothingMode == SmoothingMode.AntiAlias)
{
renderer.SmoothingMode = SmoothingMode.Default;
}
this.ResetClip(renderer);
this.PopTransforms(renderer);
}
}
///
/// Renders the fill of the to the specified
///
/// The object to render to.
protected internal virtual void RenderFill(SvgRenderer renderer)
{
if (this.Fill != null)
{
using (Brush brush = this.Fill.GetBrush(this, this.FillOpacity))
{
if (brush != null)
{
this.Path.FillMode = this.FillRule == SvgFillRule.NonZero ? FillMode.Winding : FillMode.Alternate;
renderer.FillPath(brush, this.Path);
}
}
}
}
///
/// Renders the stroke of the to the specified
///
/// The object to render to.
protected internal virtual void RenderStroke(SvgRenderer renderer)
{
if (this.Stroke != null)
{
float strokeWidth = this.StrokeWidth.ToDeviceValue(this);
using (var pen = new Pen(this.Stroke.GetBrush(this, this.StrokeOpacity), strokeWidth))
{
if (this.StrokeDashArray != null && this.StrokeDashArray.Count > 0)
{
/* divide by stroke width - GDI behaviour that I don't quite understand yet.*/
pen.DashPattern = this.StrokeDashArray.ConvertAll(u => u.Value/((strokeWidth <= 0) ? 1 : strokeWidth)).ToArray();
}
renderer.DrawPath(pen, this.Path);
}
}
}
///
/// Sets the clipping region of the specified .
///
/// The to have its clipping region set.
protected internal virtual void SetClip(SvgRenderer renderer)
{
if (this.ClipPath != null)
{
SvgClipPath clipPath = this.OwnerDocument.GetElementById(this.ClipPath.ToString());
this._previousClip = renderer.Clip;
if (clipPath != null)
{
renderer.Clip = clipPath.GetClipRegion(this);
}
}
}
///
/// Resets the clipping region of the specified back to where it was before the method was called.
///
/// The to have its clipping region reset.
protected internal virtual void ResetClip(SvgRenderer renderer)
{
if (this._previousClip != null)
{
renderer.Clip = this._previousClip;
this._previousClip = null;
}
}
///
/// Sets the clipping region of the specified .
///
/// The to have its clipping region set.
void ISvgClipable.SetClip(SvgRenderer renderer)
{
this.SetClip(renderer);
}
///
/// Resets the clipping region of the specified back to where it was before the method was called.
///
/// The to have its clipping region reset.
void ISvgClipable.ResetClip(SvgRenderer renderer)
{
this.ResetClip(renderer);
}
public override SvgElement DeepCopy()
{
var newObj = base.DeepCopy() as SvgVisualElement;
newObj.ClipPath = this.ClipPath;
newObj.ClipRule = this.ClipRule;
newObj.Filter = this.Filter;
newObj.Visible = this.Visible;
if (this.Fill != null)
newObj.Fill = this.Fill;
if (this.Stroke != null)
newObj.Stroke = this.Stroke;
newObj.FillRule = this.FillRule;
newObj.FillOpacity = this.FillOpacity;
newObj.StrokeWidth = this.StrokeWidth;
newObj.StrokeLineCap = this.StrokeLineCap;
newObj.StrokeLineJoin = this.StrokeLineJoin;
newObj.StrokeMiterLimit = this.StrokeMiterLimit;
newObj.StrokeDashArray = this.StrokeDashArray;
newObj.StrokeDashOffset = this.StrokeDashOffset;
newObj.StrokeOpacity = this.StrokeOpacity;
newObj.Opacity = this.Opacity;
return newObj;
}
}
}