diff --git a/Source/Document Structure/SvgFragment.cs b/Source/Document Structure/SvgFragment.cs index c17ccdaa5c7d76b53008766f4a901c765ae63198..ef8c813196b7281f7a70b943f618c300f55b5ef6 100644 --- a/Source/Document Structure/SvgFragment.cs +++ b/Source/Document Structure/SvgFragment.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using System.Xml; namespace Svg { @@ -41,7 +42,7 @@ namespace Svg private SvgUnit _x; private SvgUnit _y; - + /// /// Gets or sets the position where the left point of the svg should start. /// @@ -51,10 +52,10 @@ namespace Svg get { return _x; } set { - if(_x != value) + if (_x != value) { _x = value; - OnAttributeChanged(new AttributeEventArgs{ Attribute = "x", Value = value }); + OnAttributeChanged(new AttributeEventArgs { Attribute = "x", Value = value }); } } } @@ -68,10 +69,10 @@ namespace Svg get { return _y; } set { - if(_y != value) + if (_y != value) { _y = value; - OnAttributeChanged(new AttributeEventArgs{ Attribute = "y", Value = value }); + OnAttributeChanged(new AttributeEventArgs { Attribute = "y", Value = value }); } } } @@ -115,7 +116,7 @@ namespace Svg get { return this.Attributes.GetAttribute("viewBox"); } set { this.Attributes["viewBox"] = value; } } - + /// /// Gets or sets the aspect of the viewport. /// @@ -185,29 +186,29 @@ namespace Svg break; } } - + /// /// Gets the for this element. /// /// public GraphicsPath Path { - get - { + get + { var path = new GraphicsPath(); AddPaths(this, path); - + return path; } } - + /// /// Gets the bounds of the svg element. /// /// The bounds. - public RectangleF Bounds - { + public RectangleF Bounds + { get { return this.Path.GetBounds(); @@ -246,7 +247,7 @@ namespace Svg } } - if (isWidthperc) + if (isWidthperc) { w = (bounds.Width + bounds.X) * (Width.Value * 0.01f); } @@ -254,11 +255,11 @@ namespace Svg { w = Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this); } - if (isHeightperc) + if (isHeightperc) { h = (bounds.Height + bounds.Y) * (Height.Value * 0.01f); } - else + else { h = Height.ToDeviceValue(null, UnitRenderingType.Vertical, this); } @@ -282,6 +283,20 @@ namespace Svg return newObj; } + //Override the default behavior, writing out the namespaces. + protected override void WriteStartElement(XmlTextWriter writer) + { + base.WriteStartElement(writer); + foreach (var ns in SvgAttributeAttribute.Namespaces) + { + if (string.IsNullOrEmpty(ns.Key)) + writer.WriteAttributeString("xmlns", ns.Value); + else + writer.WriteAttributeString("xmlns:" + ns.Key, ns.Value); + } + + writer.WriteAttributeString("version", "1.1"); + } } } \ No newline at end of file diff --git a/Source/SvgDocument.cs b/Source/SvgDocument.cs index 2bc106c916ee947670dc3e40328f73fbe0dcf21a..e19a2c9d0765c2d1a2dee373e736c60128f95d60 100644 --- a/Source/SvgDocument.cs +++ b/Source/SvgDocument.cs @@ -11,6 +11,8 @@ using System.Xml; using System.Linq; using ExCSS; using Svg.Css; +using System.Threading; +using System.Globalization; namespace Svg { @@ -488,6 +490,18 @@ namespace Svg //Trace.TraceInformation("End Render"); } + public override void Write(XmlTextWriter writer) + { + //Save previous culture and switch to invariant for writing + var previousCulture = Thread.CurrentThread.CurrentCulture; + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + + base.Write(writer); + + //Switch culture back + Thread.CurrentThread.CurrentCulture = previousCulture; + } + public void Write(Stream stream) { @@ -499,7 +513,7 @@ namespace Svg if (!String.IsNullOrEmpty(this.ExternalCSSHref)) xmlWriter.WriteProcessingInstruction("xml-stylesheet", String.Format("type=\"text/css\" href=\"{0}\"", this.ExternalCSSHref)); - this.WriteElement(xmlWriter); + this.Write(xmlWriter); xmlWriter.Flush(); } diff --git a/Source/SvgElement.cs b/Source/SvgElement.cs index 54680281498db2fd4bf59c745724c067c0c3420b..de729d3e8a1e28355a2d21b16222ba4e2e590312 100644 --- a/Source/SvgElement.cs +++ b/Source/SvgElement.cs @@ -520,16 +520,11 @@ namespace Svg this.Render(renderer); } - public void WriteElement(XmlTextWriter writer) + /// Derrived classes may decide that the element should not be written. For example, the text element shouldn't be written if it's empty. + public virtual bool ShouldWriteElement() { - //Save previous culture and switch to invariant for writing - var previousCulture = Thread.CurrentThread.CurrentCulture; - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - this.Write(writer); - - //Switch culture back - Thread.CurrentThread.CurrentCulture = previousCulture; + //Write any element who has a name. + return (this.ElementName != String.Empty); } protected virtual void WriteStartElement(XmlTextWriter writer) @@ -537,18 +532,8 @@ namespace Svg if (this.ElementName != String.Empty) { writer.WriteStartElement(this.ElementName); - if (this.ElementName == "svg") - { - foreach (var ns in SvgAttributeAttribute.Namespaces) - { - if (string.IsNullOrEmpty(ns.Key)) - writer.WriteAttributeString("xmlns", ns.Value); - else - writer.WriteAttributeString("xmlns:" + ns.Key, ns.Value); - } - writer.WriteAttributeString("version", "1.1"); - } } + this.WriteAttributes(writer); } @@ -677,9 +662,9 @@ namespace Svg return resolved; } - protected virtual void Write(XmlTextWriter writer) + public virtual void Write(XmlTextWriter writer) { - if (this.ElementName != String.Empty) + if (ShouldWriteElement()) { this.WriteStartElement(writer); this.WriteChildren(writer); diff --git a/Source/SvgExtentions.cs b/Source/SvgExtentions.cs index 9a93277e6db3ba45e3bf1a1cacbda828e655e701..333a4bace6091996811e3930efde7974906ecda7 100644 --- a/Source/SvgExtentions.cs +++ b/Source/SvgExtentions.cs @@ -54,7 +54,7 @@ namespace Svg { using (XmlTextWriter xml = new XmlTextWriter(str)) { - elem.WriteElement(xml); + elem.Write(xml); result = str.ToString(); } diff --git a/Source/Text/SvgTextBase.cs b/Source/Text/SvgTextBase.cs index 9db224f181ec9a63b071b31cfb0416b95db9a985..1a07ad636cdafc0772dce2d330809ba66d0268e5 100644 --- a/Source/Text/SvgTextBase.cs +++ b/Source/Text/SvgTextBase.cs @@ -19,7 +19,7 @@ namespace Svg protected SvgUnitCollection _dx = new SvgUnitCollection(); private string _rotate; private List _rotations = new List(); - + /// /// Gets or sets the text to be rendered. /// @@ -143,7 +143,7 @@ namespace Svg { this._rotate = value; this._rotations.Clear(); - this._rotations.AddRange(from r in _rotate.Split(new char[] {',', ' ', '\r', '\n', '\t'}, StringSplitOptions.RemoveEmptyEntries) select float.Parse(r)); + this._rotations.AddRange(from r in _rotate.Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries) select float.Parse(r)); this.IsPathDirty = true; OnAttributeChanged(new AttributeEventArgs { Attribute = "rotate", Value = value }); } @@ -230,14 +230,14 @@ namespace Svg /// The bounds. public override System.Drawing.RectangleF Bounds { - get + get { var path = this.Path(null); foreach (var elem in this.Children.OfType()) { path.AddPath(elem.Path(null), false); } - return path.GetBounds(); + return path.GetBounds(); } } @@ -296,9 +296,9 @@ namespace Svg public override GraphicsPath Path(ISvgRenderer renderer) { //if there is a TSpan inside of this text element then path should not be null (even if this text is empty!) - var nodes = GetContentNodes().Where(x => x is SvgContentNode && - string.IsNullOrEmpty(x.Content.Trim(new[] {'\r', '\n', '\t'}))); - + var nodes = GetContentNodes().Where(x => x is SvgContentNode && + string.IsNullOrEmpty(x.Content.Trim(new[] { '\r', '\n', '\t' }))); + if (_path == null || IsPathDirty || nodes.Count() == 1) { renderer = (renderer ?? SvgRenderer.FromNull()); @@ -913,5 +913,10 @@ namespace Svg } } + /// Empty text elements are not legal - only write this element if it has children. + public override bool ShouldWriteElement() + { + return (this.HasChildren() || this.Nodes.Count > 0); + } } }