From 76fbb49106726ff8582f22637cd11b4dbaa20df9 Mon Sep 17 00:00:00 2001 From: davescriven Date: Sat, 20 Dec 2008 06:03:36 +0000 Subject: [PATCH] - Fixed #5650: Support SVG element "clipPath" - Refactored SvgElementFactory to use the new SvgElementAttribute to get available elements. --- Basic Shapes/SvgCircle.cs | 1 + Basic Shapes/SvgEllipse.cs | 1 + Basic Shapes/SvgLine.cs | 1 + Basic Shapes/SvgPolygon.cs | 1 + Basic Shapes/SvgPolyline.cs | 1 + Basic Shapes/SvgRectangle.cs | 1 + Basic Shapes/SvgVisualElement.cs | 17 +++- Clipping and Masking/ISvgClipable.cs | 4 + Clipping and Masking/SvgClipPath.cs | 55 +++++++----- Clipping and Masking/SvgClipRule.cs | 27 ++++++ DataTypes/SvgUnit.cs | 1 + Document Structure/SvgDefinitionList.cs | 1 + Document Structure/SvgDescription.cs | 1 + Document Structure/SvgFragment.cs | 1 + Document Structure/SvgGroup.cs | 3 + Document Structure/SvgUse.cs | 9 +- Painting/SvgGradientServer.cs | 34 +++++++- Painting/SvgGradientStop.cs | 1 + Painting/SvgLinearGradientServer.cs | 1 + Painting/SvgPaintServer.cs | 25 +++++- Painting/SvgPatternServer.cs | 28 ++++++ Painting/SvgRadialGradientServer.cs | 1 + Paths/SvgPath.cs | 1 + Svg.csproj | 4 +- SvgAttributeAttribute.cs | 37 ++++++-- SvgAttributeCollection.cs | 19 +++- SvgElement.cs | 14 +++ SvgElementAttribute.cs | 28 ++++++ SvgElementFactory.cs | 111 +++++++++--------------- SvgRenderer.cs | 2 +- Text/SvgText.cs | 1 + 31 files changed, 321 insertions(+), 111 deletions(-) create mode 100644 Clipping and Masking/SvgClipRule.cs create mode 100644 SvgElementAttribute.cs diff --git a/Basic Shapes/SvgCircle.cs b/Basic Shapes/SvgCircle.cs index de403b1..87637a9 100644 --- a/Basic Shapes/SvgCircle.cs +++ b/Basic Shapes/SvgCircle.cs @@ -12,6 +12,7 @@ namespace Svg /// /// An SVG element to render circles to the document. /// + [SvgElement("circle")] public class SvgCircle : SvgVisualElement { private GraphicsPath _path; diff --git a/Basic Shapes/SvgEllipse.cs b/Basic Shapes/SvgEllipse.cs index e585201..3ec0513 100644 --- a/Basic Shapes/SvgEllipse.cs +++ b/Basic Shapes/SvgEllipse.cs @@ -11,6 +11,7 @@ namespace Svg /// /// Represents and SVG ellipse element. /// + [SvgElement("ellipse")] public class SvgEllipse : SvgVisualElement { private SvgUnit _radiusX; diff --git a/Basic Shapes/SvgLine.cs b/Basic Shapes/SvgLine.cs index aee9e4a..4712869 100644 --- a/Basic Shapes/SvgLine.cs +++ b/Basic Shapes/SvgLine.cs @@ -10,6 +10,7 @@ namespace Svg /// /// Represents and SVG line element. /// + [SvgElement("line")] public class SvgLine : SvgVisualElement { private SvgUnit _startX; diff --git a/Basic Shapes/SvgPolygon.cs b/Basic Shapes/SvgPolygon.cs index e579211..9f73f2b 100644 --- a/Basic Shapes/SvgPolygon.cs +++ b/Basic Shapes/SvgPolygon.cs @@ -11,6 +11,7 @@ namespace Svg /// /// SvgPolygon defines a closed shape consisting of a set of connected straight line segments. /// + [SvgElement("polygon")] public class SvgPolygon : SvgVisualElement { protected GraphicsPath _path; diff --git a/Basic Shapes/SvgPolyline.cs b/Basic Shapes/SvgPolyline.cs index 13cbdb3..e8b63d1 100644 --- a/Basic Shapes/SvgPolyline.cs +++ b/Basic Shapes/SvgPolyline.cs @@ -10,6 +10,7 @@ namespace Svg /// /// SvgPolyline defines a set of connected straight line segments. Typically, defines open shapes. /// + [SvgElement("polyline")] public class SvgPolyline : SvgPolygon { public override GraphicsPath Path diff --git a/Basic Shapes/SvgRectangle.cs b/Basic Shapes/SvgRectangle.cs index 9b3c0b5..53b5138 100644 --- a/Basic Shapes/SvgRectangle.cs +++ b/Basic Shapes/SvgRectangle.cs @@ -7,6 +7,7 @@ namespace Svg /// /// Represents and SVG rectangle that could also have reounded edges. /// + [SvgElement("rect")] public class SvgRectangle : SvgVisualElement { private SvgUnit _cornerRadiusX; diff --git a/Basic Shapes/SvgVisualElement.cs b/Basic Shapes/SvgVisualElement.cs index 109e5ae..65cab4f 100644 --- a/Basic Shapes/SvgVisualElement.cs +++ b/Basic Shapes/SvgVisualElement.cs @@ -18,6 +18,7 @@ namespace Svg private bool _dirty; private bool _requiresSmoothRendering; private Region _previousClip; + private SvgClipRule clipRule = SvgClipRule.NonZero; /// /// Gets the for this element. @@ -51,6 +52,16 @@ namespace Svg set { this.Attributes["clip-path"] = value; } } + /// + /// + /// + [SvgAttribute("clip-rule")] + public SvgClipRule ClipRule + { + get { return this.Attributes.GetAttribute("clip-rule", SvgClipRule.NonZero); } + set { this.Attributes["clip-rule"] = value; } + } + /// /// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered. /// @@ -143,7 +154,7 @@ namespace Svg if (clipPath != null) { - renderer.SetClip(clipPath.GetClipRegion()); + renderer.Clip = clipPath.GetClipRegion(this); } } } @@ -154,9 +165,9 @@ namespace Svg /// The to have its clipping region reset. protected internal virtual void ResetClip(SvgRenderer renderer) { - if (this.ClipPath != null) + if (this._previousClip != null) { - renderer.SetClip(this._previousClip); + renderer.Clip = this._previousClip; this._previousClip = null; } } diff --git a/Clipping and Masking/ISvgClipable.cs b/Clipping and Masking/ISvgClipable.cs index 5130d13..dc604fa 100644 --- a/Clipping and Masking/ISvgClipable.cs +++ b/Clipping and Masking/ISvgClipable.cs @@ -16,6 +16,10 @@ namespace Svg /// Uri ClipPath { get; set; } /// + /// Specifies the rule used to define the clipping region when the element is within a . + /// + SvgClipRule ClipRule { get; set; } + /// /// Sets the clipping region of the specified . /// /// The to have its clipping region set. diff --git a/Clipping and Masking/SvgClipPath.cs b/Clipping and Masking/SvgClipPath.cs index be4b68f..7703d08 100644 --- a/Clipping and Masking/SvgClipPath.cs +++ b/Clipping and Masking/SvgClipPath.cs @@ -7,51 +7,46 @@ using System.Drawing.Drawing2D; namespace Svg { /// - /// + /// Defines a path that can be used by other elements. /// + [SvgElement("clipPath")] public sealed class SvgClipPath : SvgElement { - private SvgCoordinateUnits _clipPathUnits; - private bool _pathDirty; - private Region _region; + private bool _pathDirty = true; /// - /// + /// Specifies the coordinate system for the clipping path. /// [SvgAttribute("clipPathUnits")] - public SvgCoordinateUnits ClipPathUnits - { - get { return this._clipPathUnits; } - set { this._clipPathUnits = value; } - } + public SvgCoordinateUnits ClipPathUnits { get; set; } /// /// Initializes a new instance of the class. /// public SvgClipPath() { - this._clipPathUnits = SvgCoordinateUnits.ObjectBoundingBox; + this.ClipPathUnits = SvgCoordinateUnits.ObjectBoundingBox; } /// - /// Gets this 's region to be clipped. + /// Gets this 's region to be used as a clipping region. /// - /// A new containing the area to be clipped. - protected internal Region GetClipRegion() + /// A new containing the to be used for clipping. + public Region GetClipRegion(SvgVisualElement owner) { - if (_region == null || _pathDirty) - { - _region = new Region(); + var path = new GraphicsPath(); + if (this._pathDirty) + { foreach (SvgElement element in this.Children) { - ComplementRegion(_region, element); + this.CombinePaths(path, element); } - _pathDirty = false; + this._pathDirty = false; } - return _region; + return new Region(path); } /// @@ -59,27 +54,39 @@ namespace Svg /// /// /// - private void ComplementRegion(Region region, SvgElement element) + private void CombinePaths(GraphicsPath path, SvgElement element) { - SvgVisualElement graphicsElement = element as SvgVisualElement; + var graphicsElement = element as SvgVisualElement; if (graphicsElement != null && graphicsElement.Path != null) { - region.Complement(graphicsElement.Path); + path.FillMode = (graphicsElement.ClipRule == SvgClipRule.NonZero) ? FillMode.Winding : FillMode.Alternate; + path.AddPath(graphicsElement.Path, false); } foreach (SvgElement child in element.Children) { - ComplementRegion(region, child); + this.CombinePaths(path, child); } } + /// + /// Called by the underlying when an element has been added to the + /// collection. + /// + /// The that has been added. + /// An representing the index where the element was added to the collection. protected override void AddElement(SvgElement child, int index) { base.AddElement(child, index); this._pathDirty = true; } + /// + /// Called by the underlying when an element has been removed from the + /// collection. + /// + /// The that has been removed. protected override void RemoveElement(SvgElement child) { base.RemoveElement(child); diff --git a/Clipping and Masking/SvgClipRule.cs b/Clipping and Masking/SvgClipRule.cs new file mode 100644 index 0000000..9c97b01 --- /dev/null +++ b/Clipping and Masking/SvgClipRule.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Svg +{ + /// + /// Indicates the algorithm which is to be used to determine the clipping region. + /// + /// + /// This rule determines the "insideness" of a point on the canvas by drawing a ray from + /// that point to infinity in any direction and then examining the places where a segment of the + /// shape crosses the ray. + /// + public enum SvgClipRule + { + /// + /// This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a path segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside. + /// + NonZero, + /// + /// This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside. + /// + EvenOdd + } +} \ No newline at end of file diff --git a/DataTypes/SvgUnit.cs b/DataTypes/SvgUnit.cs index 3346754..09ced84 100644 --- a/DataTypes/SvgUnit.cs +++ b/DataTypes/SvgUnit.cs @@ -120,6 +120,7 @@ namespace Svg if (styleOwner == null) { _deviceValue = this.Value; + break; } // TODO : Support height percentages diff --git a/Document Structure/SvgDefinitionList.cs b/Document Structure/SvgDefinitionList.cs index 2d9d037..a3e099d 100644 --- a/Document Structure/SvgDefinitionList.cs +++ b/Document Structure/SvgDefinitionList.cs @@ -7,6 +7,7 @@ namespace Svg /// /// Represents a list of re-usable SVG components. /// + [SvgElement("defs")] public class SvgDefinitionList : SvgElement { /// diff --git a/Document Structure/SvgDescription.cs b/Document Structure/SvgDescription.cs index a996f7c..d9a8b6c 100644 --- a/Document Structure/SvgDescription.cs +++ b/Document Structure/SvgDescription.cs @@ -6,6 +6,7 @@ using System.ComponentModel; namespace Svg { [DefaultProperty("Text")] + [SvgElement("desc")] public class SvgDescription : SvgElement { private string _text; diff --git a/Document Structure/SvgFragment.cs b/Document Structure/SvgFragment.cs index 10db81d..8da833a 100644 --- a/Document Structure/SvgFragment.cs +++ b/Document Structure/SvgFragment.cs @@ -11,6 +11,7 @@ namespace Svg /// /// An represents an SVG fragment that can be the root element or an embedded fragment of an SVG document. /// + [SvgElement("svg")] public class SvgFragment : SvgElement, ISvgViewPort { private SvgUnit _width; diff --git a/Document Structure/SvgGroup.cs b/Document Structure/SvgGroup.cs index 8ea2156..4f169b6 100644 --- a/Document Structure/SvgGroup.cs +++ b/Document Structure/SvgGroup.cs @@ -9,6 +9,7 @@ namespace Svg /// /// An element used to group SVG shapes. /// + [SvgElement("g")] public class SvgGroup : SvgVisualElement { public SvgGroup() @@ -51,7 +52,9 @@ namespace Svg protected override void Render(SvgRenderer renderer) { this.PushTransforms(renderer); + this.SetClip(renderer); base.RenderChildren(renderer); + this.ResetClip(renderer); this.PopTransforms(renderer); } } diff --git a/Document Structure/SvgUse.cs b/Document Structure/SvgUse.cs index 284ca97..4efaf3f 100644 --- a/Document Structure/SvgUse.cs +++ b/Document Structure/SvgUse.cs @@ -8,6 +8,7 @@ using System.Drawing.Drawing2D; namespace Svg { + [SvgElement("use")] public class SvgUse : SvgVisualElement { private Uri _referencedElement; @@ -33,15 +34,21 @@ namespace Svg set { this.Attributes["y"] = value; } } + /// + /// Applies the required transforms to . + /// + /// The to be transformed. protected internal override void PushTransforms(SvgRenderer renderer) { base.PushTransforms(renderer); renderer.TranslateTransform(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true)); } + /// + /// Initializes a new instance of the class. + /// public SvgUse() { - } public override System.Drawing.Drawing2D.GraphicsPath Path diff --git a/Painting/SvgGradientServer.cs b/Painting/SvgGradientServer.cs index 27d7e70..062bad2 100644 --- a/Painting/SvgGradientServer.cs +++ b/Painting/SvgGradientServer.cs @@ -26,6 +26,12 @@ namespace Svg this._stops = new List(); } + /// + /// Called by the underlying when an element has been added to the + /// collection. + /// + /// The that has been added. + /// An representing the index where the element was added to the collection. protected override void AddElement(SvgElement child, int index) { if (child is SvgGradientStop) @@ -36,18 +42,32 @@ namespace Svg base.AddElement(child, index); } + /// + /// Called by the underlying when an element has been removed from the + /// collection. + /// + /// The that has been removed. protected override void RemoveElement(SvgElement child) { if (child is SvgGradientStop) - this.Stops.Add((SvgGradientStop)child); + { + this.Stops.Remove((SvgGradientStop)child); + } + base.RemoveElement(child); } + /// + /// Gets the ramp of colors to use on a gradient. + /// public List Stops { get { return this._stops; } } + /// + /// Specifies what happens if the gradient starts or ends inside the bounds of the target rectangle. + /// [SvgAttribute("spreadMethod")] public SvgGradientSpreadMethod SpreadMethod { @@ -55,6 +75,9 @@ namespace Svg set { this._spreadMethod = value; } } + /// + /// Gets or sets the coordinate system of the gradient. + /// [SvgAttribute("gradientUnits")] public SvgCoordinateUnits GradientUnits { @@ -68,6 +91,11 @@ namespace Svg set { this._inheritGradient = value; } } + /// + /// Gets a representing the 's gradient stops. + /// + /// The parent . + /// The opacity of the colour blend. protected ColorBlend GetColourBlend(SvgVisualElement owner, float opacity) { ColorBlend blend = new ColorBlend(); @@ -138,7 +166,9 @@ namespace Svg List stops = new List(); if (this.Stops.Count > 0) + { return stops; + } if (this.InheritGradient != null) { @@ -148,7 +178,5 @@ namespace Svg return stops; } - - } } \ No newline at end of file diff --git a/Painting/SvgGradientStop.cs b/Painting/SvgGradientStop.cs index 3a9055f..7fcbf8e 100644 --- a/Painting/SvgGradientStop.cs +++ b/Painting/SvgGradientStop.cs @@ -9,6 +9,7 @@ namespace Svg /// /// Represents a colour stop in a gradient. /// + [SvgElement("stop")] public class SvgGradientStop : SvgElement { private SvgUnit _offset; diff --git a/Painting/SvgLinearGradientServer.cs b/Painting/SvgLinearGradientServer.cs index 01ca2d5..8aeece0 100644 --- a/Painting/SvgLinearGradientServer.cs +++ b/Painting/SvgLinearGradientServer.cs @@ -7,6 +7,7 @@ using System.ComponentModel; namespace Svg { + [SvgElement("linearGradient")] public sealed class SvgLinearGradientServer : SvgGradientServer { private SvgUnit _x1; diff --git a/Painting/SvgPaintServer.cs b/Painting/SvgPaintServer.cs index ce57cfb..115e7f1 100644 --- a/Painting/SvgPaintServer.cs +++ b/Painting/SvgPaintServer.cs @@ -7,23 +7,46 @@ using System.Drawing.Drawing2D; namespace Svg { + /// + /// Represents the base class for all paint servers that are intended to be used as a fill or stroke. + /// [TypeConverter(typeof(SvgPaintServerFactory))] public abstract class SvgPaintServer : SvgElement { + /// + /// An unspecified . + /// public static readonly SvgPaintServer None = new SvgColourServer(); + /// + /// Initializes a new instance of the class. + /// public SvgPaintServer() { - } + /// + /// Renders the and contents to the specified object. + /// + /// The object to render to. protected override void Render(SvgRenderer renderer) { // Never render paint servers or their children } + /// + /// Gets a representing the current paint server. + /// + /// The owner . + /// The opacity of the brush. public abstract Brush GetBrush(SvgVisualElement styleOwner, float opacity); + /// + /// Returns a that represents the current . + /// + /// + /// A that represents the current . + /// public override string ToString() { return String.Format("url(#{0})", this.ID); diff --git a/Painting/SvgPatternServer.cs b/Painting/SvgPatternServer.cs index 7deace4..95764e8 100644 --- a/Painting/SvgPatternServer.cs +++ b/Painting/SvgPatternServer.cs @@ -9,6 +9,10 @@ using Svg.Transforms; namespace Svg { + /// + /// A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted. + /// + [SvgElement("pattern")] public sealed class SvgPatternServer : SvgPaintServer, ISvgViewPort { private SvgUnit _width; @@ -17,6 +21,10 @@ namespace Svg private SvgUnit _y; private SvgViewBox _viewBox; + /// + /// Specifies a supplemental transformation which is applied on top of any + /// transformations necessary to create a new pattern coordinate system. + /// [SvgAttribute("viewBox")] public SvgViewBox ViewBox { @@ -24,6 +32,9 @@ namespace Svg set { this._viewBox = value; } } + /// + /// Gets or sets the width of the pattern. + /// [SvgAttribute("width")] public SvgUnit Width { @@ -31,6 +42,9 @@ namespace Svg set { this._width = value; } } + /// + /// Gets or sets the height of the pattern. + /// [SvgAttribute("height")] public SvgUnit Height { @@ -38,6 +52,9 @@ namespace Svg set { this._height = value; } } + /// + /// Gets or sets the X-axis location of the pattern. + /// [SvgAttribute("x")] public SvgUnit X { @@ -45,6 +62,9 @@ namespace Svg set { this._x = value; } } + /// + /// Gets or sets the Y-axis location of the pattern. + /// [SvgAttribute("y")] public SvgUnit Y { @@ -52,6 +72,9 @@ namespace Svg set { this._y = value; } } + /// + /// Initializes a new instance of the class. + /// public SvgPatternServer() { this._x = new SvgUnit(0.0f); @@ -60,6 +83,11 @@ namespace Svg this._height = new SvgUnit(0.0f); } + /// + /// Gets a representing the current paint server. + /// + /// The owner . + /// The opacity of the brush. public override Brush GetBrush(SvgVisualElement renderingElement, float opacity) { // If there aren't any children, return null diff --git a/Painting/SvgRadialGradientServer.cs b/Painting/SvgRadialGradientServer.cs index 2afd16a..779b6c7 100644 --- a/Painting/SvgRadialGradientServer.cs +++ b/Painting/SvgRadialGradientServer.cs @@ -6,6 +6,7 @@ using System.Drawing.Drawing2D; namespace Svg { + [SvgElement("radialGradient")] public sealed class SvgRadialGradientServer : SvgGradientServer { [SvgAttribute("cx")] diff --git a/Paths/SvgPath.cs b/Paths/SvgPath.cs index dc5e3ca..0490ee0 100644 --- a/Paths/SvgPath.cs +++ b/Paths/SvgPath.cs @@ -13,6 +13,7 @@ namespace Svg /// /// Represents an SVG path element. /// + [SvgElement("path")] public class SvgPath : SvgVisualElement { private SvgPathSegmentList _pathData; diff --git a/Svg.csproj b/Svg.csproj index 98fc09e..1e5844e 100644 --- a/Svg.csproj +++ b/Svg.csproj @@ -37,7 +37,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;REFLECTION prompt 4 @@ -72,6 +72,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/SvgAttributeAttribute.cs b/SvgAttributeAttribute.cs index d220df7..ace4a4d 100644 --- a/SvgAttributeAttribute.cs +++ b/SvgAttributeAttribute.cs @@ -5,20 +5,23 @@ using System.ComponentModel; namespace Svg { + /// + /// Specifies the SVG attribute name of the associated property. + /// + [AttributeUsage(AttributeTargets.Property)] public class SvgAttributeAttribute : System.Attribute { private const string SVG_NAMESPACE = "http://www.w3.org/2000/svg"; private string _name; private string _namespace; - public override object TypeId - { - get - { - return base.TypeId; - } - } - + /// + /// When overridden in a derived class, returns a value that indicates whether this instance equals a specified object. + /// + /// An to compare with this instance of . + /// + /// true if this instance equals ; otherwise, false. + /// public override bool Match(object obj) { SvgAttributeAttribute indicator = obj as SvgAttributeAttribute; @@ -33,27 +36,45 @@ namespace Svg return String.Compare(indicator.Name, this.Name) == 0; } + /// + /// Gets the name of the SVG attribute. + /// public string Name { get { return this._name; } } + /// + /// Gets the namespace of the SVG attribute. + /// public string NameSpace { get { return this._namespace; } } + /// + /// Initializes a new instance of the class. + /// internal SvgAttributeAttribute() { this._name = String.Empty; } + /// + /// Initializes a new instance of the class with the specified attribute name. + /// + /// The name of the SVG attribute. internal SvgAttributeAttribute(string name) { this._name = name; this._namespace = SVG_NAMESPACE; } + /// + /// Initializes a new instance of the class with the specified SVG attribute name and namespace. + /// + /// The name of the SVG attribute. + /// The namespace of the SVG attribute (e.g. http://www.w3.org/2000/svg). public SvgAttributeAttribute(string name, string nameSpace) { this._name = name; diff --git a/SvgAttributeCollection.cs b/SvgAttributeCollection.cs index 3e940a6..3ad03f1 100644 --- a/SvgAttributeCollection.cs +++ b/SvgAttributeCollection.cs @@ -35,7 +35,24 @@ namespace Svg return (TAttributeType)base[attributeName]; } - return default(TAttributeType); + return this.GetAttribute(attributeName, default(TAttributeType)); + } + + /// + /// Gets the attribute with the specified name. + /// + /// The type of the attribute value. + /// A containing the name of the attribute. + /// The value to return if a value hasn't already been specified. + /// The attribute value if available; otherwise the default value of . + public T GetAttribute(string attributeName, T defaultValue) + { + if (this.ContainsKey(attributeName) && base[attributeName] != null) + { + return (T)base[attributeName]; + } + + return defaultValue; } /// diff --git a/SvgElement.cs b/SvgElement.cs index 2a3483d..8ef3e88 100644 --- a/SvgElement.cs +++ b/SvgElement.cs @@ -226,15 +226,29 @@ namespace Svg { } + /// + /// Calls the method with the specified parameters. + /// + /// The that has been added. + /// An representing the index where the element was added to the collection. internal void OnElementAdded(SvgElement child, int index) { this.AddElement(child, index); } + /// + /// Called by the underlying when an element has been removed from the + /// collection. + /// + /// The that has been removed. protected virtual void RemoveElement(SvgElement child) { } + /// + /// Calls the method with the specified as the parameter. + /// + /// The that has been removed. internal void OnElementRemoved(SvgElement child) { this.RemoveElement(child); diff --git a/SvgElementAttribute.cs b/SvgElementAttribute.cs new file mode 100644 index 0000000..7162191 --- /dev/null +++ b/SvgElementAttribute.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Svg +{ + /// + /// Specifies the SVG name of an . + /// + [AttributeUsage(AttributeTargets.Class)] + public sealed class SvgElementAttribute : Attribute + { + /// + /// Gets the name of the SVG element. + /// + public string ElementName { get; private set; } + + /// + /// Initializes a new instance of the class with the specified element name; + /// + /// The name of the SVG element. + public SvgElementAttribute(string elementName) + { + this.ElementName = elementName; + } + } +} \ No newline at end of file diff --git a/SvgElementFactory.cs b/SvgElementFactory.cs index bdc7bff..b96c1bb 100644 --- a/SvgElementFactory.cs +++ b/SvgElementFactory.cs @@ -12,6 +12,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Diagnostics; using System.Threading; +using System.Linq; using Svg.Transforms; @@ -19,6 +20,25 @@ namespace Svg { internal class SvgElementFactory { + private static List availableElements; + + private static List AvailableElements + { + get + { + if (availableElements == null) + { + var svgTypes = from t in typeof(SvgDocument).Assembly.GetExportedTypes() + where t.GetCustomAttributes(typeof(SvgElementAttribute), true).Length > 0 + select new ElementInfo { ElementName = ((SvgElementAttribute)t.GetCustomAttributes(typeof(SvgElementAttribute), true)[0]).ElementName, ElementType = t }; + + availableElements = svgTypes.ToList(); + } + + return availableElements; + } + } + public static SvgDocument CreateDocument(XmlTextReader reader) { return (SvgDocument)CreateElement(reader, true, null); @@ -37,76 +57,18 @@ namespace Svg Trace.TraceInformation("Begin CreateElement: {0}", elementName); - // Parse element - switch (elementName) + if (elementName == "svg") { - case "path": - createdElement = new SvgPath(); - break; - case "linearGradient": - createdElement = new SvgLinearGradientServer(); - break; - case "radialGradient": - createdElement = new SvgRadialGradientServer(); - break; - case "pattern": - createdElement = new SvgPatternServer(); - break; - case "defs": - createdElement = new SvgDefinitionList(); - break; - case "stop": - createdElement = new SvgGradientStop(); - break; - case "desc": - createdElement = new SvgDescription(); - break; - case "clipPath": - createdElement = new SvgClipPath(); - break; - case "svg": - if (!fragmentIsDocument) - { - fragment = new SvgFragment(); - } - else - { - fragment = new SvgDocument(); - } + createdElement = (fragmentIsDocument) ? new SvgDocument() : new SvgFragment(); + } + else + { + var validTypes = AvailableElements.Where(e => e.ElementName == elementName); - createdElement = (fragmentIsDocument) ? (SvgDocument)fragment : fragment; - break; - case "circle": - createdElement = new SvgCircle(); - break; - case "ellipse": - createdElement = new SvgEllipse(); - break; - case "rect": - createdElement = new SvgRectangle(); - break; - case "line": - createdElement = new SvgLine(); - break; - case "polyline": - createdElement = new SvgPolyline(); - break; - case "polygon": - createdElement = new SvgPolygon(); - break; - case "g": - createdElement = new SvgGroup(); - break; - case "use": - createdElement = new SvgUse(); - break; - case "text": - createdElement = new SvgText(); - break; - default: - // Do nothing - unsupported - createdElement = null; - break; + if (validTypes.Count() > 0) + { + createdElement = Activator.CreateInstance(validTypes.First().ElementType) as SvgElement; + } } if (createdElement != null) @@ -174,5 +136,18 @@ namespace Svg } } } + + private struct ElementInfo + { + public string ElementName { get; set; } + public Type ElementType { get; set; } + + public ElementInfo(string elementName, Type elementType) + : this() + { + this.ElementName = elementName; + this.ElementType = elementType; + } + } } } \ No newline at end of file diff --git a/SvgRenderer.cs b/SvgRenderer.cs index eae2e16..3c933b6 100644 --- a/SvgRenderer.cs +++ b/SvgRenderer.cs @@ -49,7 +49,7 @@ namespace Svg public void SetClip(Region region) { - this._innerGraphics.SetClip(region, CombineMode.Union); + this._innerGraphics.SetClip(region, CombineMode.Complement); } public void FillPath(Brush brush, GraphicsPath path) diff --git a/Text/SvgText.cs b/Text/SvgText.cs index 110b9ae..d099a8d 100644 --- a/Text/SvgText.cs +++ b/Text/SvgText.cs @@ -11,6 +11,7 @@ namespace Svg /// /// The element defines a graphics element consisting of text. /// + [SvgElement("text")] public class SvgText : SvgVisualElement { private SvgUnit _x; -- GitLab