Index: trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java	(revision 19335)
+++ trunk/src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java	(revision 19336)
@@ -155,8 +155,37 @@
      */
     public static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWays(Relation multipolygon) {
+        return joinWays(null, multipolygon);
+    }
+
+    /**
+     * Joins the given {@code multipolygon} to a pair of outer and inner multipolygon rings.
+     *
+     * @param multipolygon the multipolygon to join.
+     * @return a pair of outer and inner multipolygon rings.
+     * @throws JoinedPolygonCreationException if the creation fails.
+     * @since xxx
+     */
+    public static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWays(
+            Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> cache, Relation multipolygon) {
+        if (cache != null) {
+            return cache.computeIfAbsent(multipolygon, MultipolygonBuilder::joinWaysActual);
+        }
+        return joinWaysActual(multipolygon);
+    }
+
+    /**
+     * Perform the actual join ways calculation
+     *
+     * @param multipolygon the multipolygon to join.
+     * @return a pair of outer and inner multipolygon rings.
+     * @throws JoinedPolygonCreationException if the creation fails.
+     */
+    private static Pair<List<JoinedPolygon>, List<JoinedPolygon>> joinWaysActual(IRelation<?> multipolygon) {
         CheckParameterUtil.ensureThat(multipolygon.isMultipolygon(), "multipolygon.isMultipolygon");
-        final Map<String, Set<Way>> members = multipolygon.getMembers().stream()
-                .filter(RelationMember::isWay)
-                .collect(Collectors.groupingBy(RelationMember::getRole, Collectors.mapping(RelationMember::getWay, Collectors.toSet())));
+        CheckParameterUtil.ensureThat(multipolygon instanceof Relation,
+                "This method currently only supports Relation objects due to potential breakage");
+        final Map<String, Set<Way>> members = ((Relation) multipolygon).getMembers().stream()
+                .filter(IRelationMember::isWay)
+                .collect(Collectors.groupingBy(IRelationMember::getRole, Collectors.mapping(RelationMember::getWay, Collectors.toSet())));
         final List<JoinedPolygon> outerRings = joinWays(members.getOrDefault("outer", Collections.emptySet()));
         final List<JoinedPolygon> innerRings = joinWays(members.getOrDefault("inner", Collections.emptySet()));
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 19335)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 19336)
@@ -25,4 +25,6 @@
 
 import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
@@ -50,4 +52,5 @@
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Stopwatch;
 import org.openstreetmap.josm.tools.Utils;
@@ -61,4 +64,5 @@
     private final Map<MapCSSRule, MapCSSTagCheckerAndRule> ruleToCheckMap = new HashMap<>();
     private static final Map<IPrimitive, Area> mpAreaCache = new HashMap<>();
+    private static final Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> mpJoinedAreaCache = new HashMap<>();
     private static final Set<IPrimitive> toMatchForSurrounding = new HashSet<>();
     static final boolean ALL_TESTS = true;
@@ -164,4 +168,5 @@
         final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null);
         env.mpAreaCache = mpAreaCache;
+        env.mpJoinedAreaCache = mpJoinedAreaCache;
         env.toMatchForSurrounding = toMatchForSurrounding;
 
@@ -222,4 +227,5 @@
         final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null);
         env.mpAreaCache = mpAreaCache;
+        env.mpJoinedAreaCache = mpJoinedAreaCache;
         env.toMatchForSurrounding = toMatchForSurrounding;
         for (Set<MapCSSTagCheckerRule> schecks : checksCol) {
@@ -377,4 +383,5 @@
         mpAreaCache.clear();
         ruleToCheckMap.clear();
+        mpJoinedAreaCache.clear();
         toMatchForSurrounding.clear();
         super.endTest();
@@ -397,4 +404,5 @@
 
         mpAreaCache.clear();
+        mpJoinedAreaCache.clear();
         toMatchForSurrounding.clear();
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 19335)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 19336)
@@ -9,4 +9,6 @@
 
 import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
+import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
@@ -16,4 +18,5 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -91,4 +94,8 @@
      */
     public Map<IPrimitive, Area> mpAreaCache;
