diff --git a/src/org/openstreetmap/josm/data/Bounds.java b/src/org/openstreetmap/josm/data/Bounds.java
index 067a9c3..8ce17fd 100644
--- a/src/org/openstreetmap/josm/data/Bounds.java
+++ b/src/org/openstreetmap/josm/data/Bounds.java
@@ -7,9 +7,11 @@ import java.awt.geom.Rectangle2D;
 import java.text.DecimalFormat;
 import java.text.MessageFormat;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
 /**
@@ -398,12 +400,16 @@ public class Bounds {
      * @return the bounding box to Rectangle2D.Double
      */
     public Rectangle2D.Double asRect() {
-        double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
+        double w = getWidth();
         return new Rectangle2D.Double(minLon, minLat, w, maxLat-minLat);
     }
 
+    private double getWidth() {
+        return maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
+    }
+
     public double getArea() {
-        double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
+        double w = getWidth();
         return w * (maxLat - minLat);
     }
 
@@ -441,6 +447,32 @@ public class Bounds {
         maxLon = LatLon.toIntervalLon(maxLon);
     }
 
+    /**
+     * Visit points along the edge of this bounds instance.
+     * @param projection The projection that should be used to determine how often the edge should be split along a given corner.
+     * @param visitor A function to call for the points on the edge.
+     */
+    public void visitEdge(Projection projection, Consumer<LatLon> visitor) {
+        double width = getWidth();
+        double height = maxLat - minLat;
+        //TODO: Use projection to see if there is any need for doing this along each axis.
+        int splitX = Math.max((int) width / 10, 10);
+        int splitY = Math.max((int) height / 10, 10);
+
+        for (int step = 0; step < splitX; step++) {
+            visitor.accept(new LatLon(minLat, minLon + width * step / splitX));
+        }
+        for (int step = 0; step < splitY; step++) {
+            visitor.accept(new LatLon(minLat + height * step / splitY, maxLon));
+        }
+        for (int step = 0; step < splitX; step++) {
+            visitor.accept(new LatLon(maxLat, maxLon - width * step / splitX));
+        }
+        for (int step = 0; step < splitY; step++) {
+            visitor.accept(new LatLon(maxLat - height * step / splitY, minLon));
+        }
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(minLat, minLon, maxLat, maxLon);
diff --git a/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java b/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
index b8f290c..553e85b 100644
--- a/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
+++ b/src/org/openstreetmap/josm/data/osm/visitor/BoundingXYVisitor.java
@@ -53,8 +53,7 @@ public class BoundingXYVisitor extends AbstractVisitor {
      */
     public void visit(Bounds b) {
         if (b != null) {
-            visit(b.getMin());
-            visit(b.getMax());
+            b.visitEdge(Main.getProjection(), this::visit);
         }
     }
 
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java
index 63e4bb4..cdb1da9 100644
--- a/src/org/openstreetmap/josm/gui/MapView.java
+++ b/src/org/openstreetmap/josm/gui/MapView.java
@@ -17,7 +17,6 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionListener;
 import java.awt.geom.Area;
-import java.awt.geom.GeneralPath;
 import java.awt.image.BufferedImage;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
@@ -45,7 +44,6 @@ import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.ViewportData;
 import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
@@ -973,41 +971,12 @@ LayerManager.LayerChangeListener, MainLayerManager.ActiveLayerChangeListener {
     private void drawWorldBorders(Graphics2D tempG) {
         tempG.setColor(Color.WHITE);
         Bounds b = getProjection().getWorldBoundsLatLon();
-        double lat = b.getMinLat();
-        double lon = b.getMinLon();
-
-        Point p = getPoint(b.getMin());
-
-        GeneralPath path = new GeneralPath();
-
-        double d = 1.0;
-        path.moveTo(p.x, p.y);
-        double max = b.getMax().lat();
-        for (; lat <= max; lat += d) {
-            p = getPoint(new LatLon(lat >= max ? max : lat, lon));
-            path.lineTo(p.x, p.y);
-        }
-        lat = max; max = b.getMax().lon();
-        for (; lon <= max; lon += d) {
-            p = getPoint(new LatLon(lat, lon >= max ? max : lon));
-            path.lineTo(p.x, p.y);
-        }
-        lon = max; max = b.getMinLat();
-        for (; lat >= max; lat -= d) {
-            p = getPoint(new LatLon(lat <= max ? max : lat, lon));
-            path.lineTo(p.x, p.y);
-        }
-        lat = max; max = b.getMinLon();
-        for (; lon >= max; lon -= d) {
-            p = getPoint(new LatLon(lat, lon <= max ? max : lon));
-            path.lineTo(p.x, p.y);
-        }
 
         int w = getWidth();
         int h = getHeight();
 
         // Work around OpenJDK having problems when drawing out of bounds
-        final Area border = new Area(path);
+        final Area border = getState().getArea(b).getViewArea();
         // Make the viewport 1px larger in every direction to prevent an
         // additional 1px border when zooming in
         final Area viewport = new Area(new Rectangle(-1, -1, w + 2, h + 2));
diff --git a/src/org/openstreetmap/josm/gui/MapViewState.java b/src/org/openstreetmap/josm/gui/MapViewState.java
index f7dcd8d..fc08ac9 100644
--- a/src/org/openstreetmap/josm/gui/MapViewState.java
+++ b/src/org/openstreetmap/josm/gui/MapViewState.java
@@ -5,6 +5,8 @@ import java.awt.Container;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.awt.geom.Point2D.Double;
 import java.awt.geom.Rectangle2D;
@@ -213,6 +215,10 @@ public final class MapViewState {
                 topLeft.north() / scale);
     }
 
+    public LatLonRectangle getArea(Bounds bounds) {
+        return new LatLonRectangle(bounds);
+    }
+
     /**
      * Creates a new state that is the same as the current state except for that it is using a new center.
      * @param newCenter The new center coordinate.
@@ -490,4 +496,36 @@ public final class MapViewState {
         }
     }
 
+    /**
+     * This is a rectangle in lat/lon space.
+     * @author Michael Zangl
+     * @since xxx
+     */
+    public class LatLonRectangle {
+
+        private Bounds bounds;
+
+        LatLonRectangle(Bounds bounds) {
+            this.bounds = new Bounds(bounds);
+        }
+
+        /**
+         * Gets the approximate area this shape covers in view space.
+         * @return The area in view space
+         */
+        public Area getViewArea() {
+            Path2D area = new Path2D.Double();
+            bounds.visitEdge(getProjection(), latlon -> {
+                MapViewPoint point = getPointFor(latlon);
+                if (area.getCurrentPoint() == null) {
+                    area.moveTo(point.getInViewX(), point.getInViewY());
+                } else {
+                    area.lineTo(point.getInViewX(), point.getInViewY());
+                }
+            });
+            area.closePath();
+            return new Area(area);
+        }
+    }
+
 }
diff --git a/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java b/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
index 7bdfd1a..cef09f8 100644
--- a/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
@@ -12,11 +12,11 @@ import java.awt.Composite;
 import java.awt.Graphics2D;
 import java.awt.GraphicsEnvironment;
 import java.awt.GridBagLayout;
-import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.TexturePaint;
 import java.awt.event.ActionEvent;
 import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.util.ArrayList;
@@ -51,6 +51,7 @@ import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.conflict.Conflict;
 import org.openstreetmap.josm.data.conflict.ConflictCollection;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
@@ -81,6 +82,7 @@ import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
 import org.openstreetmap.josm.gui.io.AbstractIOTask;
@@ -110,6 +112,7 @@ import org.openstreetmap.josm.tools.date.DateUtils;
  * @since 17
  */
 public class OsmDataLayer extends AbstractModifiableLayer implements Listener, SelectionChangedListener {
+    private static final int HATCHED_SIZE = 15;
     /** Property used to know if this layer has to be saved on disk */
     public static final String REQUIRES_SAVE_TO_DISK_PROP = OsmDataLayer.class.getName() + ".requiresSaveToDisk";
     /** Property used to know if this layer has to be uploaded */
@@ -303,9 +306,9 @@ public class OsmDataLayer extends AbstractModifiableLayer implements Listener, S
     private final ConflictCollection conflicts;
 
     /**
-     * a paint texture for non-downloaded area
+     * a texture for non-downloaded area
      */
-    private static volatile TexturePaint hatched;
+    private static volatile BufferedImage hatched;
 
     static {
         createHatchTexture();
@@ -331,17 +334,16 @@ public class OsmDataLayer extends AbstractModifiableLayer implements Listener, S
      * Initialize the hatch pattern used to paint the non-downloaded area
      */
     public static void createHatchTexture() {
-        BufferedImage bi = new BufferedImage(15, 15, BufferedImage.TYPE_INT_ARGB);
+        BufferedImage bi = new BufferedImage(HATCHED_SIZE, HATCHED_SIZE, BufferedImage.TYPE_INT_ARGB);
         Graphics2D big = bi.createGraphics();
         big.setColor(getBackgroundColor());
         Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
         big.setComposite(comp);
-        big.fillRect(0, 0, 15, 15);
+        big.fillRect(0, 0, HATCHED_SIZE, HATCHED_SIZE);
         big.setColor(getOutsideColor());
         big.drawLine(-1, 6, 6, -1);
         big.drawLine(4, 16, 16, 4);
-        Rectangle r = new Rectangle(0, 0, 15, 15);
-        hatched = new TexturePaint(bi, r);
+        hatched = bi;
     }
 
     /**
@@ -407,14 +409,15 @@ public class OsmDataLayer extends AbstractModifiableLayer implements Listener, S
                 if (bounds.isCollapsed()) {
                     continue;
                 }
-                Point p1 = mv.getPoint(bounds.getMin());
-                Point p2 = mv.getPoint(bounds.getMax());
-                Rectangle r = new Rectangle(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), Math.abs(p2.x-p1.x), Math.abs(p2.y-p1.y));
-                a.subtract(new Area(r));
+
+                a.subtract(mv.getState().getArea(bounds).getViewArea());
             }
 
             // paint remainder
-            g.setPaint(hatched);
+            MapViewPoint anchor = mv.getState().getPointFor(new EastNorth(0, 0));
+            Rectangle2D anchorRect = new Rectangle2D.Double(anchor.getInView().getX() % HATCHED_SIZE,
+                    anchor.getInView().getY() % HATCHED_SIZE, HATCHED_SIZE, HATCHED_SIZE);
+            g.setPaint(new TexturePaint(hatched, anchorRect));
             g.fill(a);
         }
 
