1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Runtime.InteropServices;
6 
7 namespace System.Drawing.Drawing2D
8 {
9     public partial class CustomLineCap : MarshalByRefObject, ICloneable, IDisposable
10     {
11 #if FINALIZATION_WATCH
12         private string allocationSite = Graphics.GetAllocationStack();
13 #endif
14 
15         // Handle to native line cap object
16         internal SafeCustomLineCapHandle nativeCap = null;
17 
18         private bool _disposed = false;
19 
20         // For subclass creation
CustomLineCap()21         internal CustomLineCap() { }
22 
CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath)23         public CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath) : this(fillPath, strokePath, LineCap.Flat) { }
24 
CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap)25         public CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap) : this(fillPath, strokePath, baseCap, 0) { }
26 
CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap, float baseInset)27         public CustomLineCap(GraphicsPath fillPath, GraphicsPath strokePath, LineCap baseCap, float baseInset)
28         {
29             IntPtr nativeLineCap;
30             int status = SafeNativeMethods.Gdip.GdipCreateCustomLineCap(
31                                 new HandleRef(fillPath, (fillPath == null) ? IntPtr.Zero : fillPath.nativePath),
32                                 new HandleRef(strokePath, (strokePath == null) ? IntPtr.Zero : strokePath.nativePath),
33                                 baseCap, baseInset, out nativeLineCap);
34 
35             if (status != SafeNativeMethods.Gdip.Ok)
36                 throw SafeNativeMethods.Gdip.StatusException(status);
37 
38             SetNativeLineCap(nativeLineCap);
39         }
40 
41         internal CustomLineCap(IntPtr nativeLineCap) => SetNativeLineCap(nativeLineCap);
42 
SetNativeLineCap(IntPtr handle)43         internal void SetNativeLineCap(IntPtr handle)
44         {
45             if (handle == IntPtr.Zero)
46                 throw new ArgumentNullException("handle");
47 
48             nativeCap = new SafeCustomLineCapHandle(handle);
49         }
50 
Dispose()51         public void Dispose()
52         {
53             Dispose(true);
54             GC.SuppressFinalize(this);
55         }
56 
Dispose(bool disposing)57         protected virtual void Dispose(bool disposing)
58         {
59             if (_disposed)
60                 return;
61 
62 #if FINALIZATION_WATCH
63             if (!disposing && nativeCap != null)
64                 Debug.WriteLine("**********************\nDisposed through finalization:\n" + allocationSite);
65 #endif
66             // propagate the explicit dispose call to the child
67             if (disposing && nativeCap != null)
68             {
69                 nativeCap.Dispose();
70             }
71 
72             _disposed = true;
73         }
74 
~CustomLineCap()75         ~CustomLineCap() => Dispose(false);
76 
Clone()77         public virtual object Clone()
78         {
79             IntPtr clonedCap;
80             int status = SafeNativeMethods.Gdip.GdipCloneCustomLineCap(new HandleRef(this, nativeCap), out clonedCap);
81 
82             if (status != SafeNativeMethods.Gdip.Ok)
83                 throw SafeNativeMethods.Gdip.StatusException(status);
84 
85             return CreateCustomLineCapObject(clonedCap);
86         }
87 
SetStrokeCaps(LineCap startCap, LineCap endCap)88         public void SetStrokeCaps(LineCap startCap, LineCap endCap)
89         {
90             int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapStrokeCaps(new HandleRef(this, nativeCap), startCap, endCap);
91 
92             if (status != SafeNativeMethods.Gdip.Ok)
93                 throw SafeNativeMethods.Gdip.StatusException(status);
94         }
95 
GetStrokeCaps(out LineCap startCap, out LineCap endCap)96         public void GetStrokeCaps(out LineCap startCap, out LineCap endCap)
97         {
98             int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapStrokeCaps(new HandleRef(this, nativeCap), out startCap, out endCap);
99 
100             if (status != SafeNativeMethods.Gdip.Ok)
101                 throw SafeNativeMethods.Gdip.StatusException(status);
102         }
103 
104         public LineJoin StrokeJoin
105         {
106             get
107             {
108                 int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapStrokeJoin(new HandleRef(this, nativeCap), out LineJoin lineJoin);
109 
110                 if (status != SafeNativeMethods.Gdip.Ok)
111                     throw SafeNativeMethods.Gdip.StatusException(status);
112 
113                 return lineJoin;
114             }
115             set
116             {
117                 int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapStrokeJoin(new HandleRef(this, nativeCap), value);
118 
119                 if (status != SafeNativeMethods.Gdip.Ok)
120                     throw SafeNativeMethods.Gdip.StatusException(status);
121             }
122         }
123 
124         public LineCap BaseCap
125         {
126             get
127             {
128                 int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapBaseCap(new HandleRef(this, nativeCap), out LineCap baseCap);
129 
130                 if (status != SafeNativeMethods.Gdip.Ok)
131                     throw SafeNativeMethods.Gdip.StatusException(status);
132 
133                 return baseCap;
134             }
135             set
136             {
137                 int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapBaseCap(new HandleRef(this, nativeCap), value);
138 
139                 if (status != SafeNativeMethods.Gdip.Ok)
140                     throw SafeNativeMethods.Gdip.StatusException(status);
141             }
142         }
143 
144         public float BaseInset
145         {
146             get
147             {
148                 int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapBaseInset(new HandleRef(this, nativeCap), out float inset);
149 
150                 if (status != SafeNativeMethods.Gdip.Ok)
151                     throw SafeNativeMethods.Gdip.StatusException(status);
152 
153                 return inset;
154             }
155             set
156             {
157                 int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapBaseInset(new HandleRef(this, nativeCap), value);
158 
159                 if (status != SafeNativeMethods.Gdip.Ok)
160                     throw SafeNativeMethods.Gdip.StatusException(status);
161             }
162         }
163 
164         public float WidthScale
165         {
166             get
167             {
168                 int status = SafeNativeMethods.Gdip.GdipGetCustomLineCapWidthScale(new HandleRef(this, nativeCap), out float widthScale);
169 
170                 if (status != SafeNativeMethods.Gdip.Ok)
171                     throw SafeNativeMethods.Gdip.StatusException(status);
172 
173                 return widthScale;
174             }
175             set
176             {
177                 int status = SafeNativeMethods.Gdip.GdipSetCustomLineCapWidthScale(new HandleRef(this, nativeCap), value);
178 
179                 if (status != SafeNativeMethods.Gdip.Ok)
180                     throw SafeNativeMethods.Gdip.StatusException(status);
181             }
182         }
183     }
184 }
185