Commit 76fbb491 authored by davescriven's avatar davescriven
Browse files

- Fixed #5650: Support SVG element "clipPath"

- Refactored SvgElementFactory to use the new SvgElementAttribute to get available elements.
parent c912ea85
...@@ -9,6 +9,10 @@ using Svg.Transforms; ...@@ -9,6 +9,10 @@ using Svg.Transforms;
namespace Svg namespace Svg
{ {
/// <summary>
/// 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.
/// </summary>
[SvgElement("pattern")]
public sealed class SvgPatternServer : SvgPaintServer, ISvgViewPort public sealed class SvgPatternServer : SvgPaintServer, ISvgViewPort
{ {
private SvgUnit _width; private SvgUnit _width;
...@@ -17,6 +21,10 @@ namespace Svg ...@@ -17,6 +21,10 @@ namespace Svg
private SvgUnit _y; private SvgUnit _y;
private SvgViewBox _viewBox; private SvgViewBox _viewBox;
/// <summary>
/// Specifies a supplemental transformation which is applied on top of any
/// transformations necessary to create a new pattern coordinate system.
/// </summary>
[SvgAttribute("viewBox")] [SvgAttribute("viewBox")]
public SvgViewBox ViewBox public SvgViewBox ViewBox
{ {
...@@ -24,6 +32,9 @@ namespace Svg ...@@ -24,6 +32,9 @@ namespace Svg
set { this._viewBox = value; } set { this._viewBox = value; }
} }
/// <summary>
/// Gets or sets the width of the pattern.
/// </summary>
[SvgAttribute("width")] [SvgAttribute("width")]
public SvgUnit Width public SvgUnit Width
{ {
...@@ -31,6 +42,9 @@ namespace Svg ...@@ -31,6 +42,9 @@ namespace Svg
set { this._width = value; } set { this._width = value; }
} }
/// <summary>
/// Gets or sets the height of the pattern.
/// </summary>
[SvgAttribute("height")] [SvgAttribute("height")]
public SvgUnit Height public SvgUnit Height
{ {
...@@ -38,6 +52,9 @@ namespace Svg ...@@ -38,6 +52,9 @@ namespace Svg
set { this._height = value; } set { this._height = value; }
} }
/// <summary>
/// Gets or sets the X-axis location of the pattern.
/// </summary>
[SvgAttribute("x")] [SvgAttribute("x")]
public SvgUnit X public SvgUnit X
{ {
...@@ -45,6 +62,9 @@ namespace Svg ...@@ -45,6 +62,9 @@ namespace Svg
set { this._x = value; } set { this._x = value; }
} }
/// <summary>
/// Gets or sets the Y-axis location of the pattern.
/// </summary>
[SvgAttribute("y")] [SvgAttribute("y")]
public SvgUnit Y public SvgUnit Y
{ {
...@@ -52,6 +72,9 @@ namespace Svg ...@@ -52,6 +72,9 @@ namespace Svg
set { this._y = value; } set { this._y = value; }
} }
/// <summary>
/// Initializes a new instance of the <see cref="SvgPatternServer"/> class.
/// </summary>
public SvgPatternServer() public SvgPatternServer()
{ {
this._x = new SvgUnit(0.0f); this._x = new SvgUnit(0.0f);
...@@ -60,6 +83,11 @@ namespace Svg ...@@ -60,6 +83,11 @@ namespace Svg
this._height = new SvgUnit(0.0f); this._height = new SvgUnit(0.0f);
} }
/// <summary>
/// Gets a <see cref="Brush"/> representing the current paint server.
/// </summary>
/// <param name="styleOwner">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param>
public override Brush GetBrush(SvgVisualElement renderingElement, float opacity) public override Brush GetBrush(SvgVisualElement renderingElement, float opacity)
{ {
// If there aren't any children, return null // If there aren't any children, return null
......
...@@ -6,6 +6,7 @@ using System.Drawing.Drawing2D; ...@@ -6,6 +6,7 @@ using System.Drawing.Drawing2D;
namespace Svg namespace Svg
{ {
[SvgElement("radialGradient")]
public sealed class SvgRadialGradientServer : SvgGradientServer public sealed class SvgRadialGradientServer : SvgGradientServer
{ {
[SvgAttribute("cx")] [SvgAttribute("cx")]
......
...@@ -13,6 +13,7 @@ namespace Svg ...@@ -13,6 +13,7 @@ namespace Svg
/// <summary> /// <summary>
/// Represents an SVG path element. /// Represents an SVG path element.
/// </summary> /// </summary>
[SvgElement("path")]
public class SvgPath : SvgVisualElement public class SvgPath : SvgVisualElement
{ {
private SvgPathSegmentList _pathData; private SvgPathSegmentList _pathData;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>TRACE;DEBUG;REFLECTION</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
<Compile Include="Basic Shapes\SvgPolygon.cs" /> <Compile Include="Basic Shapes\SvgPolygon.cs" />
<Compile Include="Basic Shapes\SvgPolyline.cs" /> <Compile Include="Basic Shapes\SvgPolyline.cs" />
<Compile Include="Clipping and Masking\ISvgClipable.cs" /> <Compile Include="Clipping and Masking\ISvgClipable.cs" />
<Compile Include="Clipping and Masking\SvgClipRule.cs" />
<Compile Include="Clipping and Masking\SvgClipPath.cs" /> <Compile Include="Clipping and Masking\SvgClipPath.cs" />
<Compile Include="Clipping and Masking\SvgMask.cs" /> <Compile Include="Clipping and Masking\SvgMask.cs" />
<Compile Include="DataTypes\ISvgViewPort.cs" /> <Compile Include="DataTypes\ISvgViewPort.cs" />
...@@ -90,6 +91,7 @@ ...@@ -90,6 +91,7 @@
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" /> <Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\SvgGaussianBlur.cs" /> <Compile Include="Filter Effects\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\SvgMerge.cs" /> <Compile Include="Filter Effects\SvgMerge.cs" />
<Compile Include="SvgElementAttribute.cs" />
<Compile Include="SvgRenderer.cs" /> <Compile Include="SvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" /> <Compile Include="Painting\SvgColourConverter.cs" />
<Compile Include="Painting\SvgGradientSpreadMethod.cs" /> <Compile Include="Painting\SvgGradientSpreadMethod.cs" />
......
...@@ -5,20 +5,23 @@ using System.ComponentModel; ...@@ -5,20 +5,23 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
/// <summary>
/// Specifies the SVG attribute name of the associated property.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class SvgAttributeAttribute : System.Attribute public class SvgAttributeAttribute : System.Attribute
{ {
private const string SVG_NAMESPACE = "http://www.w3.org/2000/svg"; private const string SVG_NAMESPACE = "http://www.w3.org/2000/svg";
private string _name; private string _name;
private string _namespace; private string _namespace;
public override object TypeId /// <summary>
{ /// When overridden in a derived class, returns a value that indicates whether this instance equals a specified object.
get /// </summary>
{ /// <param name="obj">An <see cref="T:System.Object"/> to compare with this instance of <see cref="T:System.Attribute"/>.</param>
return base.TypeId; /// <returns>
} /// true if this instance equals <paramref name="obj"/>; otherwise, false.
} /// </returns>
public override bool Match(object obj) public override bool Match(object obj)
{ {
SvgAttributeAttribute indicator = obj as SvgAttributeAttribute; SvgAttributeAttribute indicator = obj as SvgAttributeAttribute;
...@@ -33,27 +36,45 @@ namespace Svg ...@@ -33,27 +36,45 @@ namespace Svg
return String.Compare(indicator.Name, this.Name) == 0; return String.Compare(indicator.Name, this.Name) == 0;
} }
/// <summary>
/// Gets the name of the SVG attribute.
/// </summary>
public string Name public string Name
{ {
get { return this._name; } get { return this._name; }
} }
/// <summary>
/// Gets the namespace of the SVG attribute.
/// </summary>
public string NameSpace public string NameSpace
{ {
get { return this._namespace; } get { return this._namespace; }
} }
/// <summary>
/// Initializes a new instance of the <see cref="SvgAttributeAttribute"/> class.
/// </summary>
internal SvgAttributeAttribute() internal SvgAttributeAttribute()
{ {
this._name = String.Empty; this._name = String.Empty;
} }
/// <summary>
/// Initializes a new instance of the <see cref="SvgAttributeAttribute"/> class with the specified attribute name.
/// </summary>
/// <param name="name">The name of the SVG attribute.</param>
internal SvgAttributeAttribute(string name) internal SvgAttributeAttribute(string name)
{ {
this._name = name; this._name = name;
this._namespace = SVG_NAMESPACE; this._namespace = SVG_NAMESPACE;
} }
/// <summary>
/// Initializes a new instance of the <see cref="SvgAttributeAttribute"/> class with the specified SVG attribute name and namespace.
/// </summary>
/// <param name="name">The name of the SVG attribute.</param>
/// <param name="nameSpace">The namespace of the SVG attribute (e.g. http://www.w3.org/2000/svg).</param>
public SvgAttributeAttribute(string name, string nameSpace) public SvgAttributeAttribute(string name, string nameSpace)
{ {
this._name = name; this._name = name;
......
...@@ -35,7 +35,24 @@ namespace Svg ...@@ -35,7 +35,24 @@ namespace Svg
return (TAttributeType)base[attributeName]; return (TAttributeType)base[attributeName];
} }
return default(TAttributeType); return this.GetAttribute<TAttributeType>(attributeName, default(TAttributeType));
}
/// <summary>
/// Gets the attribute with the specified name.
/// </summary>
/// <typeparam name="T">The type of the attribute value.</typeparam>
/// <param name="attributeName">A <see cref="string"/> containing the name of the attribute.</param>
/// <param name="defaultValue">The value to return if a value hasn't already been specified.</param>
/// <returns>The attribute value if available; otherwise the default value of <typeparamref name="T"/>.</returns>
public T GetAttribute<T>(string attributeName, T defaultValue)
{
if (this.ContainsKey(attributeName) && base[attributeName] != null)
{
return (T)base[attributeName];
}
return defaultValue;
} }
/// <summary> /// <summary>
......
...@@ -226,15 +226,29 @@ namespace Svg ...@@ -226,15 +226,29 @@ namespace Svg
{ {
} }
/// <summary>
/// Calls the <see cref="AddElement"/> method with the specified parameters.
/// </summary>
/// <param name="child">The <see cref="SvgElement"/> that has been added.</param>
/// <param name="index">An <see cref="int"/> representing the index where the element was added to the collection.</param>
internal void OnElementAdded(SvgElement child, int index) internal void OnElementAdded(SvgElement child, int index)
{ {
this.AddElement(child, index); this.AddElement(child, index);
} }
/// <summary>
/// Called by the underlying <see cref="SvgElement"/> when an element has been removed from the
/// <see cref="Children"/> collection.
/// </summary>
/// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
protected virtual void RemoveElement(SvgElement child) protected virtual void RemoveElement(SvgElement child)
{ {
} }
/// <summary>
/// Calls the <see cref="RemoveElement"/> method with the specified <see cref="SvgElement"/> as the parameter.
/// </summary>
/// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
internal void OnElementRemoved(SvgElement child) internal void OnElementRemoved(SvgElement child)
{ {
this.RemoveElement(child); this.RemoveElement(child);
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
/// <summary>
/// Specifies the SVG name of an <see cref="SvgElement"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class SvgElementAttribute : Attribute
{
/// <summary>
/// Gets the name of the SVG element.
/// </summary>
public string ElementName { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="SvgElementAttribute"/> class with the specified element name;
/// </summary>
/// <param name="elementName">The name of the SVG element.</param>
public SvgElementAttribute(string elementName)
{
this.ElementName = elementName;
}
}
}
\ No newline at end of file
...@@ -12,6 +12,7 @@ using System.Drawing; ...@@ -12,6 +12,7 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Linq;
using Svg.Transforms; using Svg.Transforms;
...@@ -19,6 +20,25 @@ namespace Svg ...@@ -19,6 +20,25 @@ namespace Svg
{ {
internal class SvgElementFactory internal class SvgElementFactory
{ {
private static List<ElementInfo> availableElements;
private static List<ElementInfo> 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) public static SvgDocument CreateDocument(XmlTextReader reader)
{ {
return (SvgDocument)CreateElement(reader, true, null); return (SvgDocument)CreateElement(reader, true, null);
...@@ -37,76 +57,18 @@ namespace Svg ...@@ -37,76 +57,18 @@ namespace Svg
Trace.TraceInformation("Begin CreateElement: {0}", elementName); Trace.TraceInformation("Begin CreateElement: {0}", elementName);
// Parse element if (elementName == "svg")
switch (elementName) {
{ createdElement = (fragmentIsDocument) ? new SvgDocument() : new SvgFragment();
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 else
{ {
fragment = new SvgDocument(); var validTypes = AvailableElements.Where(e => e.ElementName == elementName);
}
if (validTypes.Count() > 0)
createdElement = (fragmentIsDocument) ? (SvgDocument)fragment : fragment; {
break; createdElement = Activator.CreateInstance(validTypes.First().ElementType) as SvgElement;
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 (createdElement != null) if (createdElement != null)
...@@ -174,5 +136,18 @@ namespace Svg ...@@ -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
...@@ -49,7 +49,7 @@ namespace Svg ...@@ -49,7 +49,7 @@ namespace Svg
public void SetClip(Region region) public void SetClip(Region region)
{ {
this._innerGraphics.SetClip(region, CombineMode.Union); this._innerGraphics.SetClip(region, CombineMode.Complement);
} }
public void FillPath(Brush brush, GraphicsPath path) public void FillPath(Brush brush, GraphicsPath path)
......
...@@ -11,6 +11,7 @@ namespace Svg ...@@ -11,6 +11,7 @@ namespace Svg
/// <summary> /// <summary>
/// The <see cref="SvgText"/> element defines a graphics element consisting of text. /// The <see cref="SvgText"/> element defines a graphics element consisting of text.
/// </summary> /// </summary>
[SvgElement("text")]
public class SvgText : SvgVisualElement public class SvgText : SvgVisualElement
{ {
private SvgUnit _x; private SvgUnit _x;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment