Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BoundsRelativeToTop #945

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions Source/Basic Shapes/SvgPathBasedElement.Drawing.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
#if !NO_SDC
#if !NO_SDC
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Svg
{
public abstract partial class SvgPathBasedElement : SvgVisualElement
{
public override RectangleF Bounds
{
get
{
var path = Path(null);
if (path == null)
return new RectangleF();
if (Transforms == null || Transforms.Count == 0)
return path.GetBounds();

using (path = (GraphicsPath)path.Clone())
using (var matrix = Transforms.GetMatrix())
{
path.Transform(matrix);
return path.GetBounds();
}
}
}
/// <inheritdoc/>
public override RectangleF Bounds => TransformedBoundsFromPathToClone(Path(null));
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => TransformedBoundsPlusParentsFromPathToClone(Path(null));
}
}
#endif
70 changes: 68 additions & 2 deletions Source/Basic Shapes/SvgVisualElement.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,77 @@ SizeF ISvgBoundable.Size
}

/// <summary>
/// Gets the bounds of the element.
/// Gets the bounds of the element relative to <see cref="SvgElement.Parent"/>.
/// </summary>
/// <value>The bounds.</value>
/// <value>The bounds of the element.</value>
public abstract RectangleF Bounds { get; }

/// <summary>
/// Gets the bounds of the element relative to the top-level <see cref="SvgElement.Parent"/>.
/// </summary>
/// <value>The bounds of the element.</value>

public abstract RectangleF BoundsRelativeToTop { get; }
/// <summary>
/// Just like <see cref="SvgElement.TransformedBounds(RectangleF)"/> but considers all <see cref="SvgElement.Parents"/>.
/// </summary>
/// <param name="bounds">The rectangle to be transformed.</param>
/// <returns>The transformed rectangle, or the original rectangle if no transformation exists.</returns>
protected RectangleF TransformedBoundsPlusParents(RectangleF bounds)
{
GraphicsPath path = null;
try
{
foreach (var p in ParentsAndSelf)
if (p.Transforms is { Count: > 0 } t)
{
if (path is null)
{
path = new();
path.AddRectangle(bounds);
}
using var m = t.GetMatrix();
path.Transform(m);
}
return path?.GetBounds() ?? bounds;
}
finally { path?.Dispose(); }
}
protected RectangleF TransformedBoundsPlusParentsFromPathToClone(GraphicsPath path)
{
if (path is null) return default;
GraphicsPath pathCloned = null;
try
{
foreach (var p in ParentsAndSelf)
if (p.Transforms is { Count: > 0 } t)
{
pathCloned ??= (GraphicsPath)path.Clone();
using var m = t.GetMatrix();
pathCloned.Transform(m);
}
return pathCloned?.GetBounds() ?? path.GetBounds();
}
finally { pathCloned?.Dispose(); }
}
protected RectangleF BoundsFromChildren(Func<SvgVisualElement, RectangleF> boundsGetter, Func<RectangleF, RectangleF> transform)
{
var r = new RectangleF();
foreach (var c in this.Children)
{
if (c is SvgVisualElement v)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
r = boundsGetter(v);
else if (boundsGetter(v) is { IsEmpty: false } childBounds)
r = RectangleF.Union(r, childBounds);
}
}
return transform(r);
}

/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary>
Expand Down
38 changes: 5 additions & 33 deletions Source/Document Structure/SvgGroup.Drawing.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NO_SDC
#if !NO_SDC
using System.Drawing;
using System.Drawing.Drawing2D;

