diff options
author | Pierre-Charles David | 2016-04-11 09:37:59 +0000 |
---|---|---|
committer | Pierre-Charles David | 2016-04-13 09:46:52 +0000 |
commit | 5f957f75c7fb8c8a632b0a90047096eee4975dc2 (patch) | |
tree | 4959690fa72ce70f3215a3b16ac6c1fac228a456 | |
parent | e7db12d5b124a33ec7cc9bf986b39d923ecae829 (diff) | |
download | org.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.java | 63 |
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(); |