Commit 7a704170 authored by davescriven's avatar davescriven
Browse files

- Fixed #6324: SvgElement.PushTransforms and ViewBox - not necessarily related...

- Fixed #6324: SvgElement.PushTransforms and ViewBox - not necessarily related to ViewBox but every   element was 'resetting' the current graphics transform if the element contained it's own transform. This 
  was a very small fix for a large problem (SvgElement.PushTransforms Matrix transformMatrix = new   Matrix(); changed to Matrix transformMatrix = renderer.Transform; in order to inherit the current   transform.)
- Fixed #6344: Parsing document incorrectly parents elements when it encounters empty nodes which are   in a different namespace. Empty nodes are now ignored and current nodes are closed as required. We'll 
  see how this fix goes.
- Fixed #6381: Units in inches are incorrectly parsed as millimeters - problem was caused by some   copy/paste work.
- Graphics has been replaced by SvgRenderer. This is essentially a wrapper around graphics but will allow
  custom svg related properties in the future when needed.
- Removed ISvgRenderer: A concrete implementation is suitable.
- SvgElement.ElementName has been changed to non-virtual and is set by the parser instead of the   developer having to specify it when developing the class.
- Added more XML API documentation.
parent b12621e2
......@@ -24,7 +24,7 @@ namespace Svg
// If it's pointing to a paint server
if (string.IsNullOrEmpty(value) || value.ToLower().Trim() == "none")
{
return SvgPaintServer.None;
return new SvgColourServer(Color.Transparent);
}
else if (value.IndexOf("url(#") > -1)
{
......
......@@ -74,7 +74,7 @@ namespace Svg
float height = this._height.ToDeviceValue(renderingElement, true);
Bitmap image = new Bitmap((int)width, (int)height);
using (Graphics graphics = Graphics.FromImage(image))
using (SvgRenderer renderer = SvgRenderer.FromImage(image))
{
Matrix patternMatrix = new Matrix();
......@@ -93,17 +93,17 @@ namespace Svg
patternMatrix.Scale(this.Width.ToDeviceValue() / this.ViewBox.Width, this.Height.ToDeviceValue() / this.ViewBox.Height);
}
graphics.Transform = patternMatrix;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
renderer.Transform = patternMatrix;
renderer.CompositingQuality = CompositingQuality.HighQuality;
renderer.SmoothingMode = SmoothingMode.AntiAlias;
renderer.PixelOffsetMode = PixelOffsetMode.Half;
foreach (SvgElement child in this.Children)
{
child.RenderElement(graphics);
child.RenderElement(renderer);
}
graphics.Save();
renderer.Save();
}
TextureBrush textureBrush = new TextureBrush(image);
......
......@@ -50,14 +50,6 @@ namespace Svg
{
}
/// <summary>
/// Gets the name of the element.
/// </summary>
protected override string ElementName
{
get { return "radialGradient"; }
}
public override Brush GetBrush(SvgGraphicsElement renderingElement, float opacity)
{
GraphicsPath path = new GraphicsPath();
......
......@@ -10,13 +10,18 @@ using Svg.Pathing;
namespace Svg
{
[Serializable()]
/// <summary>
/// Represents an SVG path element.
/// </summary>
public class SvgPath : SvgGraphicsElement
{
private SvgPathSegmentList _pathData;
private GraphicsPath _path;
private int _pathLength;
/// <summary>
/// Gets or sets a <see cref="SvgPathSegmentList"/> of path data.
/// </summary>
[SvgAttribute("d")]
public SvgPathSegmentList PathData
{
......@@ -29,6 +34,9 @@ namespace Svg
}
}
/// <summary>
/// Gets or sets the length of the path.
/// </summary>
[SvgAttribute("pathLength")]
public int PathLength
{
......@@ -63,21 +71,26 @@ namespace Svg
this.IsPathDirty = true;
}
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
protected override bool RequiresSmoothRendering
{
get { return true; }
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override System.Drawing.RectangleF Bounds
{
get { return this.Path.GetBounds(); }
}
protected override string ElementName
{
get { return "path"; }
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgPath"/> class.
/// </summary>
public SvgPath()
{
this._pathData = new SvgPathSegmentList();
......
......@@ -11,10 +11,16 @@ namespace Svg
{
internal class SvgPathBuilder : TypeConverter
{
/// <summary>
/// Parses the specified string into a collection of path segments.
/// </summary>
/// <param name="path">A <see cref="string"/> containing path data.</param>
public static SvgPathSegmentList Parse(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
var segments = new SvgPathSegmentList();
......@@ -119,9 +125,9 @@ namespace Svg
}
}
}
catch
catch (Exception exc)
{
Trace.TraceError("Error parsing path \"{0}\".", path);
Trace.TraceError("Error parsing path \"{0}\": {1}", path, exc.Message);
}
return segments;
......
......@@ -90,7 +90,7 @@
<Compile Include="Filter Effects\SvgFilterPrimitive.cs" />
<Compile Include="Filter Effects\SvgGaussianBlur.cs" />
<Compile Include="Filter Effects\SvgMerge.cs" />
<Compile Include="ISvgRenderer.cs" />
<Compile Include="SvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" />
<Compile Include="Painting\SvgGradientSpreadMethod.cs" />
<Compile Include="SvgDtdResolver.cs" />
......
......@@ -25,9 +25,10 @@ namespace Svg
/// <summary>
/// Gets the name of the element.
/// </summary>
protected virtual string ElementName
protected internal string ElementName
{
get { return this._elementName; }
internal set { this._elementName = value; }
}
/// <summary>
......@@ -67,7 +68,6 @@ namespace Svg
/// <summary>
/// Gets a value to determine whether the element has children.
/// </summary>
/// <returns></returns>
public virtual bool HasChildren()
{
return (this.Children.Count > 0);
......@@ -123,9 +123,13 @@ namespace Svg
}
}
protected internal virtual void PushTransforms(Graphics graphics)
/// <summary>
/// Applies the required transforms to <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
protected internal virtual void PushTransforms(SvgRenderer renderer)
{
_graphicsMatrix = graphics.Transform;
_graphicsMatrix = renderer.Transform;
// Return if there are no transforms
if (this.Transforms == null || this.Transforms.Count == 0)
......@@ -133,30 +137,42 @@ namespace Svg
return;
}
Matrix transformMatrix = new Matrix();
Matrix transformMatrix = renderer.Transform;
foreach (SvgTransform transformation in this.Transforms)
{
transformMatrix.Multiply(transformation.Matrix);
}
graphics.Transform = transformMatrix;
renderer.Transform = transformMatrix;
}
protected internal virtual void PopTransforms(Graphics graphics)
/// <summary>
/// Removes any previously applied transforms from the specified <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> that should have transforms removed.</param>
protected internal virtual void PopTransforms(SvgRenderer renderer)
{
graphics.Transform = _graphicsMatrix;
renderer.Transform = _graphicsMatrix;
_graphicsMatrix = null;
}
void ISvgTransformable.PushTransforms(Graphics graphics)
/// <summary>
/// Applies the required transforms to <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
void ISvgTransformable.PushTransforms(SvgRenderer renderer)
{
this.PushTransforms(graphics);
this.PushTransforms(renderer);
}
void ISvgTransformable.PopTransforms(Graphics graphics)
/// <summary>
/// Removes any previously applied transforms from the specified <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> that should have transforms removed.</param>
void ISvgTransformable.PopTransforms(SvgRenderer renderer)
{
this.PopTransforms(graphics);
this.PopTransforms(renderer);
}
/// <summary>
......@@ -200,22 +216,22 @@ namespace Svg
}
}
protected virtual void ElementAdded(SvgElement child, int index)
protected virtual void AddElement(SvgElement child, int index)
{
}
internal void OnElementAdded(SvgElement child, int index)
{
this.ElementAdded(child, index);
this.AddElement(child, index);
}
protected virtual void ElementRemoved(SvgElement child)
protected virtual void RemoveElement(SvgElement child)
{
}
internal void OnElementRemoved(SvgElement child)
{
this.ElementRemoved(child);
this.RemoveElement(child);
}
/// <summary>
......@@ -228,9 +244,13 @@ namespace Svg
this._elementName = string.Empty;
}
public void RenderElement(Graphics graphics)
/// <summary>
/// Renders this element to the <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> that the element should use to render itself.</param>
public void RenderElement(SvgRenderer renderer)
{
this.Render(graphics);
this.Render(renderer);
}
public void WriteElement(XmlTextWriter writer)
......@@ -279,29 +299,43 @@ namespace Svg
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
/// </summary>
/// <param name="graphics">The <see cref="Graphics"/> object to render to.</param>
protected virtual void Render(Graphics graphics)
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected virtual void Render(SvgRenderer renderer)
{
this.PushTransforms(graphics);
this.RenderContents(graphics);
this.PopTransforms(graphics);
this.PushTransforms(renderer);
this.RenderChildren(renderer);
this.PopTransforms(renderer);
}
protected virtual void RenderContents(Graphics graphics)
/// <summary>
/// Renders the children of this <see cref="SvgElement"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> to render the child <see cref="SvgElement"/>s to.</param>
protected virtual void RenderChildren(SvgRenderer renderer)
{
foreach (SvgElement element in this.Children)
{
element.Render(graphics);
element.Render(renderer);
}
}
void ISvgElement.Render(Graphics graphics)
/// <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>
void ISvgElement.Render(SvgRenderer renderer)
{
this.Render(graphics);
this.Render(renderer);
}
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public virtual object Clone()
{
return this.MemberwiseClone();
......@@ -310,6 +344,6 @@ namespace Svg
internal interface ISvgElement
{
void Render(Graphics graphics);
void Render(SvgRenderer renderer);
}
}
\ No newline at end of file
......@@ -35,6 +35,8 @@ namespace Svg
SvgFragment fragment;
string elementName = reader.LocalName;
Trace.TraceInformation("Begin CreateElement: {0}", elementName);
// Parse element
switch (elementName)
{
......@@ -64,9 +66,13 @@ namespace Svg
break;
case "svg":
if (!fragmentIsDocument)
{
fragment = new SvgFragment();
}
else
{
fragment = new SvgDocument();
}
createdElement = (fragmentIsDocument) ? (SvgDocument)fragment : fragment;
break;
......@@ -99,16 +105,25 @@ namespace Svg
break;
default:
// Do nothing - unsupported
return null;
createdElement = null;
break;
}
SetAttributes(createdElement, reader, document);
if (createdElement != null)
{
createdElement.ElementName = elementName;
SetAttributes(createdElement, reader, document);
}
Trace.TraceInformation("End CreateElement");
return createdElement;
}
private static void SetAttributes(SvgElement element, XmlTextReader reader, SvgDocument document)
{
Trace.TraceInformation("Begin SetAttributes");
string[] styles = null;
string[] style = null;
int i = 0;
......@@ -136,11 +151,13 @@ namespace Svg
SetPropertyValue(element, reader.LocalName, reader.Value, document);
}
Trace.TraceInformation("End SetAttributes");
}
private static void SetPropertyValue(SvgElement element, string attributeName, string attributeValue, SvgDocument document)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(element.GetType(), new SvgAttributeAttribute[] { new SvgAttributeAttribute(attributeName) });
var properties = TypeDescriptor.GetProperties(element.GetType(), new SvgAttributeAttribute[] { new SvgAttributeAttribute(attributeName) });
PropertyDescriptor descriptor = null;
TypeConverter converter = null;
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace Svg
{
public sealed class SvgRenderer : IDisposable
{
private Graphics _innerGraphics;
/// <summary>
/// Initializes a new instance of the <see cref="SvgRenderer"/> class.
/// </summary>
private SvgRenderer()
{
}
/// <summary>
/// Creates a new <see cref="SvgRenderer"/> from the specified <see cref="Image"/>.
/// </summary>
/// <param name="image"><see cref="Image"/> from which to create the new <see cref="SvgRenderer"/>.</param>
public static SvgRenderer FromImage(Image image)
{
SvgRenderer renderer = new SvgRenderer();
renderer._innerGraphics = Graphics.FromImage(image);
return renderer;
}
public void FillPath(Brush brush, GraphicsPath path)
{
this._innerGraphics.FillPath(brush, path);
}
public void DrawPath(Pen pen, GraphicsPath path)
{
this._innerGraphics.DrawPath(pen, path);
}
public void TranslateTransform(float dx, float dy, MatrixOrder order)
{
this._innerGraphics.TranslateTransform(dx, dy, order);
}
public void TranslateTransform(float dx, float dy)
{
this.TranslateTransform(dx, dy, MatrixOrder.Append);
}
public void ScaleTransform(float sx, float sy, MatrixOrder order)
{
this._innerGraphics.ScaleTransform(sx, sy, order);
}
public void ScaleTransform(float sx, float sy)
{
this.ScaleTransform(sx, sy, MatrixOrder.Append);
}
public SmoothingMode SmoothingMode
{
get { return this._innerGraphics.SmoothingMode; }
set { this._innerGraphics.SmoothingMode = value; }
}
public PixelOffsetMode PixelOffsetMode
{
get { return this._innerGraphics.PixelOffsetMode; }
set { this._innerGraphics.PixelOffsetMode = value; }
}
public CompositingQuality CompositingQuality
{
get { return this._innerGraphics.CompositingQuality; }
set { this._innerGraphics.CompositingQuality = value; }
}
public TextRenderingHint TextRenderingHint
{
get { return this._innerGraphics.TextRenderingHint; }
set { this._innerGraphics.TextRenderingHint = value; }
}
public int TextContrast
{
get { return this._innerGraphics.TextContrast; }
set { this._innerGraphics.TextContrast = value; }
}
public Matrix Transform
{
get { return this._innerGraphics.Transform; }
set { this._innerGraphics.Transform = value; }
}
public void Save()
{
this._innerGraphics.Save();
}
public void Dispose()
{
this._innerGraphics.Dispose();
}
}
}
\ No newline at end of file
......@@ -21,7 +21,7 @@ namespace Svg
private Font _font;
private GraphicsPath _path;
private SvgTextAnchor _textAnchor = SvgTextAnchor.Start;
private static readonly Graphics _stringMeasure;
private static readonly SvgRenderer _stringMeasure;
/// <summary>
/// Initializes the <see cref="SvgText"/> class.
......@@ -29,7 +29,7 @@ namespace Svg
static SvgText()
{
Bitmap bitmap = new Bitmap(1, 1);
_stringMeasure = Graphics.FromImage(bitmap);
_stringMeasure = SvgRenderer.FromImage(bitmap);
_stringMeasure.TextRenderingHint = TextRenderingHint.AntiAlias;
}
......@@ -189,16 +189,16 @@ namespace Svg
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary>
/// <param name="graphics">The <see cref="Graphics"/> object to render to.</param>
protected override void Render(Graphics graphics)
protected override void Render(SvgRenderer renderer)
{
base.Render(graphics);
base.Render(renderer);
}
static private int MeasureString(Graphics graphics, string text, Font font)
static private int MeasureString(SvgRenderer renderer, string text, Font font)
{
GraphicsPath p = new GraphicsPath();
p.AddString(text, font.FontFamily, 0, font.Size, new PointF(0.0f, 0.0f), StringFormat.GenericTypographic);
p.Transform(graphics.Transform);
p.Transform(renderer.Transform);
return (int)(p.GetBounds().Width + 1.0f);
}
......@@ -214,6 +214,10 @@ namespace Svg
if (_path == null || this.IsPathDirty && !string.IsNullOrEmpty(this.Text))
{
float fontSize = this.FontSize.ToDeviceValue(this);
if (fontSize == 0.0f)
{
fontSize = 1.0f;
}
int stringWidth;
PointF location = PointF.Empty;
......@@ -268,7 +272,10 @@ namespace Svg
}
else
{
_path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic);
if (!string.IsNullOrEmpty(this.Text))
{
_path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic);
}
}
_path.CloseFigure();
......
......@@ -8,10 +8,24 @@ using Svg.Transforms;
namespace Svg
{
/// <summary>
/// Represents and element that may be transformed.
/// </summary>
public interface ISvgTransformable
{
/// <summary>
/// Gets or sets an <see cref="SvgTransformCollection"/> of element transforms.
/// </summary>
SvgTransformCollection Transforms { get; set; }
void PushTransforms(Graphics graphics);
void PopTransforms(Graphics graphics);
/// <summary>
/// Applies the required transforms to <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
void PushTransforms(SvgRenderer renderer);
/// <summary>
/// Removes any previously applied transforms from the specified <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> that should have transforms removed.</param>
void PopTransforms(SvgRenderer renderer);
}
}
\ No newline at end of file
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