using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Linq;
using Svg.Transforms;
using System.Reflection;
namespace Svg
{
///
/// The base class of which all SVG elements are derived from.
///
public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable
{
internal SvgElement _parent;
private string _elementName;
private SvgAttributeCollection _attributes;
private EventHandlerList _eventHandlers;
private SvgElementCollection _children;
private static readonly object _loadEventKey = new object();
private Matrix _graphicsMatrix;
private Dictionary _customAttributes;
///
/// Gets the name of the element.
///
protected internal string ElementName
{
get
{
if (string.IsNullOrEmpty(this._elementName))
{
var attr = TypeDescriptor.GetAttributes(this).OfType().SingleOrDefault();
if (attr != null)
{
this._elementName = attr.ElementName;
}
}
return this._elementName;
}
internal set { this._elementName = value; }
}
///
/// Gets or sets the content of the element.
///
public virtual string Content
{
get;
set;
}
///
/// Gets an of all events belonging to the element.
///
protected virtual EventHandlerList Events
{
get { return this._eventHandlers; }
}
///
/// Occurs when the element is loaded.
///
public event EventHandler Load
{
add { this.Events.AddHandler(_loadEventKey, value); }
remove { this.Events.RemoveHandler(_loadEventKey, value); }
}
///
/// Gets a collection of all child .
///
public virtual SvgElementCollection Children
{
get { return this._children; }
}
///
/// Gets a value to determine whether the element has children.
///
public virtual bool HasChildren()
{
return (this.Children.Count > 0);
}
///
/// Gets the parent .
///
/// An if one exists; otherwise null.
public virtual SvgElement Parent
{
get { return this._parent; }
}
///
/// Gets the owner .
///
public virtual SvgDocument OwnerDocument
{
get
{
if (Parent == null)
{
if (this is SvgDocument)
{
return (SvgDocument)this;
}
else
{
return null;
}
}
else
{
return Parent.OwnerDocument;
}
}
}
///
/// Gets a collection of element attributes.
///
protected internal virtual SvgAttributeCollection Attributes
{
get
{
if (this._attributes == null)
{
this._attributes = new SvgAttributeCollection(this);
}
return this._attributes;
}
}
public Dictionary CustomAttributes
{
get { return this._customAttributes; }
}
///
/// Applies the required transforms to .
///
/// The to be transformed.
protected internal virtual void PushTransforms(SvgRenderer renderer)
{
_graphicsMatrix = renderer.Transform;
// Return if there are no transforms
if (this.Transforms == null || this.Transforms.Count == 0)
{
return;
}
Matrix transformMatrix = renderer.Transform;
foreach (SvgTransform transformation in this.Transforms)
{
transformMatrix.Multiply(transformation.Matrix, MatrixOrder.Append);
}
renderer.Transform = transformMatrix;
}
///
/// Removes any previously applied transforms from the specified .
///
/// The that should have transforms removed.
protected internal virtual void PopTransforms(SvgRenderer renderer)
{
renderer.Transform = _graphicsMatrix;
_graphicsMatrix = null;
}
///
/// Applies the required transforms to .
///
/// The to be transformed.
void ISvgTransformable.PushTransforms(SvgRenderer renderer)
{
this.PushTransforms(renderer);
}
///
/// Removes any previously applied transforms from the specified .
///
/// The that should have transforms removed.
void ISvgTransformable.PopTransforms(SvgRenderer renderer)
{
this.PopTransforms(renderer);
}
///
/// Gets or sets the element transforms.
///
/// The transforms.
[SvgAttribute("transform")]
public SvgTransformCollection Transforms
{
get { return (this.Attributes.GetAttribute("Transforms") ?? new SvgTransformCollection()); }
set { this.Attributes["Transforms"] = value; }
}
///
/// Gets or sets the ID of the element.
///
/// The ID is already used within the .
[SvgAttribute("id")]
public string ID
{
get { return this.Attributes.GetAttribute("ID"); }
set
{
// Don't do anything if it hasn't changed
if (string.Compare(this.ID, value) == 0)
{
return;
}
if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Remove(this);
}
this.Attributes["ID"] = value;
if (this.OwnerDocument != null)
{
this.OwnerDocument.IdManager.Add(this);
}
}
}
///
/// Called by the underlying when an element has been added to the
/// collection.
///
/// The that has been added.
/// An representing the index where the element was added to the collection.
protected virtual void AddElement(SvgElement child, int index)
{
}
///
/// Calls the method with the specified parameters.
///
/// The that has been added.
/// An representing the index where the element was added to the collection.
internal void OnElementAdded(SvgElement child, int index)
{
this.AddElement(child, index);
}
///
/// Called by the underlying when an element has been removed from the
/// collection.
///
/// The that has been removed.
protected virtual void RemoveElement(SvgElement child)
{
}
///
/// Calls the method with the specified as the parameter.
///
/// The that has been removed.
internal void OnElementRemoved(SvgElement child)
{
this.RemoveElement(child);
}
///
/// Initializes a new instance of the class.
///
public SvgElement()
{
this._children = new SvgElementCollection(this);
this._eventHandlers = new EventHandlerList();
this._elementName = string.Empty;
this._customAttributes = new Dictionary();
}
public virtual void InitialiseFromXML(XmlTextReader reader, SvgDocument document)
{
throw new NotImplementedException();
}
///
/// Renders this element to the .
///
/// The that the element should use to render itself.
public void RenderElement(SvgRenderer renderer)
{
this.Render(renderer);
}
public void WriteElement(XmlTextWriter writer)
{
this.Write(writer);
}
protected virtual void WriteStartElement(XmlTextWriter writer)
{
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);
}
protected virtual void WriteEndElement(XmlTextWriter writer)
{
if (this.ElementName != String.Empty)
{
writer.WriteEndElement();
}
}
protected virtual void WriteAttributes(XmlTextWriter writer)
{
var attributes = from PropertyDescriptor a in TypeDescriptor.GetProperties(this)
let attribute = a.Attributes[typeof(SvgAttributeAttribute)] as SvgAttributeAttribute
where attribute != null
select new { Property = a, Attribute = attribute };
foreach (var attr in attributes)
{
if (attr.Property.Converter.CanConvertTo(typeof(string)))
{
object propertyValue = attr.Property.GetValue(this);
if (propertyValue != null)
{
var type = propertyValue.GetType();
string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
if (!SvgDefaults.IsDefault(attr.Attribute.Name, value))
{
writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
}
}
else if(attr.Attribute.Name == "fill") //if fill equals null, write 'none'
{
string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
}
}
}
//add the custom attributes
foreach (var item in this._customAttributes)
{
writer.WriteAttributeString(item.Key, item.Value);
}
}
protected virtual void Write(XmlTextWriter writer)
{
if (this.ElementName != String.Empty)
{
this.WriteStartElement(writer);
this.WriteChildren(writer);
this.WriteEndElement(writer);
}
}
protected virtual void WriteChildren(XmlTextWriter writer)
{
//write the content
if(!String.IsNullOrEmpty(this.Content))
writer.WriteString(this.Content);
//write all children
foreach (SvgElement child in this.Children)
{
child.Write(writer);
}
}
///
/// Renders the and contents to the specified object.
///
/// The object to render to.
protected virtual void Render(SvgRenderer renderer)
{
this.PushTransforms(renderer);
this.RenderChildren(renderer);
this.PopTransforms(renderer);
}
///
/// Renders the children of this .
///
/// The to render the child s to.
protected virtual void RenderChildren(SvgRenderer renderer)
{
foreach (SvgElement element in this.Children)
{
element.Render(renderer);
}
}
///
/// Renders the and contents to the specified object.
///
/// The object to render to.
void ISvgElement.Render(SvgRenderer renderer)
{
this.Render(renderer);
}
///
/// Recursive method to add up the paths of all children
///
///
///
protected void AddPaths(SvgElement elem, GraphicsPath path)
{
foreach(var child in elem.Children)
{
if (child is SvgVisualElement)
{
if(!(child is SvgGroup))
{
var childPath = ((SvgVisualElement)child).Path;
if (childPath != null)
{
childPath = (GraphicsPath)childPath.Clone();
if(child.Transforms != null)
childPath.Transform(child.Transforms.GetMatrix());
path.AddPath(childPath, false);
}
}
}
AddPaths(child, path);
}
}
///
/// Recursive method to add up the paths of all children
///
///
///
protected GraphicsPath GetPaths(SvgElement elem)
{
var ret = new GraphicsPath();
foreach(var child in elem.Children)
{
if (child is SvgVisualElement)
{
if(!(child is SvgGroup))
{
var childPath = ((SvgVisualElement)child).Path;
if (childPath != null)
{
childPath = (GraphicsPath)childPath.Clone();
if(child.Transforms != null)
childPath.Transform(child.Transforms.GetMatrix());
ret.AddPath(childPath, false);
}
}
else
{
var childPath = GetPaths(child);
if(child.Transforms != null)
childPath.Transform(child.Transforms.GetMatrix());
}
}
}
return ret;
}
///
/// Creates a new object that is a copy of the current instance.
///
///
/// A new object that is a copy of this instance.
///
public virtual object Clone()
{
return this.MemberwiseClone();
}
public abstract SvgElement DeepCopy();
public virtual SvgElement DeepCopy() where T : SvgElement, new()
{
var newObj = new T();
newObj.Content = this.Content;
newObj.ElementName = this.ElementName;
// if (this.Parent != null)
// this.Parent.Children.Add(newObj);
if (this.Transforms != null)
{
newObj.Transforms = new SvgTransformCollection();
foreach (var transform in this.Transforms)
newObj.Transforms.Add(transform.Clone() as SvgTransform);
}
foreach (var child in this.Children)
{
newObj.Children.Add(child.DeepCopy());
}
return newObj;
}
}
internal interface ISvgElement
{
SvgElement Parent {get;}
SvgElementCollection Children { get; }
void Render(SvgRenderer renderer);
}
}