Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 11358)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 11360)
@@ -163,4 +163,10 @@
     }
 
+    /**
+     * Class representing a string of ways.
+     *
+     * The last node of one way is the first way of the next one.
+     * The string may or may not be closed.
+     */
     public static class JoinedWay {
         protected final List<Node> nodes;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 11358)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 11360)
@@ -18,5 +18,4 @@
 import java.util.Locale;
 import java.util.Objects;
-import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Function;
@@ -966,7 +965,6 @@
          */
         public static boolean inside(Environment env, String codes) { // NO_UCD (unused code)
-            Set<String> osmCodes = Territories.getIso3166Codes(center(env));
             for (String code : codes.toUpperCase(Locale.ENGLISH).split(",")) {
-                if (osmCodes.contains(code.trim())) {
+                if (Territories.isIso3166Code(code.trim(), center(env))) {
                     return true;
                 }
Index: trunk/src/org/openstreetmap/josm/tools/DefaultGeoProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/DefaultGeoProperty.java	(revision 11358)
+++ trunk/src/org/openstreetmap/josm/tools/DefaultGeoProperty.java	(revision 11360)
@@ -7,4 +7,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 
@@ -14,5 +15,5 @@
 public class DefaultGeoProperty implements GeoProperty<Boolean> {
 
-    private Area area;
+    private final Area area;
 
     /**
@@ -22,12 +23,23 @@
      */
     public DefaultGeoProperty(Collection<Way> ways) {
+        Area area = null;
         for (Way w : ways) {
-            Area tmp = Geometry.getAreaLatLon(w.getNodes());
+            Area wayArea = Geometry.getAreaLatLon(w.getNodes());
             if (area == null) {
-                area = tmp;
+                area = wayArea;
             } else {
-                area.add(tmp);
+                area.add(wayArea);
             }
         }
+        this.area = area;
+    }
+
+    /**
+     * Create DefaultGeoProperty based on a multipolygon relation.
+     *
+     * @param multipolygon the multipolygon
+     */
+    public DefaultGeoProperty(Relation multipolygon) {
+        this.area = Geometry.getAreaLatLon(multipolygon);
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/Geometry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 11358)
+++ trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 11360)
@@ -478,6 +478,6 @@
     /**
      * Returns the Area of a polygon, from its list of nodes.
-     * @param polygon List of nodes forming polygon (EastNorth coordinates)
-     * @return Area for the given list of nodes
+     * @param polygon List of nodes forming polygon
+     * @return Area for the given list of nodes  (EastNorth coordinates)
      * @since 6841
      */
@@ -506,6 +506,6 @@
     /**
      * Returns the Area of a polygon, from its list of nodes.
-     * @param polygon List of nodes forming polygon (LatLon coordinates)
-     * @return Area for the given list of nodes
+     * @param polygon List of nodes forming polygon
+     * @return Area for the given list of nodes (LatLon coordinates)
      * @since 6841
      */
@@ -527,4 +527,29 @@
 
         return new Area(path);
+    }
+
+    /**
+     * Returns the Area of a polygon, from the multipolygon relation.
+     * @param multipolygon the multipolygon relation
+     * @return Area for the multipolygon (LatLon coordinates)
+     */
+    public static Area getAreaLatLon(Relation multipolygon) {
+        final Multipolygon mp = Main.map == null || Main.map.mapView == null
+                ? new Multipolygon(multipolygon)
+                : MultipolygonCache.getInstance().get(Main.map.mapView, multipolygon);
+        Area result = null;
+        for (Multipolygon.PolyData pd : mp.getCombinedPolygons()) {
+            Area area = getAreaLatLon(pd.getNodes());
+            for (Multipolygon.PolyData pdInner : pd.getInners()) {
+                Area areaInner = getAreaLatLon(pdInner.getNodes());
+                area.subtract(areaInner);
+            }
+            if (result == null) {
+                result = area;
+            } else {
+                result.add(area);
+            }
+        }
+        return result;
     }
 
Index: trunk/src/org/openstreetmap/josm/tools/Territories.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Territories.java	(revision 11358)
+++ trunk/src/org/openstreetmap/josm/tools/Territories.java	(revision 11360)
@@ -1,4 +1,6 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.tools;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.io.IOException;
@@ -6,15 +8,15 @@
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.SelectByInternalPointAction;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.IllegalDataException;
@@ -29,33 +31,7 @@
     private static final String ISO3166_2 = "ISO3166-2";
 
-    private static class Iso3166GeoProperty implements GeoProperty<Set<String>> {
+    private static DataSet dataSet;
 
-        @Override
-        public Set<String> get(LatLon ll) {
-            Set<String> result = new HashSet<>();
-            for (OsmPrimitive surrounding :
-                    SelectByInternalPointAction.getSurroundingObjects(dataSet, Main.getProjection().latlon2eastNorth(ll), true)) {
-                String iso1 = surrounding.get(ISO3166_1);
-                if (iso1 != null) {
-                    result.add(iso1);
-                }
-                String iso2 = surrounding.get(ISO3166_2);
-                if (iso2 != null) {
-                    result.add(iso2);
-                }
-            }
-            return result;
-        }
-
-        @Override
-        public Set<String> get(BBox box) {
-            return null; // TODO
-        }
-    }
-
-    private static DataSet dataSet;
-    private static final Map<String, OsmPrimitive> iso3166Map = new ConcurrentHashMap<>();
-
-    private static volatile GeoPropertyIndex<Set<String>> iso3166Cache;
+    private static volatile Map<String, GeoPropertyIndex<Boolean>> iso3166Cache;
 
     private Territories() {
@@ -69,15 +45,22 @@
      */
     public static synchronized Set<String> getKnownIso3166Codes() {
-        return iso3166Map.keySet();
+        return iso3166Cache.keySet();
     }
 
     /**
-     * Get the ISO3166-1 and ISO3166-2 codes for the given location.
+     * Determine, if a point is inside a territory with the given the ISO3166-1
+     * or ISO3166-2 code.
      *
+     * @param code the ISO3166-1 or ISO3166-2 code
      * @param ll the coordinates of the point
-     * @return the ISO3166-1 and ISO3166-2 codes for the given location
+     * @return true, if the point is inside a territory with the given code
      */
-    public static synchronized Set<String> getIso3166Codes(LatLon ll) {
-        return iso3166Cache.get(ll);
+    public static synchronized boolean isIso3166Code(String code, LatLon ll) {
+        GeoPropertyIndex<Boolean> gpi = iso3166Cache.get(code);
+        if (gpi == null) {
+            Main.warn(tr("Unknown territory id: {0}", code));
+            return false;
+        }
+        return gpi.get(ll);
     }
 
@@ -95,5 +78,5 @@
      */
     public static synchronized void initialize() {
-        iso3166Cache = new GeoPropertyIndex<>(new Iso3166GeoProperty(), 24);
+        iso3166Cache = new HashMap<>();
         try (CachedFile cf = new CachedFile("resource://data/boundaries.osm");
                 InputStream is = cf.getInputStream()) {
@@ -103,10 +86,19 @@
             for (OsmPrimitive osm : candidates) {
                 String iso1 = osm.get(ISO3166_1);
-                if (iso1 != null) {
-                    iso3166Map.put(iso1, osm);
-                }
                 String iso2 = osm.get(ISO3166_2);
-                if (iso2 != null) {
-                    iso3166Map.put(iso2, osm);
+                if (iso1 != null || iso2 != null) {
+                    GeoProperty<Boolean> gp;
+                    if (osm instanceof Way) {
+                        gp = new DefaultGeoProperty(Collections.singleton((Way) osm));
+                    } else {
+                        gp = new DefaultGeoProperty((Relation) osm);
+                    }
+                    GeoPropertyIndex gpi = new GeoPropertyIndex(gp, 24);
+                    if (iso1 != null) {
+                        iso3166Cache.put(iso1, gpi);
+                    }
+                    if (iso2 != null) {
+                        iso3166Cache.put(iso2, gpi);
+                    }
                 }
             }
