4040 * @since 3.1
4141 */
4242public class Pattern extends Resource {
43-
44- private int initialZoom ;
45-
46- private Runnable bitmapDestructor ;
47-
4843 // These are the possible fields with which a pattern can be initialized from the appropriate constructors.
4944 private final Image image ;
5045 private float baseX1 , baseY1 , baseX2 , baseY2 ;
5146 private Color color1 , color2 ;
5247 private int alpha1 , alpha2 ;
5348
54- private final Map <Integer , Long > zoomLevelToHandle = new HashMap <>();
49+ private final Map <Integer , PatternHandle > zoomToHandle = new HashMap <>();
50+
51+ private boolean isDestroyed ;
5552
5653/**
5754 * Constructs a new Pattern given an image. Drawing with the resulting
@@ -87,8 +84,6 @@ public Pattern(Device device, Image image) {
8784 if (image .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
8885 this .device .checkGDIP ();
8986 this .image = image ;
90- initialZoom = DPIUtil .getDeviceZoom ();
91- setImageHandle (image , initialZoom );
9287 init ();
9388 this .device .registerResourceWithZoomSupport (this );
9489}
@@ -182,126 +177,49 @@ public Pattern(Device device, float x1, float y1, float x2, float y2, Color colo
182177 this .alpha1 = alpha1 ;
183178 this .alpha2 = alpha2 ;
184179 this .image = null ;
185- initialZoom = DPIUtil .getDeviceZoom ();
186- initializeSize (initialZoom );
180+ init ();
187181 this .device .registerResourceWithZoomSupport (this );
188182}
189183
190- long getHandle (int zoom ) {
191- if (!this .zoomLevelToHandle .containsKey (zoom )) {
192- if (isImagePattern ()) {
193- setImageHandle (image , zoom );
194- } else {
195- initializeSize (zoom );
196- }
184+ private PatternHandle newPatternHandle (int zoom ) {
185+ if (image != null ) {
186+ return new ImagePatternHandle (zoom );
187+ } else {
188+ return new BasePatternHandle (zoom );
197189 }
198- return this .zoomLevelToHandle .get (zoom );
199190}
200191
201- private void initializeSize (int zoom ) {
202- long handle ;
203- float x1 = DPIUtil .scaleUp (this .baseX1 , zoom );
204- float y1 = DPIUtil .scaleUp (this .baseY1 , zoom );
205- float x2 = DPIUtil .scaleUp (this .baseX2 , zoom );
206- float y2 = DPIUtil .scaleUp (this .baseY2 , zoom );
207- if (color1 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
208- if (color1 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
209- if (color2 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
210- if (color2 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
211- this .device .checkGDIP ();
212- int colorRef1 = color1 .handle ;
213- int foreColor = ((alpha1 & 0xFF ) << 24 ) | ((colorRef1 >> 16 ) & 0xFF ) | (colorRef1 & 0xFF00 ) | ((colorRef1 & 0xFF ) << 16 );
214- if (x1 == x2 && y1 == y2 ) {
215- handle = Gdip .SolidBrush_new (foreColor );
216- if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
217- } else {
218- int colorRef2 = color2 .handle ;
219- int backColor = ((alpha2 & 0xFF ) << 24 ) | ((colorRef2 >> 16 ) & 0xFF ) | (colorRef2 & 0xFF00 ) | ((colorRef2 & 0xFF ) << 16 );
220- PointF p1 = new PointF ();
221- p1 .X = x1 ;
222- p1 .Y = y1 ;
223- PointF p2 = new PointF ();
224- p2 .X = x2 ;
225- p2 .Y = y2 ;
226- handle = Gdip .LinearGradientBrush_new (p1 , p2 , foreColor , backColor );
227- if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
228- if (alpha1 != 0xFF || alpha2 != 0xFF ) {
229- int a = (int )((alpha1 & 0xFF ) * 0.5f + (alpha2 & 0xFF ) * 0.5f );
230- int r = (int )(((colorRef1 & 0xFF ) >> 0 ) * 0.5f + ((colorRef2 & 0xFF ) >> 0 ) * 0.5f );
231- int g = (int )(((colorRef1 & 0xFF00 ) >> 8 ) * 0.5f + ((colorRef2 & 0xFF00 ) >> 8 ) * 0.5f );
232- int b = (int )(((colorRef1 & 0xFF0000 ) >> 16 ) * 0.5f + ((colorRef2 & 0xFF0000 ) >> 16 ) * 0.5f );
233- int midColor = a << 24 | r << 16 | g << 8 | b ;
234- Gdip .LinearGradientBrush_SetInterpolationColors (handle , new int [] {foreColor , midColor , backColor }, new float []{0 , 0.5f , 1 }, 3 );
235- }
192+ private PatternHandle getPatternHandle (int zoom ) {
193+ if (!zoomToHandle .containsKey (zoom )) {
194+ zoomToHandle .put (zoom , newPatternHandle (zoom ));
236195 }
237- this .zoomLevelToHandle .put (zoom , handle );
238- init ();
196+ return zoomToHandle .get (zoom );
239197}
240198
241- void setImageHandle (Image image , int zoom ) {
242- long [] gdipImage = image .createGdipImage (zoom );
243- long img = gdipImage [0 ];
244- int width = Gdip .Image_GetWidth (img );
245- int height = Gdip .Image_GetHeight (img );
246- long handle = Gdip .TextureBrush_new (img , Gdip .WrapModeTile , 0 , 0 , width , height );
247- bitmapDestructor = () -> {
248- Gdip .Bitmap_delete (img );
249- if (gdipImage [1 ] != 0 ) {
250- long hHeap = OS .GetProcessHeap ();
251- OS .HeapFree (hHeap , 0 , gdipImage [1 ]);
252- }
253- };
254- if (handle == 0 ) {
255- bitmapDestructor .run ();
256- SWT .error (SWT .ERROR_NO_HANDLES );
257- } else {
258- zoomLevelToHandle .put (zoom , handle );
259- }
199+ long getHandle (int zoom ) {
200+ return this .getPatternHandle (zoom ).handle ;
260201}
261202
262203@ Override
263204void destroy () {
264205 device .deregisterResourceWithZoomSupport (this );
265- for (long handle : zoomLevelToHandle .values ()) {
266- destroyHandle (handle );
267- }
268- zoomLevelToHandle .clear ();
269- if (bitmapDestructor != null ) {
270- bitmapDestructor .run ();
271- bitmapDestructor = null ;
272- }
206+ zoomToHandle .values ().forEach (PatternHandle ::destroy );
207+ zoomToHandle .clear ();
208+ this .isDestroyed = true ;
273209}
274210
275211@ Override
276212void destroyHandlesExcept (Set <Integer > zoomLevels ) {
277- zoomLevelToHandle .entrySet ().removeIf (entry -> {
213+ zoomToHandle .entrySet ().removeIf (entry -> {
278214 final Integer zoom = entry .getKey ();
279- if (!zoomLevels .contains (zoom ) && zoom != initialZoom ) {
280- destroyHandle ( entry .getValue ());
215+ if (!zoomLevels .contains (zoom ) ) {
216+ entry .getValue (). destroy ( );
281217 return true ;
282218 }
283219 return false ;
284220 });
285221}
286222
287- private void destroyHandle (long handle ) {
288- int type = Gdip .Brush_GetType (handle );
289- switch (type ) {
290- case Gdip .BrushTypeSolidColor :
291- Gdip .SolidBrush_delete (handle );
292- break ;
293- case Gdip .BrushTypeHatchFill :
294- Gdip .HatchBrush_delete (handle );
295- break ;
296- case Gdip .BrushTypeLinearGradient :
297- Gdip .LinearGradientBrush_delete (handle );
298- break ;
299- case Gdip .BrushTypeTextureFill :
300- Gdip .TextureBrush_delete (handle );
301- break ;
302- }
303- }
304-
305223/**
306224 * Returns <code>true</code> if the Pattern has been disposed,
307225 * and <code>false</code> otherwise.
@@ -314,7 +232,7 @@ private void destroyHandle(long handle) {
314232 */
315233@ Override
316234public boolean isDisposed () {
317- return zoomLevelToHandle . isEmpty () ;
235+ return isDestroyed ;
318236}
319237
320238/**
@@ -326,11 +244,118 @@ public boolean isDisposed() {
326244@ Override
327245public String toString () {
328246 if (isDisposed ()) return "Pattern {*DISPOSED*}" ;
329- return "Pattern {" + zoomLevelToHandle + "}" ;
247+ return "Pattern {" + zoomToHandle + "}" ;
248+ }
249+
250+ private class BasePatternHandle extends PatternHandle {
251+ public BasePatternHandle (int zoom ) {
252+ super (zoom );
253+ }
254+
255+ @ Override
256+ long createHandle (int zoom ) {
257+ long handle ;
258+ float x1 = DPIUtil .scaleUp (baseX1 , zoom );
259+ float y1 = DPIUtil .scaleUp (baseY1 , zoom );
260+ float x2 = DPIUtil .scaleUp (baseX2 , zoom );
261+ float y2 = DPIUtil .scaleUp (baseY2 , zoom );
262+ if (color1 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
263+ if (color1 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
264+ if (color2 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
265+ if (color2 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
266+ device .checkGDIP ();
267+ int colorRef1 = color1 .handle ;
268+ int foreColor = ((alpha1 & 0xFF ) << 24 ) | ((colorRef1 >> 16 ) & 0xFF ) | (colorRef1 & 0xFF00 ) | ((colorRef1 & 0xFF ) << 16 );
269+ if (x1 == x2 && y1 == y2 ) {
270+ handle = Gdip .SolidBrush_new (foreColor );
271+ if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
272+ } else {
273+ int colorRef2 = color2 .handle ;
274+ int backColor = ((alpha2 & 0xFF ) << 24 ) | ((colorRef2 >> 16 ) & 0xFF ) | (colorRef2 & 0xFF00 ) | ((colorRef2 & 0xFF ) << 16 );
275+ PointF p1 = new PointF ();
276+ p1 .X = x1 ;
277+ p1 .Y = y1 ;
278+ PointF p2 = new PointF ();
279+ p2 .X = x2 ;
280+ p2 .Y = y2 ;
281+ handle = Gdip .LinearGradientBrush_new (p1 , p2 , foreColor , backColor );
282+ if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
283+ if (alpha1 != 0xFF || alpha2 != 0xFF ) {
284+ int a = (int )((alpha1 & 0xFF ) * 0.5f + (alpha2 & 0xFF ) * 0.5f );
285+ int r = (int )(((colorRef1 & 0xFF ) >> 0 ) * 0.5f + ((colorRef2 & 0xFF ) >> 0 ) * 0.5f );
286+ int g = (int )(((colorRef1 & 0xFF00 ) >> 8 ) * 0.5f + ((colorRef2 & 0xFF00 ) >> 8 ) * 0.5f );
287+ int b = (int )(((colorRef1 & 0xFF0000 ) >> 16 ) * 0.5f + ((colorRef2 & 0xFF0000 ) >> 16 ) * 0.5f );
288+ int midColor = a << 24 | r << 16 | g << 8 | b ;
289+ Gdip .LinearGradientBrush_SetInterpolationColors (handle , new int [] {foreColor , midColor , backColor }, new float []{0 , 0.5f , 1 }, 3 );
290+ }
291+ }
292+ return handle ;
293+ }
330294}
331295
332- private boolean isImagePattern () {
333- return image != null ;
296+ private class ImagePatternHandle extends PatternHandle {
297+ private long [] gdipImage ;
298+
299+ public ImagePatternHandle (int zoom ) {
300+ super (zoom );
301+ }
302+
303+ @ Override
304+ long createHandle (int zoom ) {
305+ gdipImage = image .createGdipImage (zoom );
306+ long img = gdipImage [0 ];
307+ int width = Gdip .Image_GetWidth (img );
308+ int height = Gdip .Image_GetHeight (img );
309+ long handle = Gdip .TextureBrush_new (img , Gdip .WrapModeTile , 0 , 0 , width , height );
310+ if (handle == 0 ) {
311+ cleanupBitmap ();
312+ SWT .error (SWT .ERROR_NO_HANDLES );
313+ }
314+ return handle ;
315+ }
316+
317+ @ Override
318+ protected void destroy () {
319+ super .destroy ();
320+ cleanupBitmap ();
321+ }
322+
323+ private void cleanupBitmap () {
324+ if (gdipImage .length < 2 ) return ;
325+ long img = gdipImage [0 ];
326+ Gdip .Bitmap_delete (img );
327+ if (gdipImage [1 ] != 0 ) {
328+ long hHeap = OS .GetProcessHeap ();
329+ OS .HeapFree (hHeap , 0 , gdipImage [1 ]);
330+ }
331+ }
334332}
335333
334+ private abstract class PatternHandle {
335+ long handle ;
336+
337+ public PatternHandle (int zoom ) {
338+ this .handle = createHandle (zoom );
339+ }
340+
341+ abstract long createHandle (int zoom );
342+
343+ protected void destroy () {
344+ int type = Gdip .Brush_GetType (handle );
345+ switch (type ) {
346+ case Gdip .BrushTypeSolidColor :
347+ Gdip .SolidBrush_delete (handle );
348+ break ;
349+ case Gdip .BrushTypeHatchFill :
350+ Gdip .HatchBrush_delete (handle );
351+ break ;
352+ case Gdip .BrushTypeLinearGradient :
353+ Gdip .LinearGradientBrush_delete (handle );
354+ break ;
355+ case Gdip .BrushTypeTextureFill :
356+ Gdip .TextureBrush_delete (handle );
357+ break ;
358+ }
359+ }
360+ }
336361}
0 commit comments