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;
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
{
private SvgUnit _width;
......@@ -17,6 +21,10 @@ namespace Svg
private SvgUnit _y;
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")]
public SvgViewBox ViewBox
{
......@@ -24,6 +32,9 @@ namespace Svg
set { this._viewBox = value; }
}
/// <summary>
/// Gets or sets the width of the pattern.
/// </summary>
[SvgAttribute("width")]
public SvgUnit Width
{
......@@ -31,6 +42,9 @@ namespace Svg
set { this._width = value; }
}
/// <summary>
/// Gets or sets the height of the pattern.
/// </summary>
[SvgAttribute("height")]
public SvgUnit Height
{
......@@ -38,6 +52,9 @@ namespace Svg
set { this._height = value; }
}
/// <summary>
/// Gets or sets the X-axis location of the pattern.
/// </summary>
[SvgAttribute("x")]
public SvgUnit X
{
......@@ -45,6 +62,9 @@ namespace Svg
set { this._x = value; }
}
/// <summary>
/// Gets or sets the Y-axis location of the pattern.
/// </summary>
[SvgAttribute("y")]
public SvgUnit Y
{
......@@ -52,6 +72,9 @@ namespace Svg
set { this._y = value; }
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgPatternServer"/> class.
/// </summary>
public SvgPatternServer()
{
this._x = new SvgUnit(0.0f);
......@@ -60,6 +83,11 @@ namespace Svg
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)
{
// If there aren't any children, return null
......
......@@ -6,6 +6,7 @@ using System.Drawing.Drawing2D;
namespace Svg
{
[SvgElement("radialGradient")]
public sealed class SvgRadialGradientServer : SvgGradientServer
{
[SvgAttribute("cx")]
......
......@@ -13,6 +13,7 @@ namespace Svg
/// <summary>
/// Represents an SVG path element.
/// </summary>
[SvgElement("path")]
public class SvgPath : SvgVisualElement
{
private SvgPathSegmentList _pathData;
......
......@@ -37,7 +37,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;REFLECTION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
......@@ -72,6 +72,7 @@
<Compile Include="Basic Shapes\SvgPolygon.cs" />
<Compile Include="Basic Shapes\SvgPolyline.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\SvgMask.cs" />
<Compile Include="DataTypes\ISvgViewPort.cs" />
......@@ -90,6 +91,7 @@
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\SvgMerge.cs" />
<Compile Include="SvgElementAttribute.cs" />
<Compile Include="SvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" />
<Compile Include="Painting\SvgGradientSpreadMethod.cs" />
......
......@@ -5,20 +5,23 @@ using System.ComponentModel;
namespace Svg
{
/// <summary>
/// Specifies the SVG attribute name of the associated property.
/// </summary>
[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;
}
}
/// <summary>
/// When overridden in a derived class, returns a value that indicates whether this instance equals a specified object.
/// </summary>
/// <param name="obj">An <see cref="T:System.Object"/> to compare with this instance of <see cref="T:System.Attribute"/>.</param>
/// <returns>
/// true if this instance equals <paramref name="obj"/>; otherwise, false.
/// </returns>
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;
}
/// <summary>
/// Gets the name of the SVG attribute.
/// </summary>
public string Name
{
get { return this._name; }
}
/// <summary>
/// Gets the namespace of the SVG attribute.
/// </summary>
public string NameSpace
{
get { return this._namespace; }
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgAttributeAttribute"/> class.
/// </summary>
internal SvgAttributeAttribute()
{
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)
{
this._name = name;
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)
{
this._name = name;
......
......@@ -35,7 +35,24 @@ namespace Svg
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>
......
......@@ -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)
{
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)
{
}
/// <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)
{
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;
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<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)
{
return (SvgDocument)CreateElement(reader, true, null);
......@@ -37,76 +57,18 @@ namespace Svg
Trace.TraceInformation("Begin CreateElement: {0}", elementName);
// Parse element
switch (elementName)
{
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();
if (elementName == "svg")
{
createdElement = (fragmentIsDocument) ? new SvgDocument() : new SvgFragment();
}
else
{
fragment = new SvgDocument();
}
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;
var validTypes = AvailableElements.Where(e => e.ElementName == elementName);
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
......@@ -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)
......
......@@ -11,6 +11,7 @@ namespace Svg
/// <summary>
/// The <see cref="SvgText"/> element defines a graphics element consisting of text.
/// </summary>
[SvgElement("text")]
public class SvgText : SvgVisualElement
{
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