Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Charles David2016-04-11 09:37:59 +0000
committerPierre-Charles David2016-04-13 09:46:52 +0000
commit5f957f75c7fb8c8a632b0a90047096eee4975dc2 (patch)
tree4959690fa72ce70f3215a3b16ac6c1fac228a456
parente7db12d5b124a33ec7cc9bf986b39d923ecae829 (diff)
downloadorg.eclipse.sirius-5f957f75c7fb8c8a632b0a90047096eee4975dc2.tar.gz
org.eclipse.sirius-5f957f75c7fb8c8a632b0a90047096eee4975dc2.tar.xz
org.eclipse.sirius-5f957f75c7fb8c8a632b0a90047096eee4975dc2.zip
[442268] Limit the cache size in terms of MB instead of number of items
* Add a configurable (using a system property) maximum size for the cache, corresponding actual memory occupation of the cached bitmaps (assuming 4 8-bits channels) instead of a number of items. * Also fix some crashes (NPE and/or "widget is disposed") by adding some synchronization around image rendering and disposing (as disposing happens in a background thread controlled by the cache). Bug: 442268 Change-Id: I7ebfd2794d87aaa6b1f6f2b1e1e0bd90d2d6b04c Signed-off-by: Pierre-Charles David <pierre-charles.david@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java63
1 files changed, 56 insertions, 7 deletions
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java
index e3c77826a9..1cce84108d 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java
@@ -39,6 +39,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
+import com.google.common.cache.Weigher;
import com.google.common.collect.Lists;
//CHECKSTYLE:OFF
@@ -48,14 +49,54 @@ public class SVGFigure extends Figure implements StyledFigure, ITransparentFigur
*/
private static class ImageCache {
/**
- * The rendered bitmaps, organized by key..
+ * The maximum size of the cache, in bytes.
+ */
+ private static final int MAX_WEIGHT;
+
+ static {
+ String s = System.getProperty("org.eclipse.sirius.diagram.ui.svg.maxCacheSizeMB"); //$NON-NLS-1$
+ int mb;
+ try {
+ mb = Integer.parseInt(s);
+ } catch (NumberFormatException nfe) {
+ mb = 50;
+ }
+ MAX_WEIGHT = mb * 1024 * 1024;
+ }
+
+ /**
+ * Computes the weight of a rendered image, as the number of bytes
+ * occupied by the raw raster data (assumes 4 8-bit channels).
*/
- private final Cache<String, Image> images = CacheBuilder.newBuilder().maximumSize(10).removalListener(new RemovalListener<String, Image>() {
+ private static final class ImageWeigher implements Weigher<String, Image> {
+ @Override
+ public int weigh(String key, Image value) {
+ if (value != null) {
+ synchronized (value) {
+ if (!value.isDisposed()) {
+ org.eclipse.swt.graphics.Rectangle bounds = value.getBounds();
+ return bounds.width * bounds.height * 4;
+ }
+ }
+ }
+ return 0;
+ }
+ }
+
+ private final class ImageRemovalListener implements RemovalListener<String, Image> {
@Override
public void onRemoval(RemovalNotification<String, Image> notification) {
- notification.getValue().dispose();
+ Image img = notification.getValue();
+ synchronized (img) {
+ img.dispose();
+ }
}
- }).build();
+ }
+
+ /**
+ * The rendered bitmaps, organized by key..
+ */
+ private final Cache<String, Image> images = CacheBuilder.newBuilder().maximumWeight(ImageCache.MAX_WEIGHT).removalListener(new ImageRemovalListener()).weigher(new ImageWeigher()).build();
/**
* Get the image cached or create new one and cache it.
@@ -71,7 +112,7 @@ public class SVGFigure extends Figure implements StyledFigure, ITransparentFigur
public synchronized Image getImage(SVGFigure fig, Rectangle clientArea, Graphics graphics) {
String key = fig.getKey(graphics);
Image result = images.getIfPresent(key);
- if (result == null) {
+ if (result == null || result.isDisposed()) {
if (fig.transcoder != null) {
result = fig.transcoder.render(fig, clientArea, graphics, CACHE_SCALED_IMAGES);
}
@@ -323,12 +364,20 @@ public class SVGFigure extends Figure implements StyledFigure, ITransparentFigur
scaledArea.performScale(graphics.getAbsoluteScale());
Image image = getImage(svgArea, graphics);
if (image != null) {
- graphics.drawImage(image, 0, 0, scaledArea.width(), scaledArea.height(), svgArea.x(), svgArea.y(), svgArea.width(), svgArea.height());
+ synchronized (image) {
+ if (!image.isDisposed()) {
+ graphics.drawImage(image, 0, 0, scaledArea.width(), scaledArea.height(), svgArea.x(), svgArea.y(), svgArea.width(), svgArea.height());
+ }
+ }
}
} else {
Image image = getImage(svgArea, graphics);
if (image != null) {
- graphics.drawImage(image, svgArea.x(), svgArea.y());
+ synchronized (image) {
+ if (!image.isDisposed()) {
+ graphics.drawImage(image, svgArea.x(), svgArea.y());
+ }
+ }
}
}
modifier.popState();

Back to the top