Commit c97ef156 authored by davescriven's avatar davescriven
Browse files

- Applied patches 1944, 1955 and 1956.

- Made all transforms (SvgTranslate, SvgMatrix etc) sealed types.
parent 7a704170
...@@ -13,10 +13,11 @@ namespace Svg ...@@ -13,10 +13,11 @@ namespace Svg
/// <summary> /// <summary>
/// The class that all SVG elements should derive from when they are to be rendered. /// The class that all SVG elements should derive from when they are to be rendered.
/// </summary> /// </summary>
public abstract partial class SvgGraphicsElement : SvgElement, ISvgStylable public abstract partial class SvgGraphicsElement : SvgElement, ISvgStylable, ISvgClipable
{ {
private bool _dirty; private bool _dirty;
private bool _requiresSmoothRendering; private bool _requiresSmoothRendering;
private Region _previousClip;
/// <summary> /// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element. /// Gets the <see cref="GraphicsPath"/> for this element.
...@@ -40,6 +41,16 @@ namespace Svg ...@@ -40,6 +41,16 @@ namespace Svg
set { this._dirty = value; } set { this._dirty = value; }
} }
/// <summary>
/// Gets the associated <see cref="SvgClipPath"/> if one has been specified.
/// </summary>
[SvgAttribute("clip-path")]
public virtual Uri ClipPath
{
get { return this.Attributes.GetAttribute<Uri>("clip-path"); }
set { this.Attributes["clip-path"] = value; }
}
/// <summary> /// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered. /// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary> /// </summary>
...@@ -66,6 +77,7 @@ namespace Svg ...@@ -66,6 +77,7 @@ namespace Svg
if (this.Path != null && this.Visible) if (this.Path != null && this.Visible)
{ {
this.PushTransforms(renderer); this.PushTransforms(renderer);
this.SetClip(renderer);
// If this element needs smoothing enabled turn anti aliasing on // If this element needs smoothing enabled turn anti aliasing on
if (this.RequiresSmoothRendering) if (this.RequiresSmoothRendering)
...@@ -104,8 +116,38 @@ namespace Svg ...@@ -104,8 +116,38 @@ namespace Svg
renderer.SmoothingMode = SmoothingMode.Default; renderer.SmoothingMode = SmoothingMode.Default;
} }
this.ResetClip(renderer);
this.PopTransforms(renderer); this.PopTransforms(renderer);
} }
} }
protected internal virtual void SetClip(SvgRenderer renderer)
{
if (this.ClipPath != null)
{
SvgClipPath clipPath = this.OwnerDocument.GetElementById<SvgClipPath>(this.ClipPath.ToString());
this._previousClip = renderer.Clip;
renderer.SetClip(clipPath.GetClipRegion());
}
}
protected internal virtual void ResetClip(SvgRenderer renderer)
{
if (this.ClipPath != null)
{
renderer.SetClip(this._previousClip);
this._previousClip = null;
}
}
void ISvgClipable.SetClip(SvgRenderer renderer)
{
this.SetClip(renderer);
}
void ISvgClipable.ResetClip(SvgRenderer renderer)
{
this.ResetClip(renderer);
}
} }
} }
\ No newline at end of file
...@@ -8,8 +8,11 @@ namespace Svg ...@@ -8,8 +8,11 @@ namespace Svg
{ {
public interface ISvgClipable public interface ISvgClipable
{ {
SvgClipPath ClipPath { get; set; } /// <summary>
void SetClip(Graphics graphics); /// Gets or sets the ID of the associated <see cref="SvgClipPath"/> if one has been specified.
void ResetClip(Graphics graphics); /// </summary>
Uri ClipPath { get; set; }
void SetClip(SvgRenderer renderer);
void ResetClip(SvgRenderer renderer);
} }
} }
\ No newline at end of file
...@@ -6,12 +6,18 @@ using System.Drawing.Drawing2D; ...@@ -6,12 +6,18 @@ using System.Drawing.Drawing2D;
namespace Svg namespace Svg
{ {
/// <summary>
///
/// </summary>
public sealed class SvgClipPath : SvgElement public sealed class SvgClipPath : SvgElement
{ {
private SvgCoordinateUnits _clipPathUnits; private SvgCoordinateUnits _clipPathUnits;
private bool _pathDirty; private bool _pathDirty;
private Region _region; private Region _region;
/// <summary>
///
/// </summary>
[SvgAttribute("clipPathUnits")] [SvgAttribute("clipPathUnits")]
public SvgCoordinateUnits ClipPathUnits public SvgCoordinateUnits ClipPathUnits
{ {
...@@ -27,7 +33,11 @@ namespace Svg ...@@ -27,7 +33,11 @@ namespace Svg
this._clipPathUnits = SvgCoordinateUnits.ObjectBoundingBox; this._clipPathUnits = SvgCoordinateUnits.ObjectBoundingBox;
} }
private Region GetClipRegion() /// <summary>
/// Gets this <see cref="SvgClipPath"/>'s region to be clipped.
/// </summary>
/// <returns>A new <see cref="Region"/> containing the area to be clipped.</returns>
protected internal Region GetClipRegion()
{ {
if (_region == null || _pathDirty) if (_region == null || _pathDirty)
{ {
...@@ -44,18 +54,23 @@ namespace Svg ...@@ -44,18 +54,23 @@ namespace Svg
return _region; return _region;
} }
/// <summary>
///
/// </summary>
/// <param name="region"></param>
/// <param name="element"></param>
private void ComplementRegion(Region region, SvgElement element) private void ComplementRegion(Region region, SvgElement element)
{ {
SvgGraphicsElement graphicsElement = element as SvgGraphicsElement; SvgGraphicsElement graphicsElement = element as SvgGraphicsElement;
if (graphicsElement != null) if (graphicsElement != null && graphicsElement.Path != null)
{ {
region.Complement(graphicsElement.Path); region.Complement(graphicsElement.Path);
} }
foreach (SvgElement child in element.Children) foreach (SvgElement child in element.Children)
{ {
ComplementRegion(region, element); ComplementRegion(region, child);
} }
} }
...@@ -71,6 +86,10 @@ namespace Svg ...@@ -71,6 +86,10 @@ namespace Svg
this._pathDirty = true; this._pathDirty = true;
} }
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected override void Render(SvgRenderer renderer) protected override void Render(SvgRenderer renderer)
{ {
// Do nothing // Do nothing
......
...@@ -90,6 +90,10 @@ namespace Svg ...@@ -90,6 +90,10 @@ namespace Svg
switch (this.Type) switch (this.Type)
{ {
case SvgUnitType.Em:
float points = (float)(this.Value * 9);
_deviceValue = (points / 72) * ppi;
break;
case SvgUnitType.Centimeter: case SvgUnitType.Centimeter:
_deviceValue = (float)((this.Value / cmInInch) * ppi); _deviceValue = (float)((this.Value / cmInInch) * ppi);
break; break;
......
...@@ -93,6 +93,16 @@ namespace Svg ...@@ -93,6 +93,16 @@ namespace Svg
return IdManager.GetElementById(id); return IdManager.GetElementById(id);
} }
/// <summary>
/// Retrieves the <see cref="SvgElement"/> with the specified ID.
/// </summary>
/// <param name="id">A <see cref="string"/> containing the ID of the element to find.</param>
/// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns>
public virtual TSvgElement GetElementById<TSvgElement>(string id) where TSvgElement : SvgElement
{
return (this.GetElementById(id) as TSvgElement);
}
/// <summary> /// <summary>
/// Opens the document at the specified path and loads the contents. /// Opens the document at the specified path and loads the contents.
/// </summary> /// </summary>
......
...@@ -46,7 +46,11 @@ namespace Svg ...@@ -46,7 +46,11 @@ namespace Svg
public override System.Drawing.Drawing2D.GraphicsPath Path public override System.Drawing.Drawing2D.GraphicsPath Path
{ {
get { return null; } get
{
SvgGraphicsElement element = (SvgGraphicsElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement);
return (element != null) ? element.Path : null;
}
} }
public override System.Drawing.RectangleF Bounds public override System.Drawing.RectangleF Bounds
...@@ -54,6 +58,17 @@ namespace Svg ...@@ -54,6 +58,17 @@ namespace Svg
get { return new System.Drawing.RectangleF(); } get { return new System.Drawing.RectangleF(); }
} }
public override SvgElementCollection Children
{
get
{
SvgElement element = this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement);
SvgElementCollection elements = new SvgElementCollection(this, true);
elements.Add(element);
return elements;
}
}
protected override void Render(SvgRenderer renderer) protected override void Render(SvgRenderer renderer)
{ {
this.PushTransforms(renderer); this.PushTransforms(renderer);
......
...@@ -135,8 +135,11 @@ ...@@ -135,8 +135,11 @@
<Compile Include="Text\SvgTextAnchor.cs" /> <Compile Include="Text\SvgTextAnchor.cs" />
<Compile Include="Text\SvgTextSpan.cs" /> <Compile Include="Text\SvgTextSpan.cs" />
<Compile Include="Transforms\ISvgTransformable.cs" /> <Compile Include="Transforms\ISvgTransformable.cs" />
<Compile Include="Transforms\SvgMatrix.cs" />
<Compile Include="Transforms\SvgRotate.cs" /> <Compile Include="Transforms\SvgRotate.cs" />
<Compile Include="Transforms\SvgScale.cs" /> <Compile Include="Transforms\SvgScale.cs" />
<Compile Include="Transforms\SvgShear.cs" />
<Compile Include="Transforms\SvgSkew.cs" />
<Compile Include="Transforms\SvgTransform.cs" /> <Compile Include="Transforms\SvgTransform.cs" />
<Compile Include="Transforms\SvgTransformCollection.cs" /> <Compile Include="Transforms\SvgTransformCollection.cs" />
<Compile Include="Transforms\SvgTransformConverter.cs" /> <Compile Include="Transforms\SvgTransformConverter.cs" />
......
...@@ -11,12 +11,19 @@ namespace Svg ...@@ -11,12 +11,19 @@ namespace Svg
{ {
private List<SvgElement> _elements; private List<SvgElement> _elements;
private SvgElement _owner; private SvgElement _owner;
private bool _mock;
/// <summary> /// <summary>
/// Initialises a new instance of an <see cref="SvgElementCollection"/> class. /// Initialises a new instance of an <see cref="SvgElementCollection"/> class.
/// </summary> /// </summary>
/// <param name="owner">The owner <see cref="SvgElement"/> of the collection.</param> /// <param name="owner">The owner <see cref="SvgElement"/> of the collection.</param>
internal SvgElementCollection(SvgElement owner) internal SvgElementCollection(SvgElement owner)
: this(owner, false)
{
}
internal SvgElementCollection(SvgElement owner, bool mock)
{ {
if (owner == null) if (owner == null)
{ {
...@@ -25,6 +32,7 @@ namespace Svg ...@@ -25,6 +32,7 @@ namespace Svg
this._elements = new List<SvgElement>(); this._elements = new List<SvgElement>();
this._owner = owner; this._owner = owner;
this._mock = mock;
} }
/// <summary> /// <summary>
...@@ -65,14 +73,19 @@ namespace Svg ...@@ -65,14 +73,19 @@ namespace Svg
public void Add(SvgElement item) public void Add(SvgElement item)
{ {
if (this._owner.OwnerDocument != null) if (!this._mock)
{ {
this._owner.OwnerDocument.IdManager.Add(item); if (this._owner.OwnerDocument != null)
{
this._owner.OwnerDocument.IdManager.Add(item);
}
item._parent = this._owner;
} }
this._elements.Add(item);
item._parent = this._owner;
item._parent.OnElementAdded(item, this.Count - 1); item._parent.OnElementAdded(item, this.Count - 1);
this._elements.Add(item);
} }
public void Clear() public void Clear()
...@@ -111,11 +124,15 @@ namespace Svg ...@@ -111,11 +124,15 @@ namespace Svg
if (removed) if (removed)
{ {
this._owner.OnElementRemoved(item); this._owner.OnElementRemoved(item);
item._parent = null;
if (this._owner.OwnerDocument != null) if (!this._mock)
{ {
this._owner.OwnerDocument.IdManager.Remove(item); item._parent = null;
if (this._owner.OwnerDocument != null)
{
this._owner.OwnerDocument.IdManager.Remove(item);
}
} }
} }
......
...@@ -20,11 +20,20 @@ namespace Svg ...@@ -20,11 +20,20 @@ namespace Svg
/// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns> /// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns>
public virtual SvgElement GetElementById(string id) public virtual SvgElement GetElementById(string id)
{ {
if (id.StartsWith("url("))
{
id = id.Substring(4);
id = id.TrimEnd(')');
}
if (id.StartsWith("#")) if (id.StartsWith("#"))
{ {
id = id.Substring(1); id = id.Substring(1);
} }
return this._idValueMap[id];
SvgElement element = null;
this._idValueMap.TryGetValue(id, out element);
return element;
} }
public virtual SvgElement GetElementById(Uri uri) public virtual SvgElement GetElementById(Uri uri)
......
...@@ -19,6 +19,12 @@ namespace Svg ...@@ -19,6 +19,12 @@ namespace Svg
{ {
} }
public Region Clip
{
get { return this._innerGraphics.Clip; }
set { this._innerGraphics.Clip = value; }
}
/// <summary> /// <summary>
/// Creates a new <see cref="SvgRenderer"/> from the specified <see cref="Image"/>. /// Creates a new <see cref="SvgRenderer"/> from the specified <see cref="Image"/>.
/// </summary> /// </summary>
...@@ -30,6 +36,11 @@ namespace Svg ...@@ -30,6 +36,11 @@ namespace Svg
return renderer; return renderer;
} }
public void SetClip(Region region)
{
this._innerGraphics.SetClip(region, CombineMode.Union);
}
public void FillPath(Brush brush, GraphicsPath path) public void FillPath(Brush brush, GraphicsPath path)
{ {
this._innerGraphics.FillPath(brush, path); this._innerGraphics.FillPath(brush, path);
......
...@@ -4,7 +4,7 @@ using System.Text; ...@@ -4,7 +4,7 @@ using System.Text;
namespace Svg.Transforms namespace Svg.Transforms
{ {
public class SvgRotate : SvgTransform public sealed class SvgRotate : SvgTransform
{ {
private float angle; private float angle;
......
...@@ -5,7 +5,7 @@ using System.Drawing.Drawing2D; ...@@ -5,7 +5,7 @@ using System.Drawing.Drawing2D;
namespace Svg.Transforms namespace Svg.Transforms
{ {
public class SvgScale : SvgTransform public sealed class SvgScale : SvgTransform
{ {
private float scaleFactorX; private float scaleFactorX;
private float scaleFactorY; private float scaleFactorY;
......
...@@ -20,7 +20,7 @@ namespace Svg.Transforms ...@@ -20,7 +20,7 @@ namespace Svg.Transforms
if (transforms[i] == ')') if (transforms[i] == ')')
{ {
yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim(); yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
transformEnd = i+1; transformEnd = i + 1;
} }
} }
} }
...@@ -57,7 +57,7 @@ namespace Svg.Transforms ...@@ -57,7 +57,7 @@ namespace Svg.Transforms
switch (transformName) switch (transformName)
{ {
case "translate": case "translate":
string[] coords = contents.Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries); string[] coords = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (coords.Length != 2) if (coords.Length != 2)
{ {
...@@ -92,6 +92,51 @@ namespace Svg.Transforms ...@@ -92,6 +92,51 @@ namespace Svg.Transforms
transformList.Add(new SvgScale(sx)); transformList.Add(new SvgScale(sx));
} }
break;
case "matrix":
string[] points = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (points.Length != 6)
{
throw new FormatException("Matrix transforms must be in the format 'matrix(m11, m12, m21, m22, dx, dy)'");
}
List<float> mPoints = new List<float>();
foreach (string point in points)
{
mPoints.Add(float.Parse(point.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture));
}
transformList.Add(new SvgMatrix(mPoints));
break;
case "shear":
string[] shears = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (shears.Length == 0 || shears.Length > 2)
{
throw new FormatException("Shear transforms must be in the format 'shear(x [,y])'");
}
float hx = float.Parse(shears[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
if (shears.Length > 1)
{
float hy = float.Parse(shears[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
transformList.Add(new SvgShear(hx, hy));
}
else
{
transformList.Add(new SvgShear(hx));
}
break;
case "skewX":
float ax = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
transformList.Add(new SvgSkew(ax, 0));
break;
case "skewY":
float ay = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
transformList.Add(new SvgSkew(0, ay));
break; break;
} }
} }
......
...@@ -4,7 +4,7 @@ using System.Text; ...@@ -4,7 +4,7 @@ using System.Text;
namespace Svg.Transforms namespace Svg.Transforms
{ {
public class SvgTranslate : SvgTransform public sealed class SvgTranslate : SvgTransform
{ {
private float x; private float x;
private float y; private float y;
......
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