Index: trunk/src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 4422)
+++ trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 4423)
@@ -43,8 +43,8 @@
 
     public Bounds(double minlat, double minlon, double maxlat, double maxlon) {
-        this.minLat = roundToOsmPrecision(minlat);
-        this.minLon = roundToOsmPrecision(minlon);
-        this.maxLat = roundToOsmPrecision(maxlat);
-        this.maxLon = roundToOsmPrecision(maxlon);
+        this.minLat = LatLon.roundToOsmPrecision(minlat);
+        this.minLon = LatLon.roundToOsmPrecision(minlon);
+        this.maxLat = LatLon.roundToOsmPrecision(maxlat);
+        this.maxLon = LatLon.roundToOsmPrecision(maxlon);
     }
 
@@ -53,8 +53,8 @@
         if (coords.length != 4)
             throw new IllegalArgumentException(MessageFormat.format("Expected array of length 4, got {0}", coords.length));
-        this.minLat = roundToOsmPrecision(coords[0]);
-        this.minLon = roundToOsmPrecision(coords[1]);
-        this.maxLat = roundToOsmPrecision(coords[2]);
-        this.maxLon = roundToOsmPrecision(coords[3]);
+        this.minLat = LatLon.roundToOsmPrecision(coords[0]);
+        this.minLon = LatLon.roundToOsmPrecision(coords[1]);
+        this.maxLat = LatLon.roundToOsmPrecision(coords[2]);
+        this.maxLon = LatLon.roundToOsmPrecision(coords[3]);
     }
 
@@ -81,8 +81,8 @@
             throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", values[3]));
 
-        this.minLat = roundToOsmPrecision(values[0]);
-        this.minLon = roundToOsmPrecision(values[1]);
-        this.maxLat = roundToOsmPrecision(values[2]);
-        this.maxLon = roundToOsmPrecision(values[3]);
+        this.minLat = LatLon.roundToOsmPrecision(values[0]);
+        this.minLon = LatLon.roundToOsmPrecision(values[1]);
+        this.maxLat = LatLon.roundToOsmPrecision(values[2]);
+        this.maxLon = LatLon.roundToOsmPrecision(values[3]);
     }
 
@@ -114,8 +114,8 @@
             throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "lonExtent", lonExtent));
 
-        this.minLat = roundToOsmPrecision(center.lat() - latExtent / 2);
-        this.minLon = roundToOsmPrecision(center.lon() - lonExtent / 2);
-        this.maxLat = roundToOsmPrecision(center.lat() + latExtent / 2);
-        this.maxLon = roundToOsmPrecision(center.lon() + lonExtent / 2);
+        this.minLat = LatLon.roundToOsmPrecision(center.lat() - latExtent / 2);
+        this.minLon = LatLon.roundToOsmPrecision(center.lon() - lonExtent / 2);
+        this.maxLat = LatLon.roundToOsmPrecision(center.lat() + latExtent / 2);
+        this.maxLon = LatLon.roundToOsmPrecision(center.lon() + lonExtent / 2);
     }
 
@@ -145,14 +145,14 @@
     public void extend(LatLon ll) {
         if (ll.lat() < minLat) {
-            minLat = roundToOsmPrecision(ll.lat());
+            minLat = LatLon.roundToOsmPrecision(ll.lat());
         }
         if (ll.lon() < minLon) {
-            minLon = roundToOsmPrecision(ll.lon());
+            minLon = LatLon.roundToOsmPrecision(ll.lon());
         }
         if (ll.lat() > maxLat) {
-            maxLat = roundToOsmPrecision(ll.lat());
+            maxLat = LatLon.roundToOsmPrecision(ll.lat());
         }
         if (ll.lon() > maxLon) {
-            maxLon = roundToOsmPrecision(ll.lon());
+            maxLon = LatLon.roundToOsmPrecision(ll.lon());
         }
     }
@@ -284,13 +284,3 @@
         return true;
     }
-
-    /**
-     * Returns the value rounded to OSM precisions, i.e. to
-     * LatLon.MAX_SERVER_PRECISION
-     *
-     * @return rounded value
-     */
-    private double roundToOsmPrecision(double value) {
-        return Math.round(value / LatLon.MAX_SERVER_PRECISION) * LatLon.MAX_SERVER_PRECISION;
-    }
 }
