SvgClipPath.cs 4.13 KB
Newer Older
davescriven's avatar
davescriven committed
1
2
3
4
5
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
6
using Svg.Transforms;
davescriven's avatar
davescriven committed
7
8
9

namespace Svg
{
10
    /// <summary>
11
    /// Defines a path that can be used by other <see cref="ISvgClipable"/> elements.
12
    /// </summary>
13
    [SvgElement("clipPath")]
davescriven's avatar
davescriven committed
14
15
    public sealed class SvgClipPath : SvgElement
    {
16
        private bool _pathDirty = true;
davescriven's avatar
davescriven committed
17

18
        /// <summary>
19
        /// Specifies the coordinate system for the clipping path.
20
        /// </summary>
davescriven's avatar
davescriven committed
21
        [SvgAttribute("clipPathUnits")]
22
        public SvgCoordinateUnits ClipPathUnits { get; set; }
davescriven's avatar
davescriven committed
23

24
25
26
        /// <summary>
        /// Initializes a new instance of the <see cref="SvgClipPath"/> class.
        /// </summary>
davescriven's avatar
davescriven committed
27
28
        public SvgClipPath()
        {
29
            this.ClipPathUnits = SvgCoordinateUnits.ObjectBoundingBox;
davescriven's avatar
davescriven committed
30
31
        }

32
33
        private GraphicsPath cachedClipPath = null;

34
        /// <summary>
35
        /// Gets this <see cref="SvgClipPath"/>'s region to be used as a clipping region.
36
        /// </summary>
37
38
        /// <returns>A new <see cref="Region"/> containing the <see cref="Region"/> to be used for clipping.</returns>
        public Region GetClipRegion(SvgVisualElement owner)
davescriven's avatar
davescriven committed
39
        {
40
            if (cachedClipPath == null || this._pathDirty)
41
            {
42
43
                cachedClipPath = new GraphicsPath();

davescriven's avatar
davescriven committed
44
                foreach (SvgElement element in this.Children)
45
                {
46
                    this.CombinePaths(cachedClipPath, element);
47
                }
davescriven's avatar
davescriven committed
48

49
                this._pathDirty = false;
davescriven's avatar
davescriven committed
50
51
            }

52
            return new Region(cachedClipPath);
davescriven's avatar
davescriven committed
53
54
        }

55
56
57
58
59
        /// <summary>
        /// 
        /// </summary>
        /// <param name="region"></param>
        /// <param name="element"></param>
60
        private void CombinePaths(GraphicsPath path, SvgElement element)
davescriven's avatar
davescriven committed
61
        {
62
            var graphicsElement = element as SvgVisualElement;
davescriven's avatar
davescriven committed
63

64
            if (graphicsElement != null && graphicsElement.Path != null)
65
            {
66
                path.FillMode = (graphicsElement.ClipRule == SvgClipRule.NonZero) ? FillMode.Winding : FillMode.Alternate;
67
68
69
70
71
72
73
74
75
76
77
78

                GraphicsPath childPath = graphicsElement.Path;

                if (graphicsElement.Transforms != null)
                {
                    foreach (SvgTransform transform in graphicsElement.Transforms)
                    {
                        childPath.Transform(transform.Matrix);
                    }
                }

                path.AddPath(childPath, false);
79
            }
davescriven's avatar
davescriven committed
80
81

            foreach (SvgElement child in element.Children)
82
            {
83
                this.CombinePaths(path, child);
84
            }
davescriven's avatar
davescriven committed
85
86
        }

87
88
89
90
91
92
        /// <summary>
        /// Called by the underlying <see cref="SvgElement"/> when an element has been added to the
        /// <see cref="Children"/> collection.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been added.</param>
        /// <param name="index">An <see cref="int"/> representing the index where the element was added to the collection.</param>
93
        protected override void AddElement(SvgElement child, int index)
davescriven's avatar
davescriven committed
94
        {
95
            base.AddElement(child, index);
davescriven's avatar
davescriven committed
96
97
98
            this._pathDirty = true;
        }

99
100
101
102
103
        /// <summary>
        /// Called by the underlying <see cref="SvgElement"/> when an element has been removed from the
        /// <see cref="Children"/> collection.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
104
        protected override void RemoveElement(SvgElement child)
davescriven's avatar
davescriven committed
105
        {
106
            base.RemoveElement(child);
davescriven's avatar
davescriven committed
107
108
109
            this._pathDirty = true;
        }

110
111
112
113
        /// <summary>
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
114
        protected override void Render(SvgRenderer renderer)
davescriven's avatar
davescriven committed
115
116
117
118
119
        {
            // Do nothing
        }
    }
}