Index: trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 15958)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 15959)
@@ -3,6 +3,6 @@
 
 import java.awt.geom.Area;
-import java.util.HashMap;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -10,4 +10,6 @@
 import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
@@ -72,7 +74,17 @@
 
     /**
+     * Crossing ways result from CrossingFinder, filled for incomplete ways/relations
+    */
+    public Map<IPrimitive, Map<List<Way>, List<WaySegment>>> crossingWaysMap;
+
+    /**
      * Intersection areas (only filled with CrossingFinder if children is not null)
      */
     public Map<IPrimitive, Area> intersections;
+
+    /**
+     * Cache for multipolygon areas, can be null, used with CrossingFinder
+     */
+    public Map<IPrimitive, Area> mpAreaCache;
 
     /**
@@ -126,5 +138,7 @@
         this.context = other.getContext();
         this.children = other.children == null ? null : new LinkedHashSet<>(other.children);
-        this.intersections = other.intersections == null ? null : new HashMap<>(other.intersections);
+        this.intersections = other.intersections;
+        this.crossingWaysMap = other.crossingWaysMap;
+        this.mpAreaCache = other.mpAreaCache;
     }
 
@@ -294,4 +308,5 @@
         children = null;
         intersections = null;
+        crossingWaysMap = null;
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 15958)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 15959)
@@ -5,4 +5,5 @@
 
 import java.awt.geom.Area;
+import java.awt.geom.Point2D;
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -12,4 +13,5 @@
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.function.IntFunction;
@@ -26,6 +28,9 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
+import org.openstreetmap.josm.data.validation.tests.CrossingWays;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.gui.mappaint.Range;
@@ -303,28 +308,90 @@
             private final String layer;
             private Area area;
+            /** Will contain all way segments, grouped by cells */
+            Map<Point2D, List<WaySegment>> cellSegments;
 
             private CrossingFinder(Environment e) {
                 super(e);
-                CheckParameterUtil.ensureThat(e.osm instanceof IWay, "Only ways are supported");
+                CheckParameterUtil.ensureThat(isArea(e.osm), "Only areas are supported");
                 layer = OsmUtils.getLayer(e.osm);
             }
 
-            @Override
-            public void visit(IWay<?> w) {
-                if (Objects.equals(layer, OsmUtils.getLayer(w))
-                    && left.matches(new Environment(w).withParent(e.osm))
-                    && e.osm instanceof IWay) {
-                    if (area == null) {
-                        area = Geometry.getAreaEastNorth(e.osm);
-                    }
-                    Pair<PolygonIntersection, Area> is = Geometry.polygonIntersectionResult(
-                            Geometry.getAreaEastNorth(w), area, Geometry.INTERSECTION_EPS_EAST_NORTH);
-                    if (Geometry.PolygonIntersection.CROSSING == is.a) {
-                        addToChildren(e, w);
-                        // store intersection area to improve highlight and zoom to problem
-                        if (e.intersections == null) {
-                            e.intersections = new HashMap<>();
+            private Area getAreaEastNorth(IPrimitive p, Environment e) {
+                if (e.mpAreaCache != null && p.isMultipolygon()) {
+                    Area a = e.mpAreaCache.get(p);
+                    if (a == null) {
+                        a = Geometry.getAreaEastNorth(p);
+                        e.mpAreaCache.put(p, a);
+                    }
+                    return a;
+                }
+                return Geometry.getAreaEastNorth(p);
+            }
+
+            private Map<List<Way>, List<WaySegment>> findCrossings(IPrimitive area,
+                    Map<Point2D, List<WaySegment>> cellSegments) {
+                /** The detected crossing ways */
+                Map<List<Way>, List<WaySegment>> crossingWays = new HashMap<>(50);
+                if (area instanceof Way) {
+                    CrossingWays.findIntersectingWay((Way) area, cellSegments, crossingWays, false);
+                } else if (area instanceof Relation && area.isMultipolygon()) {
+                    Relation r = (Relation) area;
+                    for (Way w : r.getMemberPrimitives(Way.class)) {
+                        if (!w.hasIncompleteNodes()) {
+                            CrossingWays.findIntersectingWay(w, cellSegments, crossingWays, false);
                         }
-                        e.intersections.put(w, is.b);
+                    }
+                }
+                return crossingWays;
+            }
+
+            @Override
+            public void visit(Collection<? extends IPrimitive> primitives) {
+                List<? extends IPrimitive> toIgnore;
+                if (e.osm instanceof Relation) {
+                    toIgnore = ((IRelation<?>) e.osm).getMemberPrimitivesList();
+                } else {
+                    toIgnore = null;
+                }
+
+                for (IPrimitive p : primitives) {
+                    if (isPrimitiveUsable(p) && Objects.equals(layer, OsmUtils.getLayer(p))
+                            && left.matches(new Environment(p).withParent(e.osm)) && isArea(p)
+                            && (toIgnore == null || !toIgnore.contains(p))) {
+                        if (area == null) {
+                            area = getAreaEastNorth(e.osm, e);
+                        }
+                        Area otherArea = getAreaEastNorth(p, e);
+                        if (area.isEmpty() || otherArea.isEmpty()) {
+                            if (cellSegments == null) {
+                                // lazy initialisation
+                                cellSegments = new HashMap<>();
+                                findCrossings(e.osm, cellSegments); // ignore self intersections etc. here
+                            }
+                            // need a copy
+                            final Map<Point2D, List<WaySegment>> tmpCellSegments = new HashMap<>(cellSegments);
+                            // calculate all crossings between e.osm and p
+                            Map<List<Way>, List<WaySegment>> crossingWays = findCrossings(p, tmpCellSegments);
+                            if (!crossingWays.isEmpty()) {
+                                addToChildren(e, p);
+                                if (e.crossingWaysMap == null) {
+                                    e.crossingWaysMap = new HashMap<>();
+                                }
+                                e.crossingWaysMap.put(p, crossingWays);
+                            }
+                        } else {
+                            // we have complete data. This allows to find intersections with shared nodes
+                            // See #16707
+                            Pair<PolygonIntersection, Area> is = Geometry.polygonIntersectionResult(
+                                    otherArea, area, Geometry.INTERSECTION_EPS_EAST_NORTH);
+                            if (Geometry.PolygonIntersection.CROSSING == is.a) {
+                                addToChildren(e, p);
+                                // store intersection area to improve highlight and zoom to problem
+                                if (e.intersections == null) {
+                                    e.intersections = new HashMap<>();
+                                }
+                                e.intersections.put(p, is.b);
+                            }
+                        }
                     }
                 }
@@ -453,11 +520,10 @@
                 return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null;
 
-            } else if (ChildOrParentSelectorType.CROSSING == type && e.osm instanceof IWay) {
+            } else if (ChildOrParentSelectorType.CROSSING == type) {
                 e.parent = e.osm;
-                if (right instanceof OptimizedGeneralSelector
-                        && e.osm.getDataSet() != null
-                        && ((OptimizedGeneralSelector) right).matchesBase(OsmPrimitiveType.WAY)) {
+                if (e.osm.getDataSet() != null && isArea(e.osm)) {
                     final CrossingFinder crossingFinder = new CrossingFinder(e);
-                    crossingFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
+                    visitBBox(e, crossingFinder);
+                    return e.children != null;
                 }
                 return e.children != null;
