using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace Svg { [SvgElement("use")] public class SvgUse : SvgVisualElement { private Uri _referencedElement; [SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)] public virtual Uri ReferencedElement { get { return this._referencedElement; } set { this._referencedElement = value; } } private bool ElementReferencesUri(SvgElement element, List elementUris) { var useElement = element as SvgUse; if (useElement != null) { if (elementUris.Contains(useElement.ReferencedElement)) { return true; } // also detect cycles in referenced elements var refElement = this.OwnerDocument.IdManager.GetElementById(useElement.ReferencedElement); if (refElement is SvgUse) { elementUris.Add(useElement.ReferencedElement); } return useElement.ReferencedElementReferencesUri(elementUris); } var groupElement = element as SvgGroup; if (groupElement != null) { foreach (var child in groupElement.Children) { if (ElementReferencesUri(child, elementUris)) { return true; } } } return false; } private bool ReferencedElementReferencesUri( List elementUris ) { var refElement = this.OwnerDocument.IdManager.GetElementById(ReferencedElement); return ElementReferencesUri(refElement, elementUris); } /// /// Checks for any direct or indirect recursions in referenced elements, /// including recursions via groups. /// /// True if any recursions are found. private bool HasRecursiveReference() { var refElement = this.OwnerDocument.IdManager.GetElementById(ReferencedElement); var uris = new List() { ReferencedElement }; return ElementReferencesUri(refElement, uris); } [SvgAttribute("x")] public virtual SvgUnit X { get { return this.Attributes.GetAttribute("x"); } set { this.Attributes["x"] = value; } } [SvgAttribute("y")] public virtual SvgUnit Y { get { return this.Attributes.GetAttribute("y"); } set { this.Attributes["y"] = value; } } [SvgAttribute("width")] public virtual SvgUnit Width { get { return this.Attributes.GetAttribute("width"); } set { this.Attributes["width"] = value; } } [SvgAttribute("height")] public virtual SvgUnit Height { get { return this.Attributes.GetAttribute("height"); } set { this.Attributes["height"] = value; } } /// /// Applies the required transforms to . /// /// The to be transformed. protected internal override bool PushTransforms(ISvgRenderer renderer) { if (!base.PushTransforms(renderer)) return false; renderer.TranslateTransform(this.X.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this), this.Y.ToDeviceValue(renderer, UnitRenderingType.Vertical, this), MatrixOrder.Prepend); return true; } /// /// Initializes a new instance of the class. /// public SvgUse() { this.X = 0; this.Y = 0; this.Width = 0; this.Height = 0; } public override System.Drawing.Drawing2D.GraphicsPath Path(ISvgRenderer renderer) { SvgVisualElement element = (SvgVisualElement)this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement); return (element != null && !this.HasRecursiveReference()) ? element.Path(renderer) : null; } /// /// Gets an representing the top left point of the rectangle. /// public SvgPoint Location { get { return new SvgPoint(X, Y); } } /// /// Gets the bounds of the element. /// /// The bounds. public override System.Drawing.RectangleF Bounds { get { var ew = this.Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this); var eh = this.Height.ToDeviceValue(null, UnitRenderingType.Vertical, this); if (ew > 0 && eh > 0) return TransformedBounds(new RectangleF(this.Location.ToDeviceValue(null, this), new SizeF(ew, eh))); var element = this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement) as SvgVisualElement; if (element != null) { return element.Bounds; } return new System.Drawing.RectangleF(); } } protected override bool Renderable { get { return false; } } protected override void Render(ISvgRenderer renderer) { if (this.Visible && this.Displayable && this.ReferencedElement != null && !this.HasRecursiveReference() && this.PushTransforms(renderer)) { this.SetClip(renderer); var element = this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement) as SvgVisualElement; if (element != null) { var ew = Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); var eh = Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); if (ew > 0 && eh > 0) { var viewBox = element.Attributes.GetAttribute("viewBox"); if (viewBox!=SvgViewBox.Empty && Math.Abs(ew - viewBox.Width) > float.Epsilon && Math.Abs(eh - viewBox.Height) > float.Epsilon) { var sw = ew / viewBox.Width; var sh = eh / viewBox.Height; renderer.ScaleTransform(sw, sh, MatrixOrder.Prepend); } } var origParent = element.Parent; element._parent = this; // as the new parent may have other styles that are inherited, // we have to redraw the paths for the children element.InvalidateChildPaths(); element.RenderElement(renderer); element._parent = origParent; } this.ResetClip(renderer); this.PopTransforms(renderer); } } public override SvgElement DeepCopy() { return DeepCopy(); } public override SvgElement DeepCopy() { var newObj = base.DeepCopy() as SvgUse; newObj.ReferencedElement = this.ReferencedElement; newObj.X = this.X; newObj.Y = this.Y; return newObj; } } }