diff --git a/Basic Shapes/SvgCircle.cs b/Basic Shapes/SvgCircle.cs index de403b1079a9e222c50dc803a85dea6eda362b85..87637a959eff620c05e0d1127f1f634f62f392f9 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 e5852015c826d40c9aebbb674b27b1d52bec640d..3ec051319133f5969dca827ad7b16fff46f91609 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 aee9e4a37d93ef5317d98819a42ec0e4411623b2..4712869a4021900484350f9d167e702a0eff41cf 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 e57921102c8a765b2b90ec174185c8dc4989420b..9f73f2bec63827b730d46de40e80f1eacebc508e 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 13cbdb391167b2e8985152a595ae20e1a12e4dae..e8b63d170d24a3b9693c8e06efcd5211387afebb 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 9b3c0b565660af4f052a5978e1b9f77d366e8376..53b5138137f810b6c090f414b4dafdbc804a72fb 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 109e5aed38a063a1a1d1a4d5be5d75a41128e911..65cab4f3bbb046e20803042619e8abd9ed9ca29e 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 5130d133607079ba122bb3e9725d4ae2a59e9ec0..dc604fa3fe9f264a9b5d570b6d0e5c0db09e870e 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 be4b68f3ad13a73e86710e495f050d1318efb56c..7703d08fc54d2fa3090ad2096e39c4986e99ebdf 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 0000000000000000000000000000000000000000..9c97b016e5bb106bf08c835cb803fb58fa47daeb --- /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 3346754b7b3c8a96486e699758e68d423883c134..09ced84e3ff7aacaff47db34e760c05bdf47bbb0 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 2d9d0372e0787e8d70ff40c02e1bdcef038d78dd..a3e099d98fc519031ba4eae40a4336a7d20a3f00 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 a996f7c3df4913fa34fe142da9b9a47d5d0e9b51..d9a8b6cefb088b22b45e18242e8bc68c65f4b0d3 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 10db81d62d8c0d438d790f7acb77033e0731d4e1..8da833a95d078066102129792af512b653add650 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 8ea215606f8b9ace1c65dc30d4c10ec2f425d250..4f169b60232ab45e16a5256bc435a96785ae9ef6 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 284ca97e07bf52a1c44d689bab19592399f7d287..4efaf3fae90ec1d8eadb404a68e90a0e20600cc0 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 27d7e707be116c676487a96c44e6a2f836a496a7..062bad2218d3cdb2f55edcbc6a19bd0659c99975 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 3a9055fffbe9555fef331c9d5b8ae26b879d66d8..7fcbf8e1635820e6310a5b65061a182fa3b792e2 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 01ca2d579ece9b4d05c5dd52d6d262997ba7e82b..8aeece0bc1746b1f43b8164aea6facf51292d1b3 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 ce57cfb79d0e658c91d2d65fe9888c3771d10abd..115e7f1c5885c81a761fda2ae9620c32be142abe 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 7deace4d6962c97f5f1acf2d6ad0dfc8956a64f1..95764e86d702671d8e4522c40295191895d95537 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 2afd16a23c5bf699f45502c6e5be187c6abbc01a..779b6c77d2a1b380731acc42cdcbd0ffbe97c717 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 dc5e3ca6d80bee97098047d1db67f6c130018aea..0490ee01cb89887673e9bd41fd8fd6e07cac2a56 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 98fc09e4af9b01e7dd128c19078412663683af61..1e5844ed296ccbcbac8472d1e6664324fda941b6 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 d220df7dabf263c37a82e420bbc91226d222dccf..ace4a4d59063c1541119b0fdc07590bff632aa88 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 3e940a63836860dadca8fd4871a73d46ad50447a..3ad03f1fdde35dbad5600b68dbe1fabd1bf764fd 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 2a3483ddcef7748505ce88c4bd7f812ef8e1d9a6..8ef3e88c24470468107d71cb4cd8301087efe574 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 0000000000000000000000000000000000000000..7162191523833f1afef33dd285cba70f384e751d --- /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 bdc7bff70f96cf3fc84555a31f52ec152128e4c8..b96c1bbb15c640fe0db5a1f0f16522f994530dde 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 eae2e166554714fa07690707bf89b37f921b6ce4..3c933b690c660a515f35cfb9ff8d615321489955 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 110b9ae8fc0bacaeef4a5518db076a3a1cc4cbb1..d099a8dcef4fac8cb6717d1e2b59c26641c7dded 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;