// THIS FILE IS PART OF SVG PROJECT // THE SVG PROJECT IS AN OPENSOURCE LIBRARY LICENSED UNDER THE MS-PL License. // COPYRIGHT (C) svg-net. ALL RIGHTS RESERVED. // GITHUB: https://github.com/svg-net/SVG using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace AntdUI.Svg { public class SvgUse : SvgVisualElement { public override string ClassName { get => "use"; } private Uri _referencedElement; [SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)] public virtual Uri ReferencedElement { get { return _referencedElement; } set { _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 = 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 = 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 = OwnerDocument.IdManager.GetElementById(ReferencedElement); var uris = new List() { ReferencedElement }; return ElementReferencesUri(refElement, uris); } [SvgAttribute("x")] public virtual SvgUnit X { get { return Attributes.GetAttribute("x"); } set { Attributes["x"] = value; } } [SvgAttribute("y")] public virtual SvgUnit Y { get { return Attributes.GetAttribute("y"); } set { Attributes["y"] = value; } } [SvgAttribute("width")] public virtual SvgUnit Width { get { return Attributes.GetAttribute("width"); } set { Attributes["width"] = value; } } [SvgAttribute("height")] public virtual SvgUnit Height { get { return Attributes.GetAttribute("height"); } set { 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(X.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this), Y.ToDeviceValue(renderer, UnitRenderingType.Vertical, this), MatrixOrder.Prepend); return true; } /// /// Initializes a new instance of the class. /// public SvgUse() { X = 0; Y = 0; Width = 0; Height = 0; } public override GraphicsPath Path(ISvgRenderer renderer) { SvgVisualElement element = (SvgVisualElement)OwnerDocument.IdManager.GetElementById(ReferencedElement); return (element != null && !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 RectangleF Bounds { get { var ew = Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this); var eh = Height.ToDeviceValue(null, UnitRenderingType.Vertical, this); if (ew > 0 && eh > 0) return TransformedBounds(new RectangleF(Location.ToDeviceValue(null, this), new SizeF(ew, eh))); var element = OwnerDocument.IdManager.GetElementById(ReferencedElement) as SvgVisualElement; if (element != null) { return element.Bounds; } return new RectangleF(); } } protected override bool Renderable { get { return false; } } protected override void Render(ISvgRenderer renderer) { if (Visible && Displayable && ReferencedElement != null && !HasRecursiveReference() && PushTransforms(renderer)) { SetClip(renderer); var element = OwnerDocument.IdManager.GetElementById(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; } ResetClip(renderer); PopTransforms(renderer); } } } }