Expand All @@ -15,38 +15,10 @@ public override GraphicsPath Path(ISvgRenderer renderer)
return GetPaths(this, renderer);
}

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
{
get
{
var r = new RectangleF();
foreach (var c in this.Children)
{
if (c is SvgVisualElement)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
{
r = ((SvgVisualElement)c).Bounds;
}
else
{
var childBounds = ((SvgVisualElement)c).Bounds;
if (!childBounds.IsEmpty)
{
r = RectangleF.Union(r, childBounds);
}
}
}
}
return TransformedBounds(r);
}
}
/// <inheritdoc/>
public override RectangleF Bounds => BoundsFromChildren(e => e.Bounds, TransformedBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => BoundsFromChildren(e => e.BoundsRelativeToTop, r => r);
}
}
#endif
15 changes: 8 additions & 7 deletions Source/Document Structure/SvgImage.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ public partial class SvgImage : SvgVisualElement
private bool _gettingBounds;
private GraphicsPath _path;

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
RectangleF RawBounds
{
get
{
Expand All @@ -31,13 +27,18 @@ public override RectangleF Bounds
return new RectangleF();
}
_gettingBounds = true;
var bounds = TransformedBounds(new RectangleF(Location.ToDeviceValue(null, this),
var bounds = new RectangleF(Location.ToDeviceValue(null, this),
new SizeF(Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this),
Height.ToDeviceValue(null, UnitRenderingType.Vertical, this))));
Height.ToDeviceValue(null, UnitRenderingType.Vertical, this)));
_gettingBounds = false;
return bounds;
}
}
/// <inheritdoc/>
public override RectangleF Bounds => TransformedBounds(RawBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => TransformedBoundsPlusParents(RawBounds);


/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
Expand Down
39 changes: 5 additions & 34 deletions Source/Document Structure/SvgSwitch.Drawing.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NO_SDC
#if !NO_SDC
using System.Drawing;
using System.Drawing.Drawing2D;

Expand All @@ -15,39 +15,10 @@ public override GraphicsPath Path(ISvgRenderer renderer)
return GetPaths(this, renderer);
}

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
{
get
{
var r = new RectangleF();
foreach (var c in this.Children)
{
if (c is SvgVisualElement)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
{
r = ((SvgVisualElement)c).Bounds;
}
else
{
var childBounds = ((SvgVisualElement)c).Bounds;
if (!childBounds.IsEmpty)
{
r = RectangleF.Union(r, childBounds);
}
}
}
}

return TransformedBounds(r);
}
}
/// <inheritdoc/>
public override RectangleF Bounds => BoundsFromChildren(e => e.Bounds, TransformedBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => BoundsFromChildren(e => e.BoundsRelativeToTop, r => r);

/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
Expand Down
37 changes: 4 additions & 33 deletions Source/Document Structure/SvgSymbol.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,10 @@ public override GraphicsPath Path(ISvgRenderer renderer)
return GetPaths(this, renderer);
}

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
{
get
{
var r = new RectangleF();
foreach (var c in this.Children)
{
if (c is SvgVisualElement)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
{
r = ((SvgVisualElement)c).Bounds;
}
else
{
var childBounds = ((SvgVisualElement)c).Bounds;
if (!childBounds.IsEmpty)
{
r = RectangleF.Union(r, childBounds);
}
}
}
}

return TransformedBounds(r);
}
}
/// <inheritdoc/>
public override RectangleF Bounds => BoundsFromChildren(e => e.Bounds, TransformedBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => BoundsFromChildren(e => e.BoundsRelativeToTop, r => r);

/// <summary>
/// Applies the required transforms to <see cref="ISvgRenderer"/>.
Expand Down
32 changes: 14 additions & 18 deletions Source/Document Structure/SvgUse.Drawing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,24 @@ public override GraphicsPath Path(ISvgRenderer renderer)
return (element != null && !this.HasRecursiveReference()) ? element.Path(renderer) : null;
}

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
RectangleF RawBounds(Func<SvgVisualElement, RectangleF> boundsGetter, Func<RectangleF, RectangleF> transform)
{
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 transform(new RectangleF(this.Location.ToDeviceValue(null, this),
new SizeF(ew, eh)));
if (this.OwnerDocument.IdManager.GetElementById(this.ReferencedElement) is SvgVisualElement element)
{
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 RectangleF();
return boundsGetter(element);
}

return new RectangleF();
}
/// <inheritdoc/>
public override RectangleF Bounds => RawBounds(e => e.Bounds, TransformedBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => RawBounds(e => e.BoundsRelativeToTop, r => r);

protected override void RenderChildren(ISvgRenderer renderer)
{
Expand Down
39 changes: 5 additions & 34 deletions Source/Extensibility/SvgForeignObject.Drawing.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !NO_SDC
#if !NO_SDC
using System.Drawing;
using System.Drawing.Drawing2D;

Expand All @@ -15,39 +15,10 @@ public override GraphicsPath Path(ISvgRenderer renderer)
return GetPaths(this, renderer);
}

/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public override RectangleF Bounds
{
get
{
var r = new RectangleF();
foreach (var c in this.Children)
{
if (c is SvgVisualElement)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if (r.IsEmpty)
{
r = ((SvgVisualElement)c).Bounds;
}
else
{
var childBounds = ((SvgVisualElement)c).Bounds;
if (!childBounds.IsEmpty)
{
r = RectangleF.Union(r, childBounds);
}
}
}
}

return TransformedBounds(r);
}
}
/// <inheritdoc/>
public override RectangleF Bounds => BoundsFromChildren(e => e.Bounds, TransformedBounds);
/// <inheritdoc/>
public override RectangleF BoundsRelativeToTop => BoundsFromChildren(e => e.BoundsRelativeToTop, r => r);

///// <summary>
///// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
Expand Down
Loading
Loading