Commit 33ccfa70 authored by davescriven's avatar davescriven
Browse files

- Bug fix to SvgHandler that caused exceptions to be thrown when ?raw=true was in the querystring

- Fixed support for text-anchor="middle" and text-anchor="end" for <text/> elements.
- Added more XML API documentation
- Added x attribute and y attribute support to <use/> elements.
parent a37ad025
...@@ -15,9 +15,6 @@ namespace Svg ...@@ -15,9 +15,6 @@ namespace Svg
public class SvgCircle : SvgGraphicsElement public class SvgCircle : SvgGraphicsElement
{ {
private GraphicsPath _path; private GraphicsPath _path;
private SvgUnit _cx;
private SvgUnit _cy;
private SvgUnit _radius;
/// <summary> /// <summary>
/// Gets the center point of the circle. /// Gets the center point of the circle.
...@@ -35,11 +32,14 @@ namespace Svg ...@@ -35,11 +32,14 @@ namespace Svg
[SvgAttribute("cx")] [SvgAttribute("cx")]
public SvgUnit CenterX public SvgUnit CenterX
{ {
get { return this._cx; } get { return this.Attributes.GetAttribute<SvgUnit>("cx"); }
set set
{ {
this._cx = value; if (this.Attributes.GetAttribute<SvgUnit>("cx") != value)
this.IsPathDirty = true; {
this.Attributes["cx"] = value;
this.IsPathDirty = true;
}
} }
} }
...@@ -50,11 +50,14 @@ namespace Svg ...@@ -50,11 +50,14 @@ namespace Svg
[SvgAttribute("cy")] [SvgAttribute("cy")]
public SvgUnit CenterY public SvgUnit CenterY
{ {
get { return this._cy; } get { return this.Attributes.GetAttribute<SvgUnit>("cy"); }
set set
{ {
this._cy = value; if (this.Attributes.GetAttribute<SvgUnit>("cy") != value)
this.IsPathDirty = true; {
this.Attributes["cy"] = value;
this.IsPathDirty = true;
}
} }
} }
...@@ -65,18 +68,20 @@ namespace Svg ...@@ -65,18 +68,20 @@ namespace Svg
[SvgAttribute("r")] [SvgAttribute("r")]
public SvgUnit Radius public SvgUnit Radius
{ {
get { return this._radius; } get { return this.Attributes.GetAttribute<SvgUnit>("r"); }
set set
{ {
this._radius = value; if (this.Attributes.GetAttribute<SvgUnit>("r") != value)
this.IsPathDirty = true; {
this.Attributes["r"] = value;
this.IsPathDirty = true;
}
} }
} }
/// <summary> /// <summary>
/// Gets the name of the element. /// Gets the name of the element.
/// </summary> /// </summary>
/// <value></value>
protected override string ElementName protected override string ElementName
{ {
get { return "circle"; } get { return "circle"; }
...@@ -85,7 +90,7 @@ namespace Svg ...@@ -85,7 +90,7 @@ namespace Svg
/// <summary> /// <summary>
/// Gets the bounds of the circle. /// Gets the bounds of the circle.
/// </summary> /// </summary>
/// <value>The bounds.</value> /// <value>The rectangular bounds of the circle.</value>
public override RectangleF Bounds public override RectangleF Bounds
{ {
get { return this.Path.GetBounds(); } get { return this.Path.GetBounds(); }
...@@ -102,6 +107,9 @@ namespace Svg ...@@ -102,6 +107,9 @@ namespace Svg
get { return true; } get { return true; }
} }
/// <summary>
/// Gets the <see cref="GraphicsPath"/> representing this element.
/// </summary>
public override GraphicsPath Path public override GraphicsPath Path
{ {
get get
......
...@@ -8,42 +8,43 @@ namespace Svg ...@@ -8,42 +8,43 @@ namespace Svg
{ {
public sealed class SvgClipPath : SvgElement public sealed class SvgClipPath : SvgElement
{ {
private SvgCoordinateSystem _clipPathUnits; private SvgCoordinateUnits _clipPathUnits;
private bool _pathDirty; private bool _pathDirty;
private Region _region; private Region _region;
[SvgAttribute("clipPathUnits")] [SvgAttribute("clipPathUnits")]
public SvgCoordinateSystem ClipPathUnits public SvgCoordinateUnits ClipPathUnits
{ {
get { return this._clipPathUnits; } get { return this._clipPathUnits; }
set { this._clipPathUnits = value; } set { this._clipPathUnits = value; }
} }
/// <summary>
/// Initializes a new instance of the <see cref="SvgClipPath"/> class.
/// </summary>
public SvgClipPath() public SvgClipPath()
{ {
this._clipPathUnits = SvgCoordinateSystem.UserSpaceOnUse; this._clipPathUnits = SvgCoordinateUnits.ObjectBoundingBox;
} }
public override string ElementName /// <summary>
/// Gets the name of the element.
/// </summary>
protected override string ElementName
{ {
get { return "clipPath"; } get { return "clipPath"; }
} }
public override object Clone() private Region GetClipRegion()
{
SvgClipPath path = new SvgClipPath();
path._clipPathUnits = this._clipPathUnits;
return path;
}
public Region GetClipRegion()
{ {
if (_region == null || _pathDirty) if (_region == null || _pathDirty)
{ {
_region = new Region(); _region = new Region();
foreach (SvgElement element in this.Children) foreach (SvgElement element in this.Children)
{
ComplementRegion(_region, element); ComplementRegion(_region, element);
}
_pathDirty = false; _pathDirty = false;
} }
...@@ -56,21 +57,25 @@ namespace Svg ...@@ -56,21 +57,25 @@ namespace Svg
SvgGraphicsElement graphicsElement = element as SvgGraphicsElement; SvgGraphicsElement graphicsElement = element as SvgGraphicsElement;
if (graphicsElement != null) if (graphicsElement != 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, element);
}
} }
protected override void AddedElement(SvgElement child, int index) protected override void ElementAdded(SvgElement child, int index)
{ {
base.AddedElement(child, index); base.ElementAdded(child, index);
this._pathDirty = true; this._pathDirty = true;
} }
protected override void RemovedElement(SvgElement child) protected override void ElementRemoved(SvgElement child)
{ {
base.RemovedElement(child); base.ElementRemoved(child);
this._pathDirty = true; this._pathDirty = true;
} }
......
...@@ -6,9 +6,5 @@ namespace Svg ...@@ -6,9 +6,5 @@ namespace Svg
{ {
public class SvgMask : SvgElement public class SvgMask : SvgElement
{ {
public override object Clone()
{
throw new Exception("The method or operation is not implemented.");
}
} }
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ namespace Svg ...@@ -17,7 +17,7 @@ namespace Svg
private bool _isEmpty; private bool _isEmpty;
private float? _deviceValue; private float? _deviceValue;
public static readonly SvgUnit Empty = new SvgUnit(0.0f); public static readonly SvgUnit Empty = new SvgUnit();
/// <summary> /// <summary>
/// Gets a value to determine whether the unit is empty. /// Gets a value to determine whether the unit is empty.
...@@ -114,10 +114,14 @@ namespace Svg ...@@ -114,10 +114,14 @@ namespace Svg
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj == null) if (obj == null)
{
return false; return false;
}
if (!(obj.GetType() == typeof(SvgUnit))) if (!(obj.GetType() == typeof(SvgUnit)))
{
return false; return false;
}
SvgUnit unit = (SvgUnit)obj; SvgUnit unit = (SvgUnit)obj;
return (unit.Value == this.Value && unit.Type == this.Type); return (unit.Value == this.Value && unit.Type == this.Type);
......
...@@ -211,7 +211,8 @@ namespace Svg ...@@ -211,7 +211,8 @@ namespace Svg
using (Graphics g = Graphics.FromImage(bitmap)) using (Graphics g = Graphics.FromImage(bitmap))
{ {
g.TextContrast = 0; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.TextContrast = 1;
g.PixelOffsetMode = PixelOffsetMode.Half; g.PixelOffsetMode = PixelOffsetMode.Half;
this.Render(g); this.Render(g);
g.Save(); g.Save();
......
...@@ -4,6 +4,7 @@ using System.Text; ...@@ -4,6 +4,7 @@ using System.Text;
using System.Web; using System.Web;
using System.Xml; using System.Xml;
using System.Xml.Serialization; using System.Xml.Serialization;
using System.Drawing.Drawing2D;
namespace Svg namespace Svg
{ {
...@@ -18,6 +19,26 @@ namespace Svg ...@@ -18,6 +19,26 @@ namespace Svg
set { this._referencedElement = value; } set { this._referencedElement = value; }
} }
[SvgAttribute("x")]
public virtual SvgUnit X
{
get { return this.Attributes.GetAttribute<SvgUnit>("x"); }
set { this.Attributes["x"] = value; }
}
[SvgAttribute("y")]
public virtual SvgUnit Y
{
get { return this.Attributes.GetAttribute<SvgUnit>("y"); }
set { this.Attributes["y"] = value; }
}
protected internal override void PushTransforms(System.Drawing.Graphics graphics)
{
base.PushTransforms(graphics);
graphics.TranslateTransform(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true));
}
public SvgUse() public SvgUse()
{ {
......
...@@ -28,9 +28,8 @@ namespace Svg ...@@ -28,9 +28,8 @@ namespace Svg
{ {
int alpha = (int)((opacity * (this.Colour.A/255) ) * 255); int alpha = (int)((opacity * (this.Colour.A/255) ) * 255);
Color colour = Color.FromArgb(alpha, this.Colour); Color colour = Color.FromArgb(alpha, this.Colour);
SolidBrush brush = new SolidBrush(colour);
return brush; return new SolidBrush(colour);
} }
public override string ToString() public override string ToString()
...@@ -39,7 +38,9 @@ namespace Svg ...@@ -39,7 +38,9 @@ namespace Svg
// Return the name if it exists // Return the name if it exists
if (c.IsKnownColor) if (c.IsKnownColor)
{
return c.Name; return c.Name;
}
// Return the hex value // Return the hex value
return String.Format("#{0}", c.ToArgb().ToString("x").Substring(2)); return String.Format("#{0}", c.ToArgb().ToString("x").Substring(2));
......
...@@ -9,14 +9,14 @@ namespace Svg ...@@ -9,14 +9,14 @@ namespace Svg
{ {
public abstract class SvgGradientServer : SvgPaintServer public abstract class SvgGradientServer : SvgPaintServer
{ {
private SvgGradientUnit _gradientUnits; private SvgCoordinateUnits _gradientUnits;
private SvgGradientSpreadMethod _spreadMethod = SvgGradientSpreadMethod.Pad; private SvgGradientSpreadMethod _spreadMethod = SvgGradientSpreadMethod.Pad;
private SvgGradientServer _inheritGradient; private SvgGradientServer _inheritGradient;
private List<SvgGradientStop> _stops; private List<SvgGradientStop> _stops;
internal SvgGradientServer() internal SvgGradientServer()
{ {
this.GradientUnits = SvgGradientUnit.ObjectBoundingBox; this.GradientUnits = SvgCoordinateUnits.ObjectBoundingBox;
this._stops = new List<SvgGradientStop>(); this._stops = new List<SvgGradientStop>();
} }
...@@ -47,7 +47,7 @@ namespace Svg ...@@ -47,7 +47,7 @@ namespace Svg
} }
[SvgAttribute("gradientUnits")] [SvgAttribute("gradientUnits")]
public SvgGradientUnit GradientUnits public SvgCoordinateUnits GradientUnits
{ {
get { return this._gradientUnits; } get { return this._gradientUnits; }
set { this._gradientUnits = value; } set { this._gradientUnits = value; }
......
...@@ -84,11 +84,13 @@ namespace Svg ...@@ -84,11 +84,13 @@ namespace Svg
{ {
// Need at least 2 colours to do the gradient fill // Need at least 2 colours to do the gradient fill
if (this.Stops.Count < 2) if (this.Stops.Count < 2)
{
return null; return null;
}
PointF start; PointF start;
PointF end; PointF end;
RectangleF bounds = (this.GradientUnits == SvgGradientUnit.ObjectBoundingBox) ? owner.Bounds : owner.OwnerDocument.GetDimensions(); RectangleF bounds = (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox) ? owner.Bounds : owner.OwnerDocument.GetDimensions();
// Have start/end points been set? If not the gradient is horizontal // Have start/end points been set? If not the gradient is horizontal
if (!this.End.IsEmpty()) if (!this.End.IsEmpty())
......
...@@ -64,7 +64,7 @@ namespace Svg ...@@ -64,7 +64,7 @@ namespace Svg
float left = this.CenterX.ToDeviceValue(renderingElement); float left = this.CenterX.ToDeviceValue(renderingElement);
float top = this.CenterY.ToDeviceValue(renderingElement, true); float top = this.CenterY.ToDeviceValue(renderingElement, true);
float radius = this.Radius.ToDeviceValue(renderingElement); float radius = this.Radius.ToDeviceValue(renderingElement);
RectangleF boundingBox = (this.GradientUnits == SvgGradientUnit.ObjectBoundingBox) ? renderingElement.Bounds : renderingElement.OwnerDocument.GetDimensions(); RectangleF boundingBox = (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox) ? renderingElement.Bounds : renderingElement.OwnerDocument.GetDimensions();
path.AddEllipse(left-radius, top-radius, radius*2, radius*2); path.AddEllipse(left-radius, top-radius, radius*2, radius*2);
......
...@@ -71,8 +71,12 @@ ...@@ -71,8 +71,12 @@
<Compile Include="Basic Shapes\SvgLine.cs" /> <Compile Include="Basic Shapes\SvgLine.cs" />
<Compile Include="Basic Shapes\SvgPolygon.cs" /> <Compile Include="Basic Shapes\SvgPolygon.cs" />
<Compile Include="Basic Shapes\SvgPolyline.cs" /> <Compile Include="Basic Shapes\SvgPolyline.cs" />
<Compile Include="Clipping and Masking\ISvgClipable.cs" />
<Compile Include="Clipping and Masking\SvgClipPath.cs" />
<Compile Include="Clipping and Masking\SvgMask.cs" />
<Compile Include="DataTypes\ISvgViewPort.cs" /> <Compile Include="DataTypes\ISvgViewPort.cs" />
<Compile Include="DataTypes\SvgElementStyle.cs" /> <Compile Include="DataTypes\SvgElementStyle.cs" />
<Compile Include="DataTypes\SvgCoordinateUnits.cs" />
<Compile Include="DataTypes\SvgUnitCollection.cs" /> <Compile Include="DataTypes\SvgUnitCollection.cs" />
<Compile Include="DataTypes\SvgViewBox.cs" /> <Compile Include="DataTypes\SvgViewBox.cs" />
<Compile Include="Document Structure\SvgDefinitionList.cs" /> <Compile Include="Document Structure\SvgDefinitionList.cs" />
...@@ -89,7 +93,6 @@ ...@@ -89,7 +93,6 @@
<Compile Include="ISvgRenderer.cs" /> <Compile Include="ISvgRenderer.cs" />
<Compile Include="Painting\SvgColourConverter.cs" /> <Compile Include="Painting\SvgColourConverter.cs" />
<Compile Include="Painting\SvgGradientSpreadMethod.cs" /> <Compile Include="Painting\SvgGradientSpreadMethod.cs" />
<Compile Include="Painting\SvgGradientUnit.cs" />
<Compile Include="SvgDtdResolver.cs" /> <Compile Include="SvgDtdResolver.cs" />
<Compile Include="Exceptions\SvgException.cs" /> <Compile Include="Exceptions\SvgException.cs" />
<Compile Include="Painting\SvgFillRule.cs" /> <Compile Include="Painting\SvgFillRule.cs" />
...@@ -160,7 +163,6 @@ ...@@ -160,7 +163,6 @@
<EmbeddedResource Include="Resources\svg11.dtd" /> <EmbeddedResource Include="Resources\svg11.dtd" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Clipping and Masking\" />
<Folder Include="Web\Resources\" /> <Folder Include="Web\Resources\" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
......
...@@ -15,7 +15,6 @@ namespace Svg ...@@ -15,7 +15,6 @@ namespace Svg
public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable
{ {
internal SvgElement _parent; internal SvgElement _parent;
private string _content;
private string _elementName; private string _elementName;
private SvgAttributeCollection _attributes; private SvgAttributeCollection _attributes;
private EventHandlerList _eventHandlers; private EventHandlerList _eventHandlers;
...@@ -36,8 +35,8 @@ namespace Svg ...@@ -36,8 +35,8 @@ namespace Svg
/// </summary> /// </summary>
public virtual string Content public virtual string Content
{ {
get { return this._content; } get;
set { this._content = value; } set;
} }
/// <summary> /// <summary>
...@@ -93,12 +92,18 @@ namespace Svg ...@@ -93,12 +92,18 @@ namespace Svg
if (Parent == null) if (Parent == null)
{ {
if (this is SvgDocument) if (this is SvgDocument)
{
return (SvgDocument)this; return (SvgDocument)this;
}
else else
{
return null; return null;
}
} }
else else
{
return Parent.OwnerDocument; return Parent.OwnerDocument;
}
} }
} }
...@@ -120,14 +125,14 @@ namespace Svg ...@@ -120,14 +125,14 @@ namespace Svg
protected internal virtual void PushTransforms(Graphics graphics) protected internal virtual void PushTransforms(Graphics graphics)
{ {
_graphicsMatrix = graphics.Transform;
// Return if there are no transforms // Return if there are no transforms
if (this.Transforms == null || this.Transforms.Count == 0) if (this.Transforms == null || this.Transforms.Count == 0)
{ {
return; return;
} }
_graphicsMatrix = graphics.Transform;
Matrix transformMatrix = new Matrix(); Matrix transformMatrix = new Matrix();
foreach (SvgTransform transformation in this.Transforms) foreach (SvgTransform transformation in this.Transforms)
...@@ -140,11 +145,6 @@ namespace Svg ...@@ -140,11 +145,6 @@ namespace Svg
protected internal virtual void PopTransforms(Graphics graphics) protected internal virtual void PopTransforms(Graphics graphics)
{ {
if (this.Transforms == null || this.Transforms.Count == 0 || _graphicsMatrix == null)
{
return;
}
graphics.Transform = _graphicsMatrix; graphics.Transform = _graphicsMatrix;
_graphicsMatrix = null; _graphicsMatrix = null;
} }
...@@ -182,7 +182,9 @@ namespace Svg ...@@ -182,7 +182,9 @@ namespace Svg
{ {
// Don't do anything if it hasn't changed // Don't do anything if it hasn't changed
if (string.Compare(this.ID, value) == 0) if (string.Compare(this.ID, value) == 0)
{
return; return;
}
if (this.OwnerDocument != null) if (this.OwnerDocument != null)
{ {
......
...@@ -52,7 +52,9 @@ namespace Svg ...@@ -52,7 +52,9 @@ namespace Svg
SvgElement element = this[index]; SvgElement element = this[index];
if (element != null) if (element != null)
{
this.Remove(element); this.Remove(element);
}
} }
public SvgElement this[int index] public SvgElement this[int index]
......
...@@ -59,6 +59,9 @@ namespace Svg ...@@ -59,6 +59,9 @@ namespace Svg
case "desc": case "desc":
createdElement = new SvgDescription(); createdElement = new SvgDescription();
break; break;
case "clipPath":
createdElement = new SvgClipPath();
break;
case "svg": case "svg":
if (!fragmentIsDocument) if (!fragmentIsDocument)
fragment = new SvgFragment(); fragment = new SvgFragment();
...@@ -156,132 +159,5 @@ namespace Svg ...@@ -156,132 +159,5 @@ namespace Svg
} }
} }
} }
//private static void SetAttributes(SvgElement element, Dictionary<string, string> attributes, SvgDocument document)
//{
// // Parse attributes
// foreach(KeyValuePair<string, string> keyValuePair in attributes)
// {
// string name = keyValuePair.Key;
// string value = keyValuePair.Value;
// switch (name)
// {
// case "id":
// if (!String.IsNullOrEmpty(value))
// SetProperty(element, name, value);
// break;
// case "style":
// string[] styles = value.Split(';');
// Dictionary<string, string> styleAttributes = new Dictionary<string, string>();
// foreach (string style in styles)
// {
// if (String.IsNullOrEmpty(style) || style.IndexOf(":") == -1)
// continue;
// string[] pair = style.Split(':');
// styleAttributes.Add(pair[0].Trim(), pair[1].Trim());
// }
// SetAttributes(element, styleAttributes, document);
// break;
// case "href":
// if (element is SvgUse)
// SetProperty(element, name, document.GetElementById(value));
// break;
// case "transform":
// SetProperty(element, name, _transformConverter.ConvertFrom(value));
// break;
// case "stroke":
// case "fill":
// SetProperty(element, name, SvgPaintServerFactory.Create(value, document));
// break;
// case "font":
// break;
// case "font-family":
// // TODO: create font family converter, loop through families list. return generic if it's not in the list
// try
// {
// SetProperty(element, name, new FontFamily(value));
// }
// catch
// {
// Trace.TraceWarning("\"{0}\" is not a recognised font.", value);
// SetProperty(element, name, FontFamily.GenericSansSerif);
// }
// break;
// case "font-weight":
// //SetProperty(createdElement, reader.LocalName, reader.Value);
// break;
// case "fill-opacity":
// case "stroke-opacity":
// case "stop-opacity":
// case "opacity":
// SetProperty(element, name, float.Parse(value));
// break;
// case "points":
// // TODO: TypeConverter for this?
// string points = value.Replace(",", " ").Trim();
// Regex spaceReplace = new Regex(@"\s+");
// points = spaceReplace.Replace(points, " ");
// string[] pts = points.Split(' ');
// List<SvgUnit> units = new List<SvgUnit>();
// foreach (string point in pts)
// units.Add((SvgUnit)_unitConverter.ConvertFrom(point));
// SetProperty(element, name, units);
// break;
// case "font-size":
// case "letter-spacing":
// case "word-spacing":
// case "r":
// case "width":
// case "height":
// case "ry":
// case "rx":
// case "x":
// case "y":
// case "x1":
// case "y1":
// case "x2":
// case "y2":
// case "cy":
// case "cx":
// case "offset":
// case "stroke-width":
// SetProperty(element, name, (SvgUnit)_unitConverter.ConvertFrom(value));
// break;
// case "stop-color":
// SetProperty(element, name, (Color)_colourConverter.ConvertFrom(value));
// break;
// case "d":
// SvgPathBuilder.Parse(value, ((SvgPath)element).PathData);
// break;
// case "pathLength":
// SetProperty(element, name, int.Parse(value));
// break;
// default:
// break;
// }
// }
//}
//private static void SetProperty(object element, string attributeName, object attributeValue)
//{
// string key = String.Format("{0}{1}", element.GetType().Name, attributeName);
// if (!_propertyDescriptorLookup.ContainsKey(key))
// {
// PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(element.GetType(), new Attribute[] { new SvgAttributeAttribute(attributeName) });
// if (properties.Count == 0)
// return;
// _propertyDescriptorLookup.Add(key, properties[0]);
// }
// PropertyDescriptor property = _propertyDescriptorLookup[key];
// property.SetValue(element, attributeValue);
//}
} }
} }
\ No newline at end of file
...@@ -21,7 +21,9 @@ namespace Svg ...@@ -21,7 +21,9 @@ namespace Svg
public virtual SvgElement GetElementById(string id) public virtual SvgElement GetElementById(string id)
{ {
if (id.StartsWith("#")) if (id.StartsWith("#"))
{
id = id.Substring(1); id = id.Substring(1);
}
return this._idValueMap[id]; return this._idValueMap[id];
} }
......
...@@ -30,6 +30,7 @@ namespace Svg ...@@ -30,6 +30,7 @@ namespace Svg
{ {
Bitmap bitmap = new Bitmap(1, 1); Bitmap bitmap = new Bitmap(1, 1);
_stringMeasure = Graphics.FromImage(bitmap); _stringMeasure = Graphics.FromImage(bitmap);
_stringMeasure.TextRenderingHint = TextRenderingHint.AntiAlias;
} }
/// <summary> /// <summary>
...@@ -193,6 +194,14 @@ namespace Svg ...@@ -193,6 +194,14 @@ namespace Svg
base.Render(graphics); base.Render(graphics);
} }
static private int MeasureString(Graphics graphics, 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);
return (int)(p.GetBounds().Width + 1.0f);
}
/// <summary> /// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element. /// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary> /// </summary>
...@@ -205,7 +214,7 @@ namespace Svg ...@@ -205,7 +214,7 @@ namespace Svg
if (_path == null || this.IsPathDirty && !string.IsNullOrEmpty(this.Text)) if (_path == null || this.IsPathDirty && !string.IsNullOrEmpty(this.Text))
{ {
float fontSize = this.FontSize.ToDeviceValue(this); float fontSize = this.FontSize.ToDeviceValue(this);
SizeF stringSize = SizeF.Empty; int stringWidth;
PointF location = PointF.Empty; PointF location = PointF.Empty;
// Minus FontSize because the x/y coords mark the bottom left, not bottom top. // Minus FontSize because the x/y coords mark the bottom left, not bottom top.
...@@ -215,12 +224,12 @@ namespace Svg ...@@ -215,12 +224,12 @@ namespace Svg
location = new PointF(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this), this.Y.ToDeviceValue(this, true) - fontSize);
break; break;
case SvgTextAnchor.Middle: case SvgTextAnchor.Middle:
stringSize = _stringMeasure.MeasureString(this.Text, new Font(this._font.FontFamily, fontSize)); stringWidth = SvgText.MeasureString(_stringMeasure, this.Text, new Font(this._font.FontFamily, fontSize));
location = new PointF(this.X.ToDeviceValue(this) - (stringSize.Width / 2), this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this) - (stringWidth / 2), this.Y.ToDeviceValue(this, true) - fontSize);
break; break;
case SvgTextAnchor.End: case SvgTextAnchor.End:
stringSize = _stringMeasure.MeasureString(this.Text, new Font(this._font.FontFamily, fontSize)); stringWidth = SvgText.MeasureString(_stringMeasure, this.Text, new Font(this._font.FontFamily, fontSize));
location = new PointF(this.X.ToDeviceValue(this) - stringSize.Width, this.Y.ToDeviceValue(this, true) - fontSize); location = new PointF(this.X.ToDeviceValue(this) - stringWidth, this.Y.ToDeviceValue(this, true) - fontSize);
break; break;
} }
...@@ -244,12 +253,14 @@ namespace Svg ...@@ -244,12 +253,14 @@ namespace Svg
char[] characters = word.ToCharArray(); char[] characters = word.ToCharArray();
foreach (char currentCharacter in characters) foreach (char currentCharacter in characters)
{ {
_path.AddString(currentCharacter.ToString(), this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault); _path.AddString(currentCharacter.ToString(), this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic);
location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y); location = new PointF(_path.GetBounds().Width + start + letterSpacing, location.Y);
} }
} }
else else
_path.AddString(word, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault); {
_path.AddString(word, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic);
}
// Move the location of the word to be written along // Move the location of the word to be written along
location = new PointF(_path.GetBounds().Width + start + wordSpacing, location.Y); location = new PointF(_path.GetBounds().Width + start + wordSpacing, location.Y);
...@@ -257,7 +268,7 @@ namespace Svg ...@@ -257,7 +268,7 @@ namespace Svg
} }
else else
{ {
_path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericDefault); _path.AddString(this.Text, this._font.FontFamily, 0, fontSize, location, StringFormat.GenericTypographic);
} }
_path.CloseFigure(); _path.CloseFigure();
......
...@@ -93,7 +93,6 @@ namespace Svg.Web ...@@ -93,7 +93,6 @@ namespace Svg.Web
this._state._context.Response.WriteFile(this._state._context.Request.PhysicalPath); this._state._context.Response.WriteFile(this._state._context.Request.PhysicalPath);
this._state._context.Response.End(); this._state._context.Response.End();
this._state.CompleteRequest(); this._state.CompleteRequest();
return;
} }
public void RenderSvg() public void RenderSvg()
...@@ -101,35 +100,38 @@ namespace Svg.Web ...@@ -101,35 +100,38 @@ namespace Svg.Web
this._state._context.Response.AddFileDependency(this._state._context.Request.PhysicalPath); this._state._context.Response.AddFileDependency(this._state._context.Request.PhysicalPath);
this._state._context.Response.Cache.SetLastModifiedFromFileDependencies(); this._state._context.Response.Cache.SetLastModifiedFromFileDependencies();
this._state._context.Response.Cache.SetETagFromFileDependencies(); this._state._context.Response.Cache.SetETagFromFileDependencies();
this._state._context.Response.Buffer = false;
// Allow crawlers to see the raw XML - they can get more information from it that way // Allow crawlers to see the raw XML - they can get more information from it that way
if (this._state._context.Request.Browser.Crawler || !string.IsNullOrEmpty(this._state._context.Request.QueryString["raw"])) if (this._state._context.Request.Browser.Crawler || !string.IsNullOrEmpty(this._state._context.Request.QueryString["raw"]))
{ {
this.RenderRawSvg(); this.RenderRawSvg();
} }
else
try
{ {
SvgDocument document = SvgDocument.Open(this._state._context.Request.PhysicalPath); try
using (Bitmap bitmap = document.Draw())
{ {
using (MemoryStream ms = new MemoryStream()) SvgDocument document = SvgDocument.Open(this._state._context.Request.PhysicalPath);
using (Bitmap bitmap = document.Draw())
{ {
bitmap.Save(ms, ImageFormat.Png); using (MemoryStream ms = new MemoryStream())
this._state._context.Response.ContentType = "image/png"; {
ms.WriteTo(this._state._context.Response.OutputStream); bitmap.Save(ms, ImageFormat.Png);
this._state._context.Response.ContentType = "image/png";
ms.WriteTo(this._state._context.Response.OutputStream);
}
} }
} }
} catch (Exception exc)
catch (Exception exc) {
{ System.Diagnostics.Trace.TraceError("An error occured while attempting to render the SVG image '" + this._state._context.Request.PhysicalPath + "': " + exc.Message);
System.Diagnostics.Trace.TraceError("An error occured while attempting to render the SVG image '" + this._state._context.Request.PhysicalPath + "': " + exc.Message); }
} finally
finally {
{ this._state._context.Response.End();
this._state._context.Response.End(); this._state.CompleteRequest();
this._state.CompleteRequest(); }
} }
} }
} }
...@@ -151,8 +153,7 @@ namespace Svg.Web ...@@ -151,8 +153,7 @@ namespace Svg.Web
/// <param name="context">The <see cref="HttpContext"/> of the request.</param> /// <param name="context">The <see cref="HttpContext"/> of the request.</param>
/// <param name="callback">The delegate to be called when the rendering is complete.</param> /// <param name="callback">The delegate to be called when the rendering is complete.</param>
/// <param name="extraData">The extra data.</param> /// <param name="extraData">The extra data.</param>
public SvgAsyncRenderState(HttpContext context, AsyncCallback callback, public SvgAsyncRenderState(HttpContext context, AsyncCallback callback, object extraData)
object extraData)
{ {
_context = context; _context = context;
_callback = callback; _callback = callback;
...@@ -167,9 +168,9 @@ namespace Svg.Web ...@@ -167,9 +168,9 @@ namespace Svg.Web
_isCompleted = true; _isCompleted = true;
lock (this) lock (this)
{ {
if (_callCompleteEvent != null) if (this.AsyncWaitHandle != null)
{ {
_callCompleteEvent.Set(); this._callCompleteEvent.Set();
} }
} }
// if a callback was registered, invoke it now // if a callback was registered, invoke it now
...@@ -179,8 +180,6 @@ namespace Svg.Web ...@@ -179,8 +180,6 @@ namespace Svg.Web
} }
} }
// IAsyncResult
//
/// <summary> /// <summary>
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
/// </summary> /// </summary>
......
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