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; } } }