using System;
using System.Xml;
using SharpVectors.Dom.Css;
namespace SharpVectors.Dom.Svg
{
public class SvgTransformableElement : SvgStyleableElement, ISvgTransformable
{
#region Constructors and Destructor
public SvgTransformableElement(string prefix, string localname, string ns, SvgDocument doc)
: base(prefix, localname, ns, doc)
{
}
#endregion
#region ISvgTransformable Members
private ISvgAnimatedTransformList transform;
public ISvgAnimatedTransformList Transform
{
get
{
if (transform == null)
{
transform = new SvgAnimatedTransformList(GetAttribute("transform"));
}
return transform;
}
}
public ISvgElement NearestViewportElement
{
get
{
XmlNode parent = this.ParentNode;
while (parent != null)
{
if (parent is SvgSvgElement)
{
return (ISvgElement)parent;
}
parent = parent.ParentNode;
}
return null;
}
}
public ISvgElement FarthestViewportElement
{
get
{
ISvgDocument doc = OwnerDocument;
if (doc.RootElement == this) return null;
else return doc.RootElement;
}
}
public ISvgRect GetBBox()
{
ISvgWindow svgWnd = this.OwnerDocument.Window;
if (svgWnd == null || svgWnd.Renderer == null)
{
return null;
}
return svgWnd.Renderer.GetRenderedBounds(this, 0);
}
///
/// For each given element, the accumulation of all transformations that have been defined
/// on the given element and all of its ancestors up to and including the element that
/// established the current viewport (usually, the 'svg' element which is the most
/// immediate ancestor to the given element) is called the current transformation matrix
/// or CTM.
///
/// A matrix representing the mapping of current user coordinates to viewport
/// coordinates.
public ISvgMatrix GetCTM()
{
ISvgMatrix matrix = new SvgMatrix();
ISvgTransformList svgTList;
ISvgMatrix vCTM;
if (this is SvgSvgElement)
{
vCTM = (this as SvgSvgElement).ViewBoxTransform;
matrix = vCTM;
}
else if (this.Transform != null)
{
svgTList = this.Transform.AnimVal;
matrix = svgTList.Consolidate().Matrix;
}
ISvgElement nVE = this.NearestViewportElement;
if (nVE != null)
{
SvgTransformableElement par = ParentNode as SvgTransformableElement;
while (par != null && par != nVE)
{
svgTList = par.Transform.AnimVal;
matrix = svgTList.Consolidate().Matrix.Multiply(matrix);
par = par.ParentNode as SvgTransformableElement;
}
if (par == nVE && nVE is SvgSvgElement)
{
vCTM = (nVE as SvgSvgElement).ViewBoxTransform;
matrix = vCTM.Multiply(matrix);
}
}
return matrix;
}
public ISvgMatrix GetScreenCTM()
{
ISvgMatrix matrix = new SvgMatrix();
ISvgTransformList svgTList;
ISvgMatrix vCTM;
if (this is SvgSvgElement)
{
vCTM = (this as SvgSvgElement).ViewBoxTransform;
matrix = vCTM;
}
else if (this.Transform != null)
{
svgTList = this.Transform.AnimVal;
matrix = svgTList.Consolidate().Matrix;
}
SvgTransformableElement par = ParentNode as SvgTransformableElement;
while (par != null)
{
// TODO: other elements can establish viewports, not just