Skip to content

Commit 70f562b

Browse files
committed
[win32] Create Pattern handles on demand
This commit refactors Pattern in the win32 implementation to better support multiple handles for different zoom settings by creating all handles only on demand.
1 parent 0a0b40c commit 70f562b

File tree

1 file changed

+132
-107
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics

1 file changed

+132
-107
lines changed

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java

Lines changed: 132 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,15 @@
4040
* @since 3.1
4141
*/
4242
public 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
263204
void 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
276212
void 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
316234
public boolean isDisposed() {
317-
return zoomLevelToHandle.isEmpty();
235+
return isDestroyed;
318236
}
319237

320238
/**
@@ -326,11 +244,118 @@ public boolean isDisposed() {
326244
@Override
327245
public 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

Comments
 (0)