using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Xml; namespace Svg { /// /// An represents an SVG fragment that can be the root element or an embedded fragment of an SVG document. /// [SvgElement("svg")] public class SvgFragment : SvgElement, ISvgViewPort, ISvgBoundable { /// /// Gets the SVG namespace string. /// public static readonly Uri Namespace = new Uri("http://www.w3.org/2000/svg"); PointF ISvgBoundable.Location { get { return PointF.Empty; } } SizeF ISvgBoundable.Size { get { return GetDimensions(); } } RectangleF ISvgBoundable.Bounds { get { return new RectangleF(((ISvgBoundable)this).Location, ((ISvgBoundable)this).Size); } } private SvgUnit _x; private SvgUnit _y; /// /// Gets or sets the position where the left point of the svg should start. /// [SvgAttribute("x")] public SvgUnit X { get { return _x; } set { if (_x != value) { _x = value; OnAttributeChanged(new AttributeEventArgs { Attribute = "x", Value = value }); } } } /// /// Gets or sets the position where the top point of the svg should start. /// [SvgAttribute("y")] public SvgUnit Y { get { return _y; } set { if (_y != value) { _y = value; OnAttributeChanged(new AttributeEventArgs { Attribute = "y", Value = value }); } } } /// /// Gets or sets the width of the fragment. /// /// The width. [SvgAttribute("width")] public SvgUnit Width { get { return this.Attributes.GetAttribute("width"); } set { this.Attributes["width"] = value; } } /// /// Gets or sets the height of the fragment. /// /// The height. [SvgAttribute("height")] public SvgUnit Height { get { return this.Attributes.GetAttribute("height"); } set { this.Attributes["height"] = value; } } [SvgAttribute("overflow")] public virtual SvgOverflow Overflow { get { return this.Attributes.GetAttribute("overflow"); } set { this.Attributes["overflow"] = value; } } /// /// Gets or sets the viewport of the element. /// /// [SvgAttribute("viewBox")] public SvgViewBox ViewBox { get { return this.Attributes.GetAttribute("viewBox"); } set { this.Attributes["viewBox"] = value; } } /// /// Gets or sets the aspect of the viewport. /// /// [SvgAttribute("preserveAspectRatio")] public SvgAspectRatio AspectRatio { get { return this.Attributes.GetAttribute("preserveAspectRatio"); } set { this.Attributes["preserveAspectRatio"] = value; } } /// /// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment. /// [SvgAttribute("font-size")] public override SvgUnit FontSize { get { return (this.Attributes["font-size"] == null) ? SvgUnit.Empty : (SvgUnit)this.Attributes["font-size"]; } set { this.Attributes["font-size"] = value; } } /// /// Indicates which font family is to be used to render the text. /// [SvgAttribute("font-family")] public override string FontFamily { get { return this.Attributes["font-family"] as string; } set { this.Attributes["font-family"] = value; } } /// /// Applies the required transforms to . /// /// The to be transformed. protected internal override bool PushTransforms(ISvgRenderer renderer) { if (!base.PushTransforms(renderer)) return false; this.ViewBox.AddViewBoxTransform(this.AspectRatio, renderer, this); return true; } protected override void Render(ISvgRenderer renderer) { switch (this.Overflow) { case SvgOverflow.Auto: case SvgOverflow.Visible: case SvgOverflow.Inherit: base.Render(renderer); break; default: var prevClip = renderer.GetClip(); try { var size = (this.Parent == null ? renderer.GetBoundable().Bounds.Size : GetDimensions()); var clip = new RectangleF(this.X.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this), this.Y.ToDeviceValue(renderer, UnitRenderingType.Vertical, this), size.Width, size.Height); renderer.SetClip(new Region(clip), CombineMode.Intersect); base.Render(renderer); } finally { renderer.SetClip(prevClip, CombineMode.Replace); } break; } } /// /// Gets the for this element. /// /// public GraphicsPath Path { get { var path = new GraphicsPath(); AddPaths(this, path); return path; } } /// /// Gets the bounds of the svg element. /// /// The bounds. public RectangleF Bounds { get { var bounds = new RectangleF(); foreach (var child in this.Children) { RectangleF childBounds = new RectangleF(); if (child is SvgFragment) { childBounds = ((SvgFragment)child).Bounds; childBounds.Offset(((SvgFragment)child).X, ((SvgFragment)child).Y); } else if (child is SvgVisualElement) { childBounds = ((SvgVisualElement)child).Bounds; } if (!childBounds.IsEmpty) { if (bounds.IsEmpty) { bounds = childBounds; } else { bounds = RectangleF.Union(bounds, childBounds); } } } return bounds; } } /// /// Initializes a new instance of the class. /// public SvgFragment() { _x = 0.0f; _y = 0.0f; this.Height = new SvgUnit(SvgUnitType.Percentage, 100.0f); this.Width = new SvgUnit(SvgUnitType.Percentage, 100.0f); this.ViewBox = SvgViewBox.Empty; this.AspectRatio = new SvgAspectRatio(SvgPreserveAspectRatio.xMidYMid); } public SizeF GetDimensions() { float w, h; var isWidthperc = Width.Type == SvgUnitType.Percentage; var isHeightperc = Height.Type == SvgUnitType.Percentage; RectangleF bounds = new RectangleF(); if (isWidthperc || isHeightperc) { if (ViewBox.Width > 0 && ViewBox.Height > 0) { bounds = new RectangleF(ViewBox.MinX, ViewBox.MinY, ViewBox.Width, ViewBox.Height); } else { bounds = this.Bounds; //do just one call to the recursive bounds property } } if (isWidthperc) { w = (bounds.Width + bounds.X) * (Width.Value * 0.01f); } else { w = Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this); } if (isHeightperc) { h = (bounds.Height + bounds.Y) * (Height.Value * 0.01f); } else { h = Height.ToDeviceValue(null, UnitRenderingType.Vertical, this); } return new SizeF(w, h); } public override SvgElement DeepCopy() { return DeepCopy(); } public override SvgElement DeepCopy() { var newObj = base.DeepCopy() as SvgFragment; newObj.Height = this.Height; newObj.Width = this.Width; newObj.Overflow = this.Overflow; newObj.ViewBox = this.ViewBox; newObj.AspectRatio = this.AspectRatio; 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"); } } }