Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 12720)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 12722)
@@ -9,4 +9,5 @@
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.awt.Shape;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
@@ -15,4 +16,5 @@
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionListener;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Area;
 import java.awt.image.BufferedImage;
@@ -511,4 +513,29 @@
 
     private void drawMapContent(Graphics g) {
+        // In HiDPI-mode, the Graphics g will have a transform that scales
+        // everything by a factor of 2.0 or so. At the same time, the value returned
+        // by getWidth()/getHeight will be reduced by that factor.
+        //
+        // This would work as intended, if we were to draw directly on g. But
+        // with a temporary buffer image, we need to move the scale transform to
+        // the Graphics of the buffer image and (in the end) transfer the content
+        // of the temporary buffer pixel by pixel onto g, without scaling.
+        // (Otherwise, we would upscale a small buffer image and the result would be
+        // blurry, with 2x2 pixel blocks.)
+        Graphics2D gg = (Graphics2D) g;
+        AffineTransform trOrig = gg.getTransform();
+        double uiScaleX = gg.getTransform().getScaleX();
+        double uiScaleY = gg.getTransform().getScaleY();
+        // width/height in full-resolution screen pixels
+        int width = (int) Math.round(getWidth() * uiScaleX);
+        int height = (int) Math.round(getHeight() * uiScaleY);
+        // This transformation corresponds to the original transformation of g,
+        // except for the translation part. It will be applied to the temporary
+        // buffer images.
+        AffineTransform trDef = AffineTransform.getScaleInstance(uiScaleX, uiScaleY);
+        // The goal is to create the temporary image at full pixel resolution,
+        // so scale up the clip shape
+        Shape scaledClip = trDef.createTransformedShape(g.getClip());
+
         List<Layer> visibleLayers = layerManager.getVisibleLayersInZOrder();
 
@@ -529,20 +556,18 @@
                 && nonChangedLayers.equals(visibleLayers.subList(0, nonChangedLayers.size()));
 
-        if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) {
-            offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
-        }
-
-        Graphics2D tempG = offscreenBuffer.createGraphics();
-        tempG.setClip(g.getClip());
+        if (null == offscreenBuffer || offscreenBuffer.getWidth() != width || offscreenBuffer.getHeight() != height) {
+            offscreenBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+        }
 
         if (!canUseBuffer || nonChangedLayersBuffer == null) {
             if (null == nonChangedLayersBuffer
-                    || nonChangedLayersBuffer.getWidth() != getWidth() || nonChangedLayersBuffer.getHeight() != getHeight()) {
-                nonChangedLayersBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
+                    || nonChangedLayersBuffer.getWidth() != width || nonChangedLayersBuffer.getHeight() != height) {
+                nonChangedLayersBuffer = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
             }
             Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
-            g2.setClip(g.getClip());
+            g2.setClip(scaledClip);
+            g2.setTransform(trDef);
             g2.setColor(PaintColors.getBackgroundColor());
-            g2.fillRect(0, 0, getWidth(), getHeight());
+            g2.fillRect(0, 0, width, height);
 
             for (int i = 0; i < nonChangedLayersCount; i++) {
@@ -553,5 +578,6 @@
             if (nonChangedLayers.size() != nonChangedLayersCount) {
                 Graphics2D g2 = nonChangedLayersBuffer.createGraphics();
-                g2.setClip(g.getClip());
+                g2.setClip(scaledClip);
+                g2.setTransform(trDef);
                 for (int i = nonChangedLayers.size(); i < nonChangedLayersCount; i++) {
                     paintLayer(visibleLayers.get(i), g2);
@@ -565,5 +591,9 @@
         lastClipBounds = g.getClipBounds();
 
+        Graphics2D tempG = offscreenBuffer.createGraphics();
+        tempG.setClip(scaledClip);
+        tempG.setTransform(new AffineTransform());
         tempG.drawImage(nonChangedLayersBuffer, 0, 0, null);
+        tempG.setTransform(trDef);
 
         for (int i = nonChangedLayersCount; i < visibleLayers.size(); i++) {
@@ -572,5 +602,7 @@
 
         try {
-            drawTemporaryLayers(tempG, getLatLonBounds(g.getClipBounds()));
+            drawTemporaryLayers(tempG, getLatLonBounds(new Rectangle(
+                    (int) Math.round(g.getClipBounds().x * uiScaleX),
+                    (int) Math.round(g.getClipBounds().y * uiScaleY))));
         } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
             BugReport.intercept(e).put("temporaryLayers", temporaryLayers).warn();
@@ -597,5 +629,6 @@
 
         try {
-            g.drawImage(offscreenBuffer, 0, 0, null);
+            gg.setTransform(new AffineTransform(1, 0, 0, 1, trOrig.getTranslateX(), trOrig.getTranslateY()));
+            gg.drawImage(offscreenBuffer, 0, 0, null);
         } catch (ClassCastException e) {
             // See #11002 and duplicate tickets. On Linux with Java >= 8 Many users face this error here:
@@ -623,4 +656,6 @@
             // But the application seems to work fine after, so let's just log the error
             Logging.error(e);
+        } finally {
+            gg.setTransform(trOrig);
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/AreaElement.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/AreaElement.java	(revision 12720)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/AreaElement.java	(revision 12722)
@@ -3,4 +3,6 @@
 
 import java.awt.Color;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
 import java.util.Objects;
 
@@ -16,4 +18,5 @@
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.HiDPISupport;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -79,6 +82,9 @@
         if (iconRef != null) {
             fillImage = new MapImage(iconRef.iconName, iconRef.source, false);
-
-            color = new Color(fillImage.getImage(false).getRGB(
+            Image img = fillImage.getImage(false);
+            // get base image from possible multi-resolution image, so we can
+            // cast to BufferedImage and get pixel value at the center of the image
+            img = HiDPISupport.getBaseImage(img);
+            color = new Color(((BufferedImage) img).getRGB(
                     fillImage.getWidth() / 2, fillImage.getHeight() / 2)
             );
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java	(revision 12720)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/MapImage.java	(revision 12722)
@@ -32,5 +32,5 @@
      * ImageIcon can change while the image is loading.
      */
-    private BufferedImage img;
+    private Image img;
 
     /**
@@ -102,5 +102,5 @@
      * @return the image
      */
-    public BufferedImage getImage(boolean disabled) {
+    public Image getImage(boolean disabled) {
         if (disabled) {
             return getDisabled();
@@ -110,5 +110,5 @@
     }
 
-    private BufferedImage getDisabled() {
+    private Image getDisabled() {
         if (disabledImgCache != null)
                 return disabledImgCache;
@@ -127,5 +127,5 @@
     }
 
-    private BufferedImage getImage() {
+    private Image getImage() {
         if (img != null)
             return img;
@@ -144,7 +144,7 @@
                             source.logWarning(tr("Failed to locate image ''{0}''", name));
                             ImageIcon noIcon = MapPaintStyles.getNoIconIcon(source);
-                            img = noIcon == null ? null : (BufferedImage) noIcon.getImage();
+                            img = noIcon == null ? null : noIcon.getImage();
                         } else {
-                            img = (BufferedImage) rescale(result.getImage());
+                            img = rescale(result.getImage());
                         }
                         if (temporary) {
@@ -160,5 +160,5 @@
         synchronized (this) {
             if (img == null) {
-                img = (BufferedImage) ImageProvider.get("clock").getImage();
+                img = ImageProvider.get("clock").getImage();
                 temporary = true;
             }