+    /**
+     * Cache for multipolygon areas as calculated by {@link MultipolygonBuilder#joinWays(Relation)}, can be {@code null}
+     */
+    public Map<IRelation<?>, Pair<List<MultipolygonBuilder.JoinedPolygon>, List<MultipolygonBuilder.JoinedPolygon>>> mpJoinedAreaCache;
 
     /**
@@ -163,4 +170,5 @@
         this.crossingWaysMap = other.crossingWaysMap;
         this.mpAreaCache = other.mpAreaCache;
+        this.mpJoinedAreaCache = other.mpJoinedAreaCache;
         this.toMatchForSurrounding = other.toMatchForSurrounding;
         this.selector = selector;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 19335)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 19336)
@@ -491,5 +491,5 @@
                 if (r instanceof Relation && r.isMultipolygon() && r.getBBox().bounds(e.osm.getBBox())
                         && left.matches(new Environment(r).withParent(e.osm))
-                        && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r).isEmpty()) {
+                        && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r, e.mpJoinedAreaCache).isEmpty()) {
                     addToChildren(e, r);
                 }
Index: trunk/src/org/openstreetmap/josm/tools/Geometry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 19335)
+++ trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 19336)
@@ -18,4 +18,5 @@
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -33,4 +34,5 @@
 import org.openstreetmap.josm.data.osm.INode;
 import org.openstreetmap.josm.data.osm.IPrimitive;
+import org.openstreetmap.josm.data.osm.IRelation;
 import org.openstreetmap.josm.data.osm.IWay;
 import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
@@ -1192,5 +1194,5 @@
                     polygonArea = getArea(polygon.getNodes());
                 }
-                Multipolygon mp = new Multipolygon((Relation) p);
+                Multipolygon mp = p.getDataSet() != null ? MultipolygonCache.getInstance().get((Relation) p) : new Multipolygon((Relation) p);
                 boolean inside = true;
                 // a (valid) multipolygon is inside the polygon if all outer rings are inside
@@ -1221,4 +1223,18 @@
      */
     public static List<IPrimitive> filterInsideMultipolygon(Collection<IPrimitive> primitives, Relation multiPolygon) {
+        return filterInsideMultipolygon(primitives, multiPolygon, null);
+    }
+
+    /**
+     * Find all primitives in the given collection which are inside the given multipolygon. Members of the multipolygon are
+     * ignored. Unclosed ways and multipolygon relations with unclosed outer rings are ignored.
+     * @param primitives the primitives
+     * @param multiPolygon the multipolygon relation
+     * @param cache The cache to avoid calculating joined inner/outer ways multiple times (see {@link MultipolygonBuilder#joinWays(Relation)})
+     * @return a new list containing the found primitives, empty if multipolygon is invalid or nothing was found.
+     * @since xxx
+     */
+    public static List<IPrimitive> filterInsideMultipolygon(Collection<IPrimitive> primitives, Relation multiPolygon,
+                                                            Map<IRelation<?>, Pair<List<JoinedPolygon>, List<JoinedPolygon>>> cache) {
         List<IPrimitive> res = new ArrayList<>();
         if (primitives.isEmpty())
@@ -1227,5 +1243,5 @@
         final Pair<List<JoinedPolygon>, List<JoinedPolygon>> outerInner;
         try {
-            outerInner = MultipolygonBuilder.joinWays(multiPolygon);
+            outerInner = MultipolygonBuilder.joinWays(cache, multiPolygon);
         } catch (MultipolygonBuilder.JoinedPolygonCreationException ex) {
             Logging.trace(ex);
Index: trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java	(revision 19335)
+++ trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java	(revision 19336)
@@ -368,13 +368,13 @@
         mp2.put("type", "multipolygon");
         assertFalse(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null));
-        assertFalse(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2).contains(w1));
+        assertFalse(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2, null).contains(w1));
 
         node4.setCoor(new LatLon(1.006, 0.99));
         // now w1 is inside
         assertTrue(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp2, null));
-        assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2).contains(w1));
-        assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(mp1), mp2).contains(mp1));
-        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(w1));
-        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2).contains(mp1));
+        assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(w1), mp2, null).contains(w1));
+        assertTrue(Geometry.filterInsideMultipolygon(Collections.singletonList(mp1), mp2, null).contains(mp1));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2, null).contains(w1));
+        assertTrue(Geometry.filterInsideMultipolygon(Arrays.asList(w1, mp1), mp2, null).contains(mp1));
     }
 
