Commit f10b0336 authored by Eric Domke's avatar Eric Domke
Browse files

Various Parsing Bug Fixes

- Implemented .Net 3.5 support mostly by removing ISvgEventCaller
functionality in .Net 3.5 build
- Added ability to parse colors such as rgb(#%, #%, #%)
- Fix issues with calculating the next coordinate after a close figure
and a relative move
- Allow the std. deviation in a gaussian blur to be a float.
- Allow "none" for a unit collection
- Allow gradients to reference other gradients defined later in the SVG
- Fix href attribute bug on the SVG use element
- Adding a descendants convenience methods (similar to the Xml to Linq
API)
- Removed non-functional property from the SvgDescription class to
encourage use of the Content property instead
parent 9643cc69
......@@ -53,16 +53,18 @@
this.open.Image = ((System.Drawing.Image)(resources.GetObject("open.Image")));
this.open.ImageTransparentColor = System.Drawing.Color.Magenta;
this.open.Name = "open";
this.open.Size = new System.Drawing.Size(53, 22);
this.open.Size = new System.Drawing.Size(56, 22);
this.open.Text = "Open";
this.open.Click += new System.EventHandler(this.open_Click);
//
// svgImage
//
this.svgImage.Dock = System.Windows.Forms.DockStyle.Left;
this.svgImage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.svgImage.Location = new System.Drawing.Point(0, 25);
this.svgImage.Name = "svgImage";
this.svgImage.Size = new System.Drawing.Size(565, 449);
this.svgImage.Size = new System.Drawing.Size(735, 449);
this.svgImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.svgImage.TabIndex = 1;
this.svgImage.TabStop = false;
......@@ -73,11 +75,13 @@
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(571, 25);
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(741, 25);
this.textBox1.MaxLength = 327670;
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(477, 446);
this.textBox1.Size = new System.Drawing.Size(307, 446);
this.textBox1.TabIndex = 2;
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
//
......@@ -96,6 +100,7 @@
((System.ComponentModel.ISupportInitialize)(this.svgImage)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
......
This diff is collapsed.
......@@ -7,9 +7,8 @@ namespace Svg.DataTypes
{
public enum SvgFontWeight
{
inherit,
normal,
bold
}
}
......@@ -45,6 +45,7 @@ namespace Svg
{
if (value is string)
{
if (string.Compare(((string)value).Trim(), "none", StringComparison.InvariantCultureIgnoreCase) == 0) return null;
string[] points = ((string)value).Trim().Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries);
SvgUnitCollection units = new SvgUnitCollection();
......
......@@ -9,17 +9,9 @@ namespace Svg
[SvgElement("desc")]
public class SvgDescription : SvgElement
{
private string _text;
public string Text
{
get { return this._text; }
set { this._text = value; }
}
public override string ToString()
{
return this.Text;
return this.Content;
}
......@@ -31,7 +23,6 @@ namespace Svg
public override SvgElement DeepCopy<T>()
{
var newObj = base.DeepCopy<T>() as SvgDescription;
newObj.Text = this.Text;
return newObj;
}
......
......@@ -8,6 +8,11 @@ namespace Svg
[SvgElement("title")]
public class SvgTitle : SvgElement
{
public override string ToString()
{
return this.Content;
}
public override SvgElement DeepCopy()
{
return DeepCopy<SvgTitle>();
......
......@@ -13,7 +13,7 @@ namespace Svg
{
private Uri _referencedElement;
[SvgAttribute("xlink:href")]
[SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)]
public virtual Uri ReferencedElement
{
get { return this._referencedElement; }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace Svg
{
public static class Extensions
{
public static IEnumerable<SvgElement> Descendants<T>(this IEnumerable<T> source) where T : SvgElement
{
if (source == null) throw new ArgumentNullException("source");
return GetDescendants<T>(source, false);
}
private static IEnumerable<SvgElement> GetAncestors<T>(IEnumerable<T> source, bool self) where T : SvgElement
{
foreach (var start in source)
{
if (start != null)
{
for (var elem = (self ? start : start.Parent) as SvgElement; elem != null; elem = (elem.Parent as SvgElement))
{
yield return elem;
}
}
}
yield break;
}
private static IEnumerable<SvgElement> GetDescendants<T>(IEnumerable<T> source, bool self) where T : SvgElement
{
var positons = new Stack<int>();
int currPos;
SvgElement currParent;
foreach (var start in source)
{
if (start != null)
{
if (self) yield return start;
positons.Push(0);
currParent = start;
while (positons.Count > 0)
{
currPos = positons.Pop();
if (currPos < currParent.Children.Count)
{
yield return currParent.Children[currPos];
currParent = currParent.Children[currPos];
positons.Push(currPos + 1);
positons.Push(0);
}
else
{
currParent = currParent.Parent;
}
}
}
}
yield break;
}
}
}
\ No newline at end of file
......@@ -14,7 +14,7 @@ namespace Svg.FilterEffects
[SvgElement("feGaussianBlur")]
public class SvgGaussianBlur : SvgFilterPrimitive
{
private int _stdDeviation;
private float _stdDeviation;
private BlurType _blurType;
private int[] _kernel;
......@@ -26,12 +26,13 @@ namespace Svg.FilterEffects
{
}
public SvgGaussianBlur(int stdDeviation)
public SvgGaussianBlur(float stdDeviation)
: this(stdDeviation, BlurType.Both)
{
}
public SvgGaussianBlur(int stdDeviation, BlurType blurType) : base()
public SvgGaussianBlur(float stdDeviation, BlurType blurType)
: base()
{
_stdDeviation = stdDeviation;
_blurType = blurType;
......@@ -42,13 +43,13 @@ namespace Svg.FilterEffects
private void PreCalculate()
{
int sz = _stdDeviation * 2 + 1;
int sz = (int)(_stdDeviation * 2 + 1);
_kernel = new int[sz];
_multable = new int[sz, 256];
for (int i = 1; i <= _stdDeviation; i++)
{
int szi = _stdDeviation - i;
int szj = _stdDeviation + i;
int szi = (int)(_stdDeviation - i);
int szj = (int)(_stdDeviation + i);
_kernel[szj] = _kernel[szi] = (szi + 1) * (szi + 1);
_kernelSum += (_kernel[szj] + _kernel[szi]);
for (int j = 0; j < 256; j++)
......@@ -56,11 +57,11 @@ namespace Svg.FilterEffects
_multable[szj, j] = _multable[szi, j] = _kernel[szj] * j;
}
}
_kernel[_stdDeviation] = (_stdDeviation + 1) * (_stdDeviation + 1);
_kernelSum += _kernel[_stdDeviation];
_kernel[(int)_stdDeviation] = (int)((_stdDeviation + 1) * (_stdDeviation + 1));
_kernelSum += _kernel[(int)_stdDeviation];
for (int j = 0; j < 256; j++)
{
_multable[_stdDeviation, j] = _kernel[_stdDeviation] * j;
_multable[(int)_stdDeviation, j] = _kernel[(int)_stdDeviation] * j;
}
}
......@@ -104,7 +105,7 @@ namespace Svg.FilterEffects
for (int i = 0; i < pixelCount; i++)
{
bsum = gsum = rsum = asum = 0;
read = i - _stdDeviation;
read = (int)(i - _stdDeviation);
for (int z = 0; z < _kernel.Length; z++)
{
if (read < start)
......@@ -156,7 +157,7 @@ namespace Svg.FilterEffects
index = 0;
for (int i = 0; i < src.Height; i++)
{
int y = i - _stdDeviation;
int y = (int)(i - _stdDeviation);
start = y * src.Width;
for (int j = 0; j < src.Width; j++)
{
......@@ -223,12 +224,12 @@ namespace Svg.FilterEffects
/// Gets or sets the radius of the blur (only allows for one value - not the two specified in the SVG Spec)
/// </summary>
[SvgAttribute("stdDeviation")]
public int StdDeviation
public float StdDeviation
{
get { return _stdDeviation; }
set
{
if (value < 1)
if (value <= 0)
{
throw new InvalidOperationException("Radius must be greater then 0");
}
......
......@@ -69,7 +69,18 @@ namespace Svg
alphaValue = (int)alphaDecimal;
}
}
Color colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
Color colorpart;
if (values[0].Trim().EndsWith("%"))
{
colorpart = System.Drawing.Color.FromArgb(alphaValue, (int)(255 * float.Parse(values[0].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[1].Trim().TrimEnd('%')) / 100f),
(int)(255 * float.Parse(values[2].Trim().TrimEnd('%')) / 100f));
}
else
{
colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
}
return colorpart;
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Svg
{
/// <summary>
/// A wrapper for a paint server which isn't defined currently in the parse process, but
/// should be defined by the time the image needs to render.
/// </summary>
public class SvgDeferredPaintServer : SvgPaintServer
{
private bool _serverLoaded = false;
private SvgPaintServer _concreteServer;
public SvgDocument Document { get; set; }
public string DeferredId { get; set; }
public SvgDeferredPaintServer() { }
public SvgDeferredPaintServer(SvgDocument document, string id)
{
this.Document = document;
this.DeferredId = id;
}
private void EnsureServer()
{
if (!_serverLoaded)
{
_concreteServer = this.Document.IdManager.GetElementById(this.DeferredId) as SvgPaintServer;
_serverLoaded = true;
}
}
public override System.Drawing.Brush GetBrush(SvgVisualElement styleOwner, float opacity)
{
EnsureServer();
return _concreteServer.GetBrush(styleOwner, opacity);
}
public override SvgElement DeepCopy()
{
return DeepCopy<SvgDeferredPaintServer>();
}
public override SvgElement DeepCopy<T>()
{
var newObj = base.DeepCopy<T>() as SvgDeferredPaintServer;
newObj.Document = this.Document;
newObj.DeferredId = this.DeferredId;
return newObj;
}
public override bool Equals(object obj)
{
var other = obj as SvgDeferredPaintServer;
if (other == null)
return false;
return this.Document == other.Document && this.DeferredId == other.DeferredId;
}
public override int GetHashCode()
{
if (this.Document == null || this.DeferredId == null) return 0;
return this.Document.GetHashCode() ^ this.DeferredId.GetHashCode();
}
public override string ToString()
{
return (_serverLoaded ? _serverLoaded.ToString() : string.Format("deferred: {0}", this.DeferredId));
}
public static T TryGet<T>(SvgPaintServer server) where T : SvgPaintServer
{
var deferred = server as SvgDeferredPaintServer;
if (deferred == null)
{
return server as T;
}
else
{
return deferred._concreteServer as T;
}
}
}
}
\ No newline at end of file
......@@ -13,7 +13,7 @@ namespace Svg
{
private SvgCoordinateUnits _gradientUnits;
private SvgGradientSpreadMethod _spreadMethod;
private SvgGradientServer _inheritGradient;
private SvgPaintServer _inheritGradient;
private List<SvgGradientStop> _stops;
/// <summary>
......@@ -89,13 +89,12 @@ namespace Svg
/// Gets or sets another gradient fill from which to inherit the stops from.
/// </summary>
[SvgAttribute("href")]
public SvgGradientServer InheritGradient
public SvgPaintServer InheritGradient
{
get { return this._inheritGradient; }
set
{
this._inheritGradient = value;
this.InheritStops();
}
}
......@@ -220,14 +219,12 @@ namespace Svg
return blend;
}
/// <summary>
// If this gradient contains no stops then it will search any inherited gradients for stops.
/// </summary>
protected virtual void InheritStops()
protected void LoadStops()
{
if (this.Stops.Count == 0 && this.InheritGradient != null)
var core = SvgDeferredPaintServer.TryGet<SvgGradientServer>(_inheritGradient);
if (this.Stops.Count == 0 && core != null)
{
_stops.AddRange(this.InheritGradient.Stops);
_stops.AddRange(core.Stops);
}
}
......
......@@ -81,6 +81,7 @@ namespace Svg
public override Brush GetBrush(SvgVisualElement renderingElement, float opacity)
{
LoadStops();
if (IsInvalid)
{
return null;
......
......@@ -38,7 +38,18 @@ namespace Svg
{
return (SvgPaintServer)document.IdManager.GetElementById(value);
}
else // Otherwise try and parse as colour
else if (value.StartsWith("#")) // Otherwise try and parse as colour
{
try
{
return new SvgColourServer((Color)_colourConverter.ConvertFrom(value.Trim()));
}
catch
{
return new SvgDeferredPaintServer(document, value);
}
}
else
{
return new SvgColourServer((Color)_colourConverter.ConvertFrom(value.Trim()));
}
......@@ -49,7 +60,7 @@ namespace Svg
if (value is string)
{
var s = (string) value;
if(String.Equals( s.Trim(), "none", StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(s))
if (String.Equals(s.Trim(), "none", StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(s) || s.Trim().Length < 1)
return SvgPaintServer.None;
else
return SvgPaintServerFactory.Create(s, (SvgDocument)context);
......
......@@ -97,6 +97,7 @@ namespace Svg
public override Brush GetBrush(SvgVisualElement renderingElement, float opacity)
{
LoadStops();
var origin = CalculateOrigin(renderingElement);
var centerPoint = CalculateCenterPoint(renderingElement, origin);
......
......@@ -8,6 +8,14 @@ namespace Svg.Pathing
{
public override void AddToPath(System.Drawing.Drawing2D.GraphicsPath graphicsPath)
{
// Important for custom line caps. Force the path the close with an explicit line, not just an implicit close of the figure.
if (graphicsPath.PathPoints.Length > 1 && !graphicsPath.PathPoints[0].Equals(graphicsPath.PathPoints[graphicsPath.PathPoints.Length - 1]))
{
int i = graphicsPath.PathTypes.Length - 1;
while (i >= 0 && graphicsPath.PathTypes[i] > 0) i--;
if (i < 0) i = 0;
graphicsPath.AddLine(graphicsPath.PathPoints[graphicsPath.PathPoints.Length - 1], graphicsPath.PathPoints[i]);
}
graphicsPath.CloseFigure();
}
......
......@@ -222,9 +222,9 @@ namespace Svg
{
var lastSegment = segments.Last;
// if the last element is a SvgClosePathSegment the position of the previous element should be used because the position of SvgClosePathSegment is 0,0
// if the last element is a SvgClosePathSegment the position of the previous move to should be used because the position of SvgClosePathSegment is 0,0
if (lastSegment is SvgClosePathSegment)
lastSegment = segments[segments.Count - 2];
lastSegment = segments.OfType<SvgMoveToSegment>().Last();
if (isRelativeX)
{
......@@ -290,6 +290,7 @@ namespace Svg
{
if (value is string)
{
if (string.IsNullOrEmpty((string)value)) return new SvgPathSegmentList();
return Parse((string)value);
}
......
......@@ -116,7 +116,9 @@
<Compile Include="Document Structure\SvgTitle.cs" />
<Compile Include="Document Structure\SvgDocumentMetadata.cs" />
<Compile Include="Extensibility\SvgForeignObject.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Painting\ISvgBoundable.cs" />
<Compile Include="Painting\SvgDeferredPaintServer.cs" />
<Compile Include="Painting\SvgMarker.cs" />
<Compile Include="Document Structure\SvgDefinitionList.cs" />
<Compile Include="Document Structure\SvgDescription.cs" />
......
......@@ -241,7 +241,7 @@ namespace Svg
element.Content = value.ToString();
// Reset content value for new element
value.Clear();
value.Length = 0;
}
break;
case XmlNodeType.CDATA:
......@@ -277,9 +277,11 @@ namespace Svg
throw new ArgumentNullException("document");
}
Stream stream = new MemoryStream(UTF8Encoding.Default.GetBytes(document.InnerXml));
using (var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(document.InnerXml)))
{
return Open<SvgDocument>(stream, null);
}
}
public static Bitmap OpenAsBitmap(string path)
{
......
......@@ -117,6 +117,15 @@ namespace Svg
get { return this._children; }
}
public IEnumerable<SvgElement> Descendants()
{
return this.AsEnumerable().Descendants();
}
private IEnumerable<SvgElement> AsEnumerable()
{
yield return this;
}
/// <summary>
/// Gets a value to determine whether the element has children.
/// </summary>
......@@ -763,6 +772,7 @@ namespace Svg
onmouseout = "<anything>"
*/
#if Net4
/// <summary>
/// Use this method to provide your implementation ISvgEventCaller which can register Actions
/// and call them if one of the events occurs. Make sure, that your SvgElement has a unique ID.
......@@ -804,6 +814,7 @@ namespace Svg
caller.UnregisterAction(rpcID + "onmouseout");
}
}
#endif
[SvgAttribute("onclick")]
public event EventHandler<MouseArg> Click;
......@@ -826,11 +837,13 @@ namespace Svg
[SvgAttribute("onmouseout")]
public event EventHandler<MouseArg> MouseOut;
#if Net4
protected Action<float, float, int, int, bool, bool, bool, string> CreateMouseEventAction(Action<object, MouseArg> eventRaiser)
{
return (x, y, button, clickCount, altKey, shiftKey, ctrlKey, sessionID) =>
eventRaiser(this, new MouseArg { x = x, y = y, Button = button, ClickCount = clickCount, AltKey = altKey, ShiftKey = shiftKey, CtrlKey = ctrlKey, SessionID = sessionID });
}
#endif
//click
protected void RaiseMouseClick(object sender, MouseArg e)
......@@ -943,6 +956,7 @@ namespace Svg
public SvgElement BeforeSibling;
}
#if Net4
//deriving class registers event actions and calls the actions if the event occurs
public interface ISvgEventCaller
{
......@@ -957,6 +971,7 @@ namespace Svg
void RegisterAction<T1, T2, T3, T4, T5, T6, T7, T8>(string rpcID, Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
void UnregisterAction(string rpcID);
}
#endif
/// <summary>
/// Represents the state of the mouse at the moment the event occured.
......
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