Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 5054)
@@ -22,5 +22,4 @@
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
 import java.util.Arrays;
 import java.util.Collection;
@@ -738,6 +737,7 @@
          *
          */
+        Rectangle box = bs.getBox();
         if (bs.hAlign == HorizontalTextAlignment.RIGHT) {
-            x += bs.box.x + bs.box.width + 2;
+            x += box.x + box.width + 2;
         } else {
             FontRenderContext frc = g.getFontRenderContext();
@@ -747,21 +747,21 @@
                 x -= textWidth / 2;
             } else if (bs.hAlign == HorizontalTextAlignment.LEFT) {
-                x -= - bs.box.x + 4 + textWidth;
+                x -= - box.x + 4 + textWidth;
             } else throw new AssertionError();
         }
 
         if (bs.vAlign == VerticalTextAlignment.BOTTOM) {
-            y += bs.box.y + bs.box.height;
+            y += box.y + box.height;
         } else {
             FontRenderContext frc = g.getFontRenderContext();
             LineMetrics metrics = text.font.getLineMetrics(s, frc);
             if (bs.vAlign == VerticalTextAlignment.ABOVE) {
-                y -= - bs.box.y + metrics.getDescent();
+                y -= - box.y + metrics.getDescent();
             } else if (bs.vAlign == VerticalTextAlignment.TOP) {
-                y -= - bs.box.y - metrics.getAscent();
+                y -= - box.y - metrics.getAscent();
             } else if (bs.vAlign == VerticalTextAlignment.CENTER) {
                 y += (metrics.getAscent() - metrics.getDescent()) / 2;
             } else if (bs.vAlign == VerticalTextAlignment.BELOW) {
-                y += bs.box.y + bs.box.height + metrics.getAscent() + 2;
+                y += box.y + box.height + metrics.getAscent() + 2;
             } else throw new AssertionError();
         }
@@ -803,9 +803,9 @@
     }
 
