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,48 @@ 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 );
197187 }
198- return this . zoomLevelToHandle . get (zoom );
188+ return new BasePatternHandle (zoom );
199189}
200190
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- }
191+ private PatternHandle getPatternHandle (int zoom ) {
192+ if (!zoomToHandle .containsKey (zoom )) {
193+ zoomToHandle .put (zoom , newPatternHandle (zoom ));
236194 }
237- this .zoomLevelToHandle .put (zoom , handle );
238- init ();
195+ return zoomToHandle .get (zoom );
239196}
240197
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- }
198+ long getHandle (int zoom ) {
199+ return this .getPatternHandle (zoom ).handle ;
260200}
261201
262202@ Override
263203void destroy () {
264204 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- }
205+ zoomToHandle .values ().forEach (PatternHandle ::destroy );
206+ zoomToHandle .clear ();
207+ this .isDestroyed = true ;
273208}
274209
275210@ Override
276211void destroyHandlesExcept (Set <Integer > zoomLevels ) {
277- zoomLevelToHandle .entrySet ().removeIf (entry -> {
212+ zoomToHandle .entrySet ().removeIf (entry -> {
278213 final Integer zoom = entry .getKey ();
279- if (!zoomLevels .contains (zoom ) && zoom != initialZoom ) {
280- destroyHandle ( entry .getValue ());
214+ if (!zoomLevels .contains (zoom ) ) {
215+ entry .getValue (). destroy ( );
281216 return true ;
282217 }
283218 return false ;
284219 });
285220}
286221
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-
305222/**
306223 * Returns <code>true</code> if the Pattern has been disposed,
307224 * and <code>false</code> otherwise.
@@ -314,7 +231,7 @@ private void destroyHandle(long handle) {
314231 */
315232@ Override
316233public boolean isDisposed () {
317- return zoomLevelToHandle . isEmpty () ;
234+ return isDestroyed ;
318235}
319236
320237/**
@@ -326,11 +243,118 @@ public boolean isDisposed() {
326243@ Override
327244public String toString () {
328245 if (isDisposed ()) return "Pattern {*DISPOSED*}" ;
329- return "Pattern {" + zoomLevelToHandle + "}" ;
246+ return "Pattern {" + zoomToHandle + "}" ;
330247}
331248
332- private boolean isImagePattern () {
333- return image != null ;
249+ private class BasePatternHandle extends PatternHandle {
250+ public BasePatternHandle (int zoom ) {
251+ super (zoom );
252+ }
253+
254+ @ Override
255+ long createHandle (int zoom ) {
256+ long handle ;
257+ float x1 = DPIUtil .scaleUp (baseX1 , zoom );
258+ float y1 = DPIUtil .scaleUp (baseY1 , zoom );
259+ float x2 = DPIUtil .scaleUp (baseX2 , zoom );
260+ float y2 = DPIUtil .scaleUp (baseY2 , zoom );
261+ if (color1 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
262+ if (color1 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
263+ if (color2 == null ) SWT .error (SWT .ERROR_NULL_ARGUMENT );
264+ if (color2 .isDisposed ()) SWT .error (SWT .ERROR_INVALID_ARGUMENT );
265+ device .checkGDIP ();
266+ int colorRef1 = color1 .handle ;
267+ int foreColor = ((alpha1 & 0xFF ) << 24 ) | ((colorRef1 >> 16 ) & 0xFF ) | (colorRef1 & 0xFF00 ) | ((colorRef1 & 0xFF ) << 16 );
268+ if (x1 == x2 && y1 == y2 ) {
269+ handle = Gdip .SolidBrush_new (foreColor );
270+ if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
271+ } else {
272+ int colorRef2 = color2 .handle ;
273+ int backColor = ((alpha2 & 0xFF ) << 24 ) | ((colorRef2 >> 16 ) & 0xFF ) | (colorRef2 & 0xFF00 ) | ((colorRef2 & 0xFF ) << 16 );
274+ PointF p1 = new PointF ();
275+ p1 .X = x1 ;
276+ p1 .Y = y1 ;
277+ PointF p2 = new PointF ();
278+ p2 .X = x2 ;
279+ p2 .Y = y2 ;
280+ handle = Gdip .LinearGradientBrush_new (p1 , p2 , foreColor , backColor );
281+ if (handle == 0 ) SWT .error (SWT .ERROR_NO_HANDLES );
282+ if (alpha1 != 0xFF || alpha2 != 0xFF ) {
283+ int a = (int )((alpha1 & 0xFF ) * 0.5f + (alpha2 & 0xFF ) * 0.5f );
284+ int r = (int )(((colorRef1 & 0xFF ) >> 0 ) * 0.5f + ((colorRef2 & 0xFF ) >> 0 ) * 0.5f );
285+ int g = (int )(((colorRef1 & 0xFF00 ) >> 8 ) * 0.5f + ((colorRef2 & 0xFF00 ) >> 8 ) * 0.5f );
286+ int b = (int )(((colorRef1 & 0xFF0000 ) >> 16 ) * 0.5f + ((colorRef2 & 0xFF0000 ) >> 16 ) * 0.5f );
287+ int midColor = a << 24 | r << 16 | g << 8 | b ;
288+ Gdip .LinearGradientBrush_SetInterpolationColors (handle , new int [] {foreColor , midColor , backColor }, new float []{0 , 0.5f , 1 }, 3 );
289+ }
290+ }
291+ return handle ;
292+ }
334293}
335294
295+ private class ImagePatternHandle extends PatternHandle {
296+ private long [] gdipImage ;
297+
298+ public ImagePatternHandle (int zoom ) {
299+ super (zoom );
300+ }
301+
302+ @ Override
303+ long createHandle (int zoom ) {
304+ gdipImage = image .createGdipImage (zoom );
305+ long img = gdipImage [0 ];
306+ int width = Gdip .Image_GetWidth (img );
307+ int height = Gdip .Image_GetHeight (img );
308+ long handle = Gdip .TextureBrush_new (img , Gdip .WrapModeTile , 0 , 0 , width , height );
309+ if (handle == 0 ) {
310+ cleanupBitmap ();
311+ SWT .error (SWT .ERROR_NO_HANDLES );
312+ }
313+ return handle ;
314+ }
315+
316+ @ Override
317+ protected void destroy () {
318+ super .destroy ();
319+ cleanupBitmap ();
320+ }
321+
322+ private void cleanupBitmap () {
323+ if (gdipImage .length < 2 ) return ;
324+ long img = gdipImage [0 ];
325+ Gdip .Bitmap_delete (img );
326+ if (gdipImage [1 ] != 0 ) {
327+ long hHeap = OS .GetProcessHeap ();
328+ OS .HeapFree (hHeap , 0 , gdipImage [1 ]);
329+ }
330+ }
331+ }
332+
333+ private abstract class PatternHandle {
334+ private final long handle ;
335+
336+ public PatternHandle (int zoom ) {
337+ this .handle = createHandle (zoom );
338+ }
339+
340+ abstract long createHandle (int zoom );
341+
342+ protected void destroy () {
343+ int type = Gdip .Brush_GetType (handle );
344+ switch (type ) {
345+ case Gdip .BrushTypeSolidColor :
346+ Gdip .SolidBrush_delete (handle );
347+ break ;
348+ case Gdip .BrushTypeHatchFill :
349+ Gdip .HatchBrush_delete (handle );
350+ break ;
351+ case Gdip .BrushTypeLinearGradient :
352+ Gdip .LinearGradientBrush_delete (handle );
353+ break ;
354+ case Gdip .BrushTypeTextureFill :
355+ Gdip .TextureBrush_delete (handle );
356+ break ;
357+ }
358+ }
359+ }
336360}
0 commit comments