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
/// <summary>
/// The class that all SVG elements should derive from when they are to be rendered.
/// </summary>
public abstract partial class SvgGraphicsElement : SvgElement, ISvgStylable
public abstract partial class SvgGraphicsElement : SvgElement, ISvgStylable, ISvgClipable
{
private bool _dirty;
private bool _requiresSmoothRendering;
private Region _previousClip;
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
......@@ -40,6 +41,16 @@ namespace Svg
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>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
......@@ -66,6 +77,7 @@ namespace Svg
if (this.Path != null && this.Visible)
{
this.PushTransforms(renderer);
this.SetClip(renderer);
// If this element needs smoothing enabled turn anti aliasing on
if (this.RequiresSmoothRendering)
......@@ -104,8 +116,38 @@ namespace Svg
renderer.SmoothingMode = SmoothingMode.Default;
}
this.ResetClip(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
{
public interface ISvgClipable
{
SvgClipPath ClipPath { get; set; }
void SetClip(Graphics graphics);
void ResetClip(Graphics graphics);
/// <summary>
/// Gets or sets the ID of the associated <see cref="SvgClipPath"/> if one has been specified.
/// </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;
namespace Svg
{
/// <summary>
///
/// </summary>
public sealed class SvgClipPath : SvgElement
{
private SvgCoordinateUnits _clipPathUnits;
private bool _pathDirty;
private Region _region;
/// <summary>
///
/// </summary>
[SvgAttribute("clipPathUnits")]
public SvgCoordinateUnits ClipPathUnits
{
......@@ -27,7 +33,11 @@ namespace Svg
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)
{
......@@ -44,18 +54,23 @@ namespace Svg
return _region;
}
/// <summary>
///
/// </summary>
/// <param name="region"></param>
/// <param name="element"></param>
private void ComplementRegion(Region region, SvgElement element)
{
SvgGraphicsElement graphicsElement = element as SvgGraphicsElement;
if (graphicsElement != null)
if (graphicsElement != null && graphicsElement.Path != null)
{
region.Complement(graphicsElement.Path);
}
foreach (SvgElement child in element.Children)
{
ComplementRegion(region, element);
ComplementRegion(region, child);
}
}
......@@ -71,6 +86,10 @@ namespace Svg
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)
{
// Do nothing
......
......@@ -90,6 +90,10 @@ namespace Svg
switch (this.Type)
{
case SvgUnitType.Em:
float points = (float)(this.Value * 9);
_deviceValue = (points / 72) * ppi;
break;
case SvgUnitType.Centimeter:
_deviceValue = (float)((this.Value / cmInInch) * ppi);
break;
......
......@@ -93,6 +93,16 @@ namespace Svg
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>
/// Opens the document at the specified path and loads the contents.
/// </summary>
......
......@@ -46,7 +46,11 @@ namespace Svg
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
......@@ -54,6 +58,17 @@ namespace Svg
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)
{
this.PushTransforms(renderer);
......
......@@ -135,8 +135,11 @@
<Compile Include="Text\SvgTextAnchor.cs" />
<Compile Include="Text\SvgTextSpan.cs" />
<Compile Include="Transforms\ISvgTransformable.cs" />
<Compile Include="Transforms\SvgMatrix.cs" />
<Compile Include="Transforms\SvgRotate.cs" />
<Compile Include="Transforms\SvgScale.cs" />
<Compile Include="Transforms\SvgShear.cs" />
<Compile Include="Transforms\SvgSkew.cs" />
<Compile Include="Transforms\SvgTransform.cs" />
<Compile Include="Transforms\SvgTransformCollection.cs" />
<Compile Include="Transforms\SvgTransformConverter.cs" />
......
......@@ -11,12 +11,19 @@ namespace Svg
{
private List<SvgElement> _elements;
private SvgElement _owner;
private bool _mock;
/// <summary>
/// Initialises a new instance of an <see cref="SvgElementCollection"/> class.
/// </summary>
/// <param name="owner">The owner <see cref="SvgElement"/> of the collection.</param>
internal SvgElementCollection(SvgElement owner)
: this(owner, false)
{
}
internal SvgElementCollection(SvgElement owner, bool mock)
{
if (owner == null)
{
......@@ -25,6 +32,7 @@ namespace Svg
this._elements = new List<SvgElement>();
this._owner = owner;
this._mock = mock;
}
/// <summary>
......@@ -64,15 +72,20 @@ namespace Svg
}
public void Add(SvgElement item)
{
if (!this._mock)
{
if (this._owner.OwnerDocument != null)
{
this._owner.OwnerDocument.IdManager.Add(item);
}
this._elements.Add(item);
item._parent = this._owner;
}
item._parent.OnElementAdded(item, this.Count - 1);
this._elements.Add(item);
}
public void Clear()
......@@ -111,6 +124,9 @@ namespace Svg
if (removed)
{
this._owner.OnElementRemoved(item);
if (!this._mock)
{
item._parent = null;
if (this._owner.OwnerDocument != null)
......@@ -118,6 +134,7 @@ namespace Svg
this._owner.OwnerDocument.IdManager.Remove(item);
}
}
}
return removed;
}
......
......@@ -20,11 +20,20 @@ namespace Svg
/// <returns>An <see cref="SvgElement"/> of one exists with the specified ID; otherwise false.</returns>
public virtual SvgElement GetElementById(string id)
{
if (id.StartsWith("url("))
{
id = id.Substring(4);
id = id.TrimEnd(')');
}
if (id.StartsWith("#"))
{
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)
......
......@@ -19,6 +19,12 @@ namespace Svg
{
}
public Region Clip
{
get { return this._innerGraphics.Clip; }
set { this._innerGraphics.Clip = value; }
}
/// <summary>
/// Creates a new <see cref="SvgRenderer"/> from the specified <see cref="Image"/>.
/// </summary>
......@@ -30,6 +36,11 @@ namespace Svg
return renderer;
}
public void SetClip(Region region)
{
this._innerGraphics.SetClip(region, CombineMode.Union);
}
public void FillPath(Brush brush, GraphicsPath path)
{
this._innerGraphics.FillPath(brush, path);
......
......@@ -4,7 +4,7 @@ using System.Text;
namespace Svg.Transforms
{
public class SvgRotate : SvgTransform
public sealed class SvgRotate : SvgTransform
{
private float angle;
......
......@@ -5,7 +5,7 @@ using System.Drawing.Drawing2D;
namespace Svg.Transforms
{
public class SvgScale : SvgTransform
public sealed class SvgScale : SvgTransform
{
private float scaleFactorX;
private float scaleFactorY;
......
......@@ -20,7 +20,7 @@ namespace Svg.Transforms
if (transforms[i] == ')')
{
yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
transformEnd = i+1;
transformEnd = i + 1;
}
}
}
......@@ -57,7 +57,7 @@ namespace Svg.Transforms
switch (transformName)
{
case "translate":
string[] coords = contents.Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);
string[] coords = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (coords.Length != 2)
{
......@@ -92,6 +92,51 @@ namespace Svg.Transforms
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;
}
}
......
......@@ -4,7 +4,7 @@ using System.Text;
namespace Svg.Transforms
{
public class SvgTranslate : SvgTransform
public sealed class SvgTranslate : SvgTransform
{
private float x;
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