-    public void drawArea(Way w, Color color, MapImage<BufferedImage> fillImage, TextElement text) {
+    public void drawArea(Way w, Color color, MapImage fillImage, TextElement text) {
         drawArea(w, getPath(w), color, fillImage, text);
     }
 
-    protected void drawArea(OsmPrimitive osm, Path2D.Double path, Color color, MapImage<BufferedImage> fillImage, TextElement text) {
+    protected void drawArea(OsmPrimitive osm, Path2D.Double path, Color color, MapImage fillImage, TextElement text) {
 
         Shape area = path.createTransformedShape(nc.getAffineTransform());
@@ -816,7 +816,7 @@
                 g.fill(area);
             } else {
-                TexturePaint texture = new TexturePaint(fillImage.img,
+                TexturePaint texture = new TexturePaint(fillImage.getImage(),
                         //                        new Rectangle(polygon.xpoints[0], polygon.ypoints[0], fillImage.getWidth(), fillImage.getHeight()));
-                        new Rectangle(0, 0, fillImage.img.getWidth(null), fillImage.img.getHeight(null)));
+                        new Rectangle(0, 0, fillImage.getWidth(), fillImage.getHeight()));
                 g.setPaint(texture);
                 Float alpha = Utils.color_int2float(fillImage.alpha);
@@ -873,5 +873,5 @@
     }
 
-    public void drawArea(Relation r, Color color, MapImage<BufferedImage> fillImage, TextElement text) {
+    public void drawArea(Relation r, Color color, MapImage fillImage, TextElement text) {
         Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, r);
         if (!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) {
@@ -915,5 +915,5 @@
     }
 
-    public void drawRestriction(Relation r, MapImage<Image> icon) {
+    public void drawRestriction(Relation r, MapImage icon) {
         Way fromWay = null;
         Way toWay = null;
@@ -1086,5 +1086,5 @@
         }
 
-        drawRestriction(inactive || r.isDisabled() ? icon.getDisabled() : icon.img,
+        drawRestriction(inactive || r.isDisabled() ? icon.getDisabled() : icon.getImage(),
                 pVia, vx, vx2, vy, vy2, iconAngle, r.isSelected());
     }
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 5054)
@@ -460,5 +460,5 @@
      * Draw the component.
      */
-    @Override public void paint(Graphics g) {
+    @Override public synchronized void paint(Graphics g) {
         if (BugReportExceptionHandler.exceptionHandlingInProgress())
             return;
@@ -833,5 +833,5 @@
     }
 
-    public void preferenceChanged(PreferenceChangeEvent e) {
+    public synchronized void preferenceChanged(PreferenceChangeEvent e) {
         paintPreferencesChanged = true;
     }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 5054)
@@ -5,7 +5,4 @@
 
 import java.awt.Color;
-import java.awt.image.BufferedImage;
-
-import javax.swing.ImageIcon;
 
 import org.openstreetmap.josm.Main;
@@ -27,8 +24,8 @@
      */
     public Color color;
-    public MapImage<BufferedImage> fillImage;
+    public MapImage fillImage;
     public TextElement text;
 
-    protected AreaElemStyle(Cascade c, Color color, MapImage<BufferedImage> fillImage, TextElement text) {
+    protected AreaElemStyle(Cascade c, Color color, MapImage fillImage, TextElement text) {
         super(c, -1000f);
         CheckParameterUtil.ensureParameterNotNull(color);
@@ -39,25 +36,20 @@
 
     public static AreaElemStyle create(Cascade c) {
-        MapImage<BufferedImage> fillImage = null;
+        MapImage fillImage = null;
         Color color = null;
 
         IconReference iconRef = c.get("fill-image", null, IconReference.class);
         if (iconRef != null) {
-            ImageIcon icon = MapPaintStyles.getIcon(iconRef, -1, -1);
-            if (icon != null) {
-                if (!(icon.getImage() instanceof BufferedImage))
-                    throw new RuntimeException();
-                fillImage = new MapImage<BufferedImage>(iconRef.iconName, iconRef.source);
-                fillImage.img = (BufferedImage) icon.getImage();
+            fillImage = new MapImage(iconRef.iconName, iconRef.source);
+            fillImage.getImage();
 
-                color = new Color(fillImage.img.getRGB(
-                        fillImage.img.getWidth() / 2, fillImage.img.getHeight() / 2)
-                );
+            color = new Color(fillImage.getImage().getRGB(
+                    fillImage.getWidth() / 2, fillImage.getHeight() / 2)
+            );
 
-                fillImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fill-image-alpha", 255))));
-                Integer pAlpha = Utils.color_float2int(c.get("fill-opacity", null, float.class));
-                if (pAlpha != null) {
-                    fillImage.alpha = pAlpha;
-                }
+            fillImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fill-image-alpha", 255))));
+            Integer pAlpha = Utils.color_float2int(c.get("fill-opacity", null, float.class));
+            if (pAlpha != null) {
+                fillImage.alpha = pAlpha;
             }
         } else {
@@ -78,5 +70,5 @@
             text = TextElement.create(c, PaintColors.AREA_TEXT.get(), true);
         }
-        
+
         if (color != null)
             return new AreaElemStyle(c, color, fillImage, text);
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/BoxTextElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/BoxTextElemStyle.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/BoxTextElemStyle.java	(revision 5054)
@@ -22,12 +22,72 @@
     public enum VerticalTextAlignment { ABOVE, TOP, CENTER, BOTTOM, BELOW }
 
+    public static interface BoxProvider {
+        BoxProviderResult get();
+    }
+
+    public static class BoxProviderResult {
+        private Rectangle box;
+        private boolean temporary;
+
+        public BoxProviderResult(Rectangle box, boolean temporary) {
+            this.box = box;
+            this.temporary = temporary;
+        }
+
+        /**
+         * The box
+         */
+        public Rectangle getBox() {
+            return box;
+        }
+
+        /**
+         * True, if the box can change in future calls of the BoxProvider get() method
+         */
+        public boolean isTemporary() {
+            return temporary;
+        }
+    }
+
+    public static class SimpleBoxProvider implements BoxProvider {
+        private Rectangle box;
+
+        public SimpleBoxProvider(Rectangle box) {
+            this.box = box;
+        }
+
+        @Override
+        public BoxProviderResult get() {
+            return new BoxProviderResult(box, false);
+        }
+
+        @Override
+        public int hashCode() {
+            return box.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null || !(obj instanceof BoxProvider))
+                return false;
+            final BoxProvider other = (BoxProvider) obj;
+            BoxProviderResult resultOther = other.get();
+            if (resultOther.isTemporary()) return false;
+            return box.equals(resultOther.getBox());
+        }
+    }
+
     public static final Rectangle ZERO_BOX = new Rectangle(0, 0, 0, 0);
 
     public TextElement text;
-    public Rectangle box;
+    // Either boxProvider or box is not null. If boxProvider is different from
+    // null, this means, that the box can still change in future, otherwise
+    // it is fixed.
+    protected BoxProvider boxProvider;
+    protected Rectangle box;
     public HorizontalTextAlignment hAlign;
     public VerticalTextAlignment vAlign;
 
-    public BoxTextElemStyle(Cascade c, TextElement text, Rectangle box, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
+    public BoxTextElemStyle(Cascade c, TextElement text, BoxProvider boxProvider, Rectangle box, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
         super(c, 2000f);
         CheckParameterUtil.ensureParameterNotNull(text);
@@ -35,4 +95,5 @@
         CheckParameterUtil.ensureParameterNotNull(vAlign);
         this.text = text;
+        this.boxProvider = boxProvider;
         this.box = box == null ? ZERO_BOX : box;
         this.hAlign = hAlign;
@@ -40,5 +101,13 @@
     }
 
+    public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider) {
+        return create(env, boxProvider, null);
+    }
+
     public static BoxTextElemStyle create(Environment env, Rectangle box) {
+        return create(env, null, box);
+    }
+
+    public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider, Rectangle box) {
         initDefaultParameters();
         Cascade c = env.mc.getCascade(env.layer);
@@ -74,5 +143,17 @@
         }
 
-        return new BoxTextElemStyle(c, text, box, hAlign, vAlign);
+        return new BoxTextElemStyle(c, text, boxProvider, box, hAlign, vAlign);
+    }
+
+    public Rectangle getBox() {
+        if (boxProvider != null) {
+            BoxProviderResult result = boxProvider.get();
+            if (!result.isTemporary()) {
+                box = result.getBox();
+                boxProvider = null;
+            }
+            return result.getBox();
+        }
+        return box;
     }
 
@@ -84,5 +165,5 @@
         Node n = new Node();
         n.put("name", "dummy");
-        SIMPLE_NODE_TEXT_ELEMSTYLE = create(new Environment(n, mc, "default", null), NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBox());
+        SIMPLE_NODE_TEXT_ELEMSTYLE = create(new Environment(n, mc, "default", null), NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBoxProvider());
         if (SIMPLE_NODE_TEXT_ELEMSTYLE == null) throw new AssertionError();
     }
@@ -113,8 +194,15 @@
             return false;
         final BoxTextElemStyle other = (BoxTextElemStyle) obj;
-        return text.equals(other.text) &&
-                box.equals(other.box) &&
-                hAlign == other.hAlign &&
-                vAlign == other.vAlign;
+        if (!text.equals(other.text)) return false;
+        if (boxProvider != null) {
+            if (!boxProvider.equals(other.boxProvider)) return false;
+        } else if (other.boxProvider != null) {
+            return false;
+        } else {
+            if (!box.equals(other.box)) return false;
+        }
+        if (hAlign != other.hAlign) return false;
+        if (vAlign != other.vAlign) return false;
+        return true;
     }
 
@@ -123,5 +211,9 @@
         int hash = super.hashCode();
         hash = 97 * hash + text.hashCode();
-        hash = 97 * hash + box.hashCode();
+        if (boxProvider != null) {
+            hash = 97 * hash + boxProvider.hashCode();
+        } else {
+            hash = 97 * hash + box.hashCode();
+        }
         hash = 97 * hash + hAlign.hashCode();
         hash = 97 * hash + vAlign.hashCode();
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 5054)
@@ -29,5 +29,5 @@
     private boolean defaultNodes, defaultLines;
     private int defaultNodesIdx, defaultLinesIdx;
-    
+
     public ElemStyles()
     {
@@ -317,7 +317,7 @@
                 if (nodeStyle != null) {
                     sl.add(nodeStyle);
-                    addIfNotNull(sl, BoxTextElemStyle.create(env, nodeStyle.getBox()));
+                    addIfNotNull(sl, BoxTextElemStyle.create(env, nodeStyle.getBoxProvider()));
                 } else {
-                    addIfNotNull(sl, BoxTextElemStyle.create(env, NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBox()));
+                    addIfNotNull(sl, BoxTextElemStyle.create(env, NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBoxProvider()));
                 }
             } else if (osm instanceof Relation) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java	(revision 5054)
@@ -1,8 +1,4 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.mappaint;
-
-import java.awt.Image;
-
-import javax.swing.ImageIcon;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -17,7 +13,7 @@
 public class LinePatternElemStyle extends ElemStyle {
 
-    public MapImage<Image> pattern;
+    public MapImage pattern;
 
-    public LinePatternElemStyle(Cascade c, MapImage<Image> pattern) {
+    public LinePatternElemStyle(Cascade c, MapImage pattern) {
         super(c, -1f);
         this.pattern = pattern;
@@ -30,9 +26,5 @@
         if (iconRef == null)
             return null;
-        ImageIcon icon = MapPaintStyles.getIcon(iconRef, -1, -1);
-        if (icon == null)
-            return null;
-        MapImage<Image> pattern = new MapImage<Image>(iconRef.iconName, iconRef.source);
-        pattern.img = icon.getImage();
+        MapImage pattern = new MapImage(iconRef.iconName, iconRef.source);
         return new LinePatternElemStyle(c, pattern);
     }
@@ -41,5 +33,5 @@
     public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member) {
         Way w = (Way)primitive;
-        painter.drawLinePattern(w, pattern.img);
+        painter.drawLinePattern(w, pattern.getImage());
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MapImage.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MapImage.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MapImage.java	(revision 5054)
@@ -3,20 +3,29 @@
 
 import static org.openstreetmap.josm.tools.Utils.equal;
+
 import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
 
 import javax.swing.GrayFilter;
 import javax.swing.ImageIcon;
 
-public class MapImage<I extends Image> {
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.BoxProvider;
+import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.BoxProviderResult;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ImageProvider.ImageCallback;
+import org.openstreetmap.josm.tools.Utils;
+
+public class MapImage {
     /**
      * ImageIcon can chage while the image is loading.
      */
-    public I img;
-
-    public int alpha = 255;
+    private BufferedImage img;
 
     /**
-     * The 4 following fields are only used to check for equality.
+     * The 5 following fields are only used to check for equality.
      */
+    public int alpha = 255;
     public String name;
     public StyleSource source;
@@ -24,4 +33,5 @@
     public int height = -1;
 
+    private boolean temporary;
     private Image disabledImg;
 
@@ -37,5 +47,103 @@
     }
 
-    // img changes when image is fully loaded and can't be used for equality check.
+    public BufferedImage getImage() {
+        if (img != null)
+            return img;
+        temporary = false;
+        new ImageProvider(name)
+                .setDirs(MapPaintStyles.getIconSourceDirs(source))
+                .setId("mappaint."+source.getPrefName())
+                .setArchive(source.zipIcons)
+                .setWidth(width)
+                .setHeight(height)
+                .setOptional(true)
+                .getInBackground(new ImageCallback() {
+                    @Override
+                    public void finished(ImageIcon result) {
+                        synchronized (MapImage.this) {
+                            if (result == null) {
+                                img = (BufferedImage) MapPaintStyles.getNoIcon_Icon(source).getImage();
+                            } else {
+                                img = (BufferedImage) result.getImage();
+                            }
+                            if (temporary) {
+                                Main.map.mapView.preferenceChanged(null); // otherwise repaint is ignored, because layer hasn't changed
+                                Main.map.mapView.repaint();
+                            }
+                            temporary = false;
+                        }
+                    }
+                }
+        );
+        synchronized (this) {
+            if (img == null) {
+                img = (BufferedImage) ImageProvider.get("clock").getImage();
+                temporary = true;
+            }
+        }
+        return img;
+    }
+
+    public int getWidth() {
+        return getImage().getWidth(null);
+    }
+
+    public int getHeight() {
+        return getImage().getHeight(null);
+    }
+
+    public float getAlphaFloat() {
+        return Utils.color_int2float(alpha);
+    }
+
+    /**
+     * Returns true, if image is not completely loaded and getImage() returns a temporary image.
+     */
+    public boolean isTemporary() {
+        return temporary;
+    }
+
+    protected class MapImageBoxProvider implements BoxProvider {
+        @Override
+        public BoxProviderResult get() {
+            return new BoxProviderResult(box(), temporary);
+        }
+
+        private Rectangle box() {
+            int w = getWidth(), h = getHeight();
+            return new Rectangle(-w/2, -h/2, w, h);
+        }
+
+        private MapImage getParent() {
+            return MapImage.this;
+        }
+
+        @Override
+        public int hashCode() {
+            return MapImage.this.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null || !(obj instanceof BoxProvider))
+                return false;
+            if (obj instanceof MapImageBoxProvider) {
+                MapImageBoxProvider other = (MapImageBoxProvider) obj;
+                return MapImage.this.equals(other.getParent());
+            } else if (temporary) {
+                return false;
+            } else {
+                final BoxProvider other = (BoxProvider) obj;
+                BoxProviderResult resultOther = other.get();
+                if (resultOther.isTemporary()) return false;
+                return box().equals(resultOther.getBox());
+            }
+        }
+    }
+
+    public BoxProvider getBoxProvider() {
+        return new MapImageBoxProvider();
+    }
+
     @Override
     public boolean equals(Object obj) {
@@ -43,4 +151,5 @@
             return false;
         final MapImage other = (MapImage) obj;
+        // img changes when image is fully loaded and can't be used for equality check.
         return  alpha == other.alpha &&
                 equal(name, other.name) &&
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 5054)
@@ -119,5 +119,5 @@
     }
 
-    private static List<String> getIconSourceDirs(StyleSource source) {
+    public static List<String> getIconSourceDirs(StyleSource source) {
         List<String> dirs = new LinkedList<String>();
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 5054)
@@ -6,9 +6,6 @@
 import java.awt.BasicStroke;
 import java.awt.Color;
-import java.awt.Image;
 import java.awt.Rectangle;
 import java.awt.Stroke;
-
-import javax.swing.ImageIcon;
 
 import org.openstreetmap.josm.Main;
@@ -20,4 +17,6 @@
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
+import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.BoxProvider;
+import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.SimpleBoxProvider;
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Utils;
@@ -27,8 +26,6 @@
  */
 public class NodeElemStyle extends ElemStyle {
-    public MapImage<Image> mapImage;
+    public MapImage mapImage;
     public Symbol symbol;
-
-    private ImageIcon disabledIcon;
 
     public enum SymbolShape { SQUARE, CIRCLE, TRIANGLE, PENTAGON, HEXAGON, HEPTAGON, OCTAGON, NONAGON, DECAGON }
@@ -95,5 +92,5 @@
     public static final StyleList DEFAULT_NODE_STYLELIST_TEXT = new StyleList(NodeElemStyle.SIMPLE_NODE_ELEMSTYLE, BoxTextElemStyle.SIMPLE_NODE_TEXT_ELEMSTYLE);
 
-    protected NodeElemStyle(Cascade c, MapImage<Image> mapImage, Symbol symbol) {
+    protected NodeElemStyle(Cascade c, MapImage mapImage, Symbol symbol) {
         super(c, 1000f);
         this.mapImage = mapImage;
@@ -108,5 +105,5 @@
         Cascade c = env.mc.getCascade(env.layer);
 
-        MapImage<Image> mapImage = createIcon(env);
+        MapImage mapImage = createIcon(env);
         Symbol symbol = null;
         if (mapImage == null) {
@@ -122,9 +119,9 @@
     }
 
-    private static MapImage<Image> createIcon(Environment env) {
+    private static MapImage createIcon(Environment env) {
         Cascade c = env.mc.getCascade(env.layer);
         Cascade c_def = env.mc.getCascade("default");
 
-        IconReference iconRef = c.get("icon-image", null, IconReference.class);
+        final IconReference iconRef = c.get("icon-image", null, IconReference.class);
         if (iconRef == null)
             return null;
@@ -145,18 +142,13 @@
         int height = heightF == null ? -1 : Math.round(heightF);
 
-        MapImage<Image> mapImage = new MapImage<Image>(iconRef.iconName, iconRef.source);
-
-        ImageIcon icon = MapPaintStyles.getIcon(iconRef, width, height);
-        if (icon == null) {
-            mapImage.img = MapPaintStyles.getNoIcon_Icon(iconRef.source).getImage();
-        } else {
-            mapImage.img = icon.getImage();
-            mapImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
-            Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
-            if (pAlpha != null) {
-                mapImage.alpha = pAlpha;
-            }
-            mapImage.width = width;
-            mapImage.height = height;
+        final MapImage mapImage = new MapImage(iconRef.iconName, iconRef.source);
+
+        mapImage.width = width;
+        mapImage.height = height;
+
+        mapImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
+        Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
+        if (pAlpha != null) {
+            mapImage.alpha = pAlpha;
         }
         return mapImage;
@@ -243,5 +235,5 @@
             Node n = (Node) primitive;
             if (mapImage != null && painter.isShowIcons()) {
-                painter.drawNodeIcon(n, (painter.isInactiveMode() || n.isDisabled()) ? mapImage.getDisabled() : mapImage.img,
+                painter.drawNodeIcon(n, (painter.isInactiveMode() || n.isDisabled()) ? mapImage.getDisabled() : mapImage.getImage(),
                         Utils.color_int2float(mapImage.alpha), selected, member);
             } else if (symbol != null) {
@@ -309,10 +301,9 @@
     }
 
-    public Rectangle getBox() {
+    public BoxProvider getBoxProvider() {
         if (mapImage != null) {
-            int w = mapImage.img.getWidth(null), h = mapImage.img.getHeight(null);
-            return new Rectangle(-w/2, -h/2, w, h);
+            return mapImage.getBoxProvider();
         } else if (symbol != null) {
-            return new Rectangle(-symbol.size/2, -symbol.size/2, symbol.size, symbol.size);
+            return new SimpleBoxProvider(new Rectangle(-symbol.size/2, -symbol.size/2, symbol.size, symbol.size));
         } else {
             // This is only executed once, so no performance concerns.
@@ -324,5 +315,5 @@
                     Main.pref.getInteger("mappaint.node.tagged-size", 3)
             );
-            return new Rectangle(-size/2, -size/2, size, size);
+            return new SimpleBoxProvider(new Rectangle(-size/2, -size/2, size, size));
         }
     }
Index: trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 5053)
+++ trunk/src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 5054)
@@ -32,4 +32,6 @@
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -104,4 +106,10 @@
     private static Map<String, ImageResource> cache = new HashMap<String, ImageResource>();
 
+    private final static ExecutorService imageFetcher = Executors.newSingleThreadExecutor();
+
+    public interface ImageCallback {
+        void finished(ImageIcon result);
+    }
+
     /**
      * @param subdir    Subdirectory the image lies in.
@@ -256,4 +264,32 @@
         else
             return ir.getImageIcon(new Dimension(width, height));
+    }
+
+    /**
+     * Load the image in a background thread.
+     *
+     * This method returns immediately and runs the image request
+     * asynchronously.
+     *
+     * @param callback is called, when the image is ready. This can happen
+     * before the call to getInBackground returns or it may be invoked some
+     * time (seconds) later.
+     * If no image is available, a null value is returned to callback (just
+     * like ImageProvider.get).
+     */
+    public void getInBackground(final ImageCallback callback) {
+        if (name.startsWith("http://") || name.startsWith("wiki://")) {
+            Runnable fetch = new Runnable() {
+                @Override
+                public void run() {
+                    ImageIcon result = get();
+                    callback.finished(result);
+                }
+            };
+            imageFetcher.submit(fetch);
+        } else {
+            ImageIcon result = get();
+            callback.finished(result);
+        }
     }
 