Index: trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 4422)
+++ trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 4423)
@@ -223,5 +223,15 @@
         return "LatLon[lat="+lat()+",lon="+lon()+"]";
     }
-
+    
+    /**
+     * Returns the value rounded to OSM precisions, i.e. to
+     * LatLon.MAX_SERVER_PRECISION
+     *
+     * @return rounded value
+     */
+    public static double roundToOsmPrecision(double value) {
+        return Math.round(value / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION;
+    }
+    
     /**
      * Replies a clone of this lat LatLon, rounded to OSM precisions, i.e. to
@@ -232,6 +242,6 @@
     public LatLon getRoundedToOsmPrecision() {
         return new LatLon(
-                Math.round(lat() / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION,
-                Math.round(lon() / MAX_SERVER_PRECISION) * MAX_SERVER_PRECISION
+                roundToOsmPrecision(lat()),
+                roundToOsmPrecision(lon())
         );
     }
Index: trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 4422)
+++ trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 4423)
@@ -39,4 +39,24 @@
         public String getUrlString() {
             return urlString;
+        }
+    }
+    
+    public static class ImageryBounds extends Bounds {
+        public ImageryBounds(String asString, String separator) {
+            super(asString, separator);
+        }
+
+        private List<Shape> shapes = new ArrayList<Shape>();
+        
+        public void addShape(Shape shape) {
+            this.shapes.add(shape);
+        }
+
+        public void setShapes(List<Shape> shapes) {
+            this.shapes = shapes;
+        }
+
+        public List<Shape> getShapes() {
+            return shapes;
         }
     }
@@ -52,5 +72,5 @@
     private int defaultMaxZoom = 0;
     private int defaultMinZoom = 0;
-    private Bounds bounds = null;
+    private ImageryBounds bounds = null;
     private List<String> serverProjections;
     private String attributionText;
@@ -107,4 +127,15 @@
         res.add(attributionImage);
         res.add(termsOfUseURL);
+        // Shapes
+        String shapesString = "";
+        if (bounds != null) {
+            for (Shape s : bounds.getShapes()) {
+                if (!shapesString.isEmpty()) {
+                    shapesString += ";";
+                }
+                shapesString += s.encodeAsString(",");
+            }
+        }
+        res.add(shapesString.isEmpty() ? null : shapesString);
         return res;
     }
@@ -128,5 +159,5 @@
         if(array.size() >= 5 && !array.get(4).isEmpty()) {
             try {
-                bounds = new Bounds(array.get(4), ",");
+                bounds = new ImageryBounds(array.get(4), ",");
             } catch (IllegalArgumentException e) {
                 Main.warn(e.toString());
@@ -144,4 +175,13 @@
         if(array.size() >= 9 && !array.get(8).isEmpty()) {
             setTermsOfUseURL(array.get(8));
+        }
+        if(bounds != null && array.size() >= 10 && !array.get(9).isEmpty()) {
+            try {
+                for (String s : array.get(9).split(";")) {
+                    bounds.addShape(new Shape(s, ","));
+                }
+            } catch (IllegalArgumentException e) {
+                Main.warn(e.toString());
+            }
         }
     }
@@ -201,14 +241,14 @@
     }
 
-    public void setBounds(Bounds b) {
+    public void setBounds(ImageryBounds b) {
         this.bounds = b;
     }
 
-    public Bounds getBounds() {
+    public ImageryBounds getBounds() {
         return bounds;
     }
 
     public void setAttributionText(String text) {
-         attributionText = text;
+        attributionText = text;
     }
 
Index: trunk/src/org/openstreetmap/josm/data/imagery/Shape.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/Shape.java	(revision 4423)
+++ trunk/src/org/openstreetmap/josm/data/imagery/Shape.java	(revision 4423)
@@ -0,0 +1,74 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.imagery;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+/**
+ * @author Vincent
+ *
+ */
+public class Shape {
+
+    private List<Coordinate> coords = new ArrayList<Coordinate>();
+    
+    public Shape(String asString, String separator) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(asString, "asString");
+        String[] components = asString.split(separator);
+        if (components.length % 2 != 0)
+            throw new IllegalArgumentException(MessageFormat.format("Even number of doubles excpected in string, got {0}: {1}", components.length, asString));
+        for (int i=0; i<components.length; i+=2) {
+            addPoint(components[i], components[i+1]);
+        }
+    }
+
+    public Shape() {
+    }
+
+    public String encodeAsString(String separator) {
+        StringBuffer sb = new StringBuffer();
+        for (Coordinate c : coords) {
+            if (sb.length() != 0) {
+                sb.append(separator);
+            }
+            sb.append(c.getLat()).append(separator).append(c.getLon());
+        }
+        return sb.toString();
+    }
+
+    public List<Coordinate> getPoints() {
+        return coords;
+    }
+
+    public void addPoint(String sLat, String sLon) throws IllegalArgumentException {
+        CheckParameterUtil.ensureParameterNotNull(sLat, "sLat");
+        CheckParameterUtil.ensureParameterNotNull(sLon, "sLon");
+
+        double lat, lon;
+        
+        try {
+            lat = Double.parseDouble(sLat);
+            if (!LatLon.isValidLat(lat))
+                throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", lat));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", sLat));
+        }
+
+        try {
+            lon = Double.parseDouble(sLon);
+            if (!LatLon.isValidLon(lon))
+                throw new IllegalArgumentException(tr("Illegal longitude value ''{0}''", lon));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", sLon));
+        }
+        
+        coords.add(new Coordinate(LatLon.roundToOsmPrecision(lat), LatLon.roundToOsmPrecision(lon)));
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 4422)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/ImageryPreference.java	(revision 4423)
@@ -18,4 +18,5 @@
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -51,12 +52,15 @@
 
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
 import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
+import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
+import org.openstreetmap.josm.data.imagery.Shape;
 import org.openstreetmap.josm.gui.layer.ImageryLayer;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
@@ -418,5 +422,5 @@
             map.setZoomContolsVisible(false);
             map.setPreferredSize(new Dimension(200, 200));
-            add(map, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.333, 0.6).insets(5, 0, 0, 0));
+            add(map, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
 
             listdef.getSelectionModel().addListSelectionListener(new DefListSelectionListener());
@@ -460,40 +464,71 @@
         // Listener of default providers list selection
         private final class DefListSelectionListener implements ListSelectionListener {
-            // The current drawn rectangles
+            // The current drawn rectangles and polygons
             private final Map<Integer, MapRectangle> mapRectangles;
+            private final Map<Integer, List<MapPolygon>> mapPolygons;
 
             private DefListSelectionListener() {
                 this.mapRectangles = new HashMap<Integer, MapRectangle>();
+                this.mapPolygons = new HashMap<Integer, List<MapPolygon>>();
             }
 
             @Override
             public void valueChanged(ListSelectionEvent e) {
-                // First index is set to -1 when the list is refreshed, so discard all map rectangles
+                // First index is set to -1 when the list is refreshed, so discard all map rectangles and polygons
                 if (e.getFirstIndex() == -1) {
                     map.removeAllMapRectangles();
+                    map.removeAllMapPolygons();
                     mapRectangles.clear();
+                    mapPolygons.clear();
                     // Only process complete (final) selection events
                 } else if (!e.getValueIsAdjusting()) {
                     for (int i = e.getFirstIndex(); i<=e.getLastIndex(); i++) {
-                        Bounds bounds = modeldef.getRow(i).getBounds();
-                        if (bounds != null) {
-                            if (listdef.getSelectionModel().isSelectedIndex(i)) {
-                                if (!mapRectangles.containsKey(i)) {
-                                    // Add new map rectangle
-                                    MapRectangle rectangle = new MapRectangleImpl(bounds);
-                                    mapRectangles.put(i, rectangle);
-                                    map.addMapRectangle(rectangle);
+                        updateBoundsAndShapes(i);
+                    }
+                    // If needed, adjust map to show all map rectangles and polygons
+                    if (!mapRectangles.isEmpty() || !mapPolygons.isEmpty()) {
+                        map.setDisplayToFitMapElements(false, true, true);
+                        map.zoomOut();
+                    }
+                }
+            }
+            
+            private void updateBoundsAndShapes(int i) {
+                ImageryBounds bounds = modeldef.getRow(i).getBounds();
+                if (bounds != null) {
+                    List<Shape> shapes = bounds.getShapes();
+                    if (shapes != null && !shapes.isEmpty()) {
+                        if (listdef.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapPolygons.containsKey(i)) {
+                                List<MapPolygon> list = new ArrayList<MapPolygon>();
+                                mapPolygons.put(i, list);
+                                // Add new map polygons
+                                for (Shape shape : shapes) {
+                                    MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
+                                    list.add(polygon);
+                                    map.addMapPolygon(polygon);
                                 }
-                            } else if (mapRectangles.containsKey(i)) {
-                                // Remove previousliy drawn map rectangle
-                                map.removeMapRectangle(mapRectangles.get(i));
-                                mapRectangles.remove(i);
                             }
+                        } else if (mapPolygons.containsKey(i)) {
+                            // Remove previously drawn map polygons
+                            for (MapPolygon polygon : mapPolygons.get(i)) {
+                                map.removeMapPolygon(polygon);
+                            }
+                            mapPolygons.remove(i);
                         }
-                    }
-                    // If needed, adjust map to show all map rectangles
-                    if (!mapRectangles.isEmpty()) {
-                        map.setDisplayToFitMapRectangle();
-                        map.zoomOut();
+                     // Only display bounds when no polygons (shapes) are defined for this provider
+                    } else {
+                        if (listdef.getSelectionModel().isSelectedIndex(i)) {
+                            if (!mapRectangles.containsKey(i)) {
+                                // Add new map rectangle
+                                MapRectangle rectangle = new MapRectangleImpl(bounds);
+                                mapRectangles.put(i, rectangle);
+                                map.addMapRectangle(rectangle);
+                            }
+                        } else if (mapRectangles.containsKey(i)) {
+                            // Remove previously drawn map rectangle
+                            map.removeMapRectangle(mapRectangles.get(i));
+                            mapRectangles.remove(i);
+                        }
                     }
                 }
Index: trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 4422)
+++ trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 4423)
@@ -19,7 +19,8 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.imagery.Shape;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.io.UTFInputStreamReader;
@@ -41,8 +42,10 @@
         SUPPORTED_PROJECTIONS,
         PR,
+        BOUNDS,
+        SHAPE,
         UNKNOWN,            // element is not recognized in the current context
     }
 
-    public ImageryReader(String source) throws IOException {
+    public ImageryReader(String source) {
         this.source = source;
     }
@@ -143,5 +146,5 @@
                             // 5th parameter optional for bounds
                             try {
-                                info.setBounds(new Bounds(val[4], ","));
+                                info.setBounds(new ImageryBounds(val[4], ","));
                             } catch (IllegalArgumentException e) {
                                 Main.warn(e.toString());
@@ -190,5 +193,6 @@
 
         ImageryInfo entry;
-        Bounds bounds;
+        ImageryBounds bounds;
+        Shape shape;
         List<String> supported_srs;
 
@@ -241,5 +245,5 @@
                     } else if (qName.equals("bounds")) {
                         try {
-                            bounds = new Bounds(
+                            bounds = new ImageryBounds(
                                     atts.getValue("min-lat") + "," +
                                     atts.getValue("min-lon") + "," +
@@ -249,8 +253,23 @@
                             break;
                         }
-                        newState = State.ENTRY_ATTRIBUTE;
+                        newState = State.BOUNDS;
                     } else if (qName.equals("supported-projections")) {
                         supported_srs = new ArrayList<String>();
                         newState = State.SUPPORTED_PROJECTIONS;
+                    }
+                    break;
+                case BOUNDS:
+                    if (qName.equals("shape")) {
+                        shape = new Shape();
+                        newState = State.SHAPE;
+                    }
+                    break;
+                case SHAPE:
+                    if (qName.equals("point")) {
+                        try {
+                            shape.addPoint(atts.getValue("lat"), atts.getValue("lon"));
+                        } catch (IllegalArgumentException e) {
+                            break;
+                        }
                     }
                     break;
@@ -339,7 +358,4 @@
                             }
                         }
-                    } else if (qName.equals("bounds")) {
-                        entry.setBounds(bounds);
-                        bounds = null;
                     } else if (qName.equals("attribution-text")) {
                         entry.setAttributionText(accumulator.toString());
@@ -359,4 +375,12 @@
                     }
                     break;
+                case BOUNDS:
+                    entry.setBounds(bounds);
+                    bounds = null;
+                    break;
+                case SHAPE:
+                    bounds.addShape(shape);
+                    shape = null;
+                    break;
                 case PR:
                     supported_srs.add(accumulator.toString());
