Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 7053)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 7054)
@@ -19,4 +19,6 @@
 import org.openstreetmap.josm.data.osm.Node;
 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.gui.mappaint.Cascade;
 import org.openstreetmap.josm.gui.mappaint.Environment;
@@ -24,5 +26,7 @@
 import org.openstreetmap.josm.gui.mappaint.Range;
 import org.openstreetmap.josm.gui.mappaint.StyleSource;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.OptimizedGeneralSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
@@ -42,5 +46,12 @@
     public static final String MAPCSS_STYLE_MIME_TYPES = "text/x-mapcss, text/mapcss, text/css; q=0.9, text/plain; q=0.8, application/zip, application/octet-stream; q=0.5";
 
-    public final List<MapCSSRule> rules;
+    // all rules
+    public final List<MapCSSRule> rules = new ArrayList<>();
+    // rules filtered by primitive type
+    public final List<MapCSSRule> nodeRules = new ArrayList<>();
+    public final List<MapCSSRule> wayRules = new ArrayList<>();
+    public final List<MapCSSRule> relationRules = new ArrayList<>();
+    public final List<MapCSSRule> multipolygonRules = new ArrayList<>();
+    
     private Color backgroundColorOverride;
     private String css = null;
@@ -49,10 +60,8 @@
     public MapCSSStyleSource(String url, String name, String shortdescription) {
         super(url, name, shortdescription);
-        rules = new ArrayList<>();
     }
 
     public MapCSSStyleSource(SourceEntry entry) {
         super(entry);
-        rules = new ArrayList<>();
     }
 
@@ -68,5 +77,4 @@
         CheckParameterUtil.ensureParameterNotNull(css);
         this.css = css;
-        rules = new ArrayList<>();
     }
 
@@ -75,4 +83,8 @@
         init();
         rules.clear();
+        nodeRules.clear();
+        wayRules.clear();
+        relationRules.clear();
+        multipolygonRules.clear();
         try (InputStream in = getSourceInputStream()) {
             try {
@@ -104,6 +116,48 @@
             logError(new ParseException(e.getMessage())); // allow e to be garbage collected, it links to the entire token stream
         }
-    }
-
+        // optimization: filter rules for different primitive types
+        for (MapCSSRule r: rules) {
+            List<Selector> nodeSel = new ArrayList<>();
+            List<Selector> waySel = new ArrayList<>();
+            List<Selector> relationSel = new ArrayList<>();
+            List<Selector> multipolygonSel = new ArrayList<>();
+            for (Selector sel : r.selectors) {
+                // find the rightmost selector, this must be a GeneralSelector
+                Selector selRightmost = sel;
+                while (selRightmost instanceof ChildOrParentSelector) {
+                    selRightmost = ((ChildOrParentSelector) selRightmost).right;
+                }
+                Selector optimizedSel = sel.optimizedBaseCheck();
+                switch (((GeneralSelector) selRightmost).getBase()) {
+                    case "node":
+                        nodeSel.add(optimizedSel);
+                        break;
+                    case "way":
+                        waySel.add(optimizedSel);
+                        break;
+                    case "area":
+                        waySel.add(optimizedSel);
+                        multipolygonSel.add(optimizedSel);
+                        break;
+                    case "relation":
+                        relationSel.add(optimizedSel);
+                        multipolygonSel.add(optimizedSel);
+                        break;
+                    case "*":
+                        nodeSel.add(optimizedSel);
+                        waySel.add(optimizedSel);
+                        relationSel.add(optimizedSel);
+                        multipolygonSel.add(optimizedSel);
+                        break;
+                }
+            }
+            nodeRules.add(new MapCSSRule(nodeSel, r.declaration));
+            wayRules.add(new MapCSSRule(waySel, r.declaration));
+            relationRules.add(new MapCSSRule(relationSel, r.declaration));
+            multipolygonRules.add(new MapCSSRule(multipolygonSel, r.declaration));
+        }
+        rules.clear();
+    }
+    
     @Override
     public InputStream getSourceInputStream() throws IOException {
@@ -188,5 +242,17 @@
     public void apply(MultiCascade mc, OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) {
         Environment env = new Environment(osm, mc, null, this);
-        RULE: for (MapCSSRule r : rules) {
+        List<MapCSSRule> matchingRules;
+        if (osm instanceof Node) {
+            matchingRules = nodeRules;
+        } else if (osm instanceof Way) {
+            matchingRules = wayRules;
+        } else {
+            if (((Relation) osm).isMultipolygon()) {
+                matchingRules = multipolygonRules;
+            } else {
+                matchingRules = relationRules;
+            }
+        }
+        RULE: for (MapCSSRule r : matchingRules) {
             for (Selector s : r.selectors) {
                 env.clearSelectorMatchingInformation();
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 7053)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 7054)
@@ -22,4 +22,18 @@
 import org.openstreetmap.josm.tools.Utils;
 
+/**
+ * MapCSS selector.
+ * 
+ * A rule has two parts, a selector and a declaration block
+ * e.g.
+ * <pre>
+ * way[highway=residential]    
+ * { width: 10; color: blue; } 
+ * </pre>
+ * 
+ * The selector decides, if the declaration block gets applied or not.
+ * 
+ * Currently all implementing classes of Selector are immutable.
+ */
 public interface Selector {
 
@@ -32,9 +46,23 @@
      * @return true, if the selector applies
      */
-    public boolean matches(Environment env);
-
-    public String getSubpart();
-
-    public Range getRange();
+    boolean matches(Environment env);
+    
+    String getSubpart();
+
+    Range getRange();
+    
+    /**
+     * Create an "optimized" copy of this selector that omits the base check.
+     * 
+     * For the style source, the list of rules is preprocessed, such that
+     * there is a separate list of rules for nodes, ways, ...
+     * 
+     * This means that the base check does not have to be performed
+     * for each rule, but only once for each primitive.
+     * 
+     * @return a selector that is identical to this object, except the base of the
+     * "rightmost" selector is not checked
+     */
+    Selector optimizedBaseCheck();
 
     public static enum ChildOrParentSelectorType {
@@ -319,4 +347,9 @@
             return right.getRange();
         }
+        
+        @Override
+        public Selector optimizedBaseCheck() {
+            return new ChildOrParentSelector(left, link, right.optimizedBaseCheck(), type);
+        }
 
         @Override
@@ -348,5 +381,5 @@
          * @return {@code true} if all conditions apply, false otherwise.
          */
-        public final boolean matchesConditions(Environment env) {
+        public boolean matches(Environment env) {
             if (conds == null) return true;
             for (Condition c : conds) {
@@ -378,5 +411,5 @@
         public boolean matches(Environment env) {
             Utils.ensure(env.isLinkContext(), "Requires LINK context in environment, got ''{0}''", env.getContext());
-            return matchesConditions(env);
+            return super.matches(env);
         }
 
@@ -392,4 +425,9 @@
 
         @Override
+        public Selector optimizedBaseCheck() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
         public String toString() {
             return "LinkSelector{" + "conditions=" + conds + '}';
@@ -397,10 +435,63 @@
     }
 
-    public static class GeneralSelector extends AbstractSelector {
+    public static class GeneralSelector extends OptimizedGeneralSelector {
+
+        public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
+            super(base, zoom, conds, subpart);
+        }
+        
+        public boolean matchesBase(OsmPrimitiveType type) {
+            if ("*".equals(base)) {
+                return true;
+            } else if (OsmPrimitiveType.NODE.equals(type)) {
+                return "node".equals(base);
+            } else if (OsmPrimitiveType.WAY.equals(type)) {
+                return "way".equals(base) || "area".equals(base);
+            } else if (OsmPrimitiveType.RELATION.equals(type)) {
+                return "area".equals(base) || "relation".equals(base) || "canvas".equals(base);
+            }
+            return false;
+        }
+
+        public boolean matchesBase(OsmPrimitive p) {
+            if (!matchesBase(p.getType())) {
+                return false;
+            } else {
+                if (p instanceof Relation) {
+                    if ("area".equals(base)) {
+                        return ((Relation) p).isMultipolygon();
+                    } else if ("canvas".equals(base)) {
+                        return p.get("#canvas") != null;
+                    }
+                }
+                return true;
+            }
+        }
+
+        public boolean matchesBase(Environment e) {
+            return matchesBase(e.osm);
+        }
+        
+        public boolean matchesConditions(Environment e) {
+            return super.matches(e);
+        }
+
+        @Override
+        public Selector optimizedBaseCheck() {
+            return new OptimizedGeneralSelector(this);
+        }
+
+        @Override
+        public boolean matches(Environment e) {
+            return matchesBase(e) && super.matches(e);
+        }
+    }
+    
+    public static class OptimizedGeneralSelector extends AbstractSelector {
         public final String base;
         public final Range range;
         public final String subpart;
 
-        public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
+        public OptimizedGeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
             super(conds);
             this.base = base;
@@ -418,4 +509,15 @@
             this.subpart = subpart;
         }
+        
+        public OptimizedGeneralSelector(String base, Range range, List<Condition> conds, String subpart) {
+            super(conds);
+            this.base = base;
+            this.range = range;
+            this.subpart = subpart;
+        }
+        
+        public OptimizedGeneralSelector(GeneralSelector s) {
+            this(s.base, s.range, s.conds, s.subpart);
+        }
 
         @Override
@@ -428,45 +530,13 @@
         }
 
-        public boolean matchesBase(OsmPrimitiveType type) {
-            if ("*".equals(base)) {
-                return true;
-            } else if (OsmPrimitiveType.NODE.equals(type)) {
-                return "node".equals(base);
-            } else if (OsmPrimitiveType.WAY.equals(type)) {
-                return "way".equals(base) || "area".equals(base);
-            } else if (OsmPrimitiveType.RELATION.equals(type)) {
-                return "area".equals(base) || "relation".equals(base) || "canvas".equals(base);
-            }
-            return false;
-        }
-
-        public boolean matchesBase(OsmPrimitive p) {
-            if (!matchesBase(p.getType())) {
-                return false;
-            } else {
-                if (p instanceof Relation) {
-                    if ("area".equals(base)) {
-                        return ((Relation) p).isMultipolygon();
-                    } else if ("canvas".equals(base)) {
-                        return p.get("#canvas") != null;
-                    }
-                }
-                return true;
-            }
-        }
-
-        public boolean matchesBase(Environment e) {
-            return matchesBase(e.osm);
-        }
-
-        @Override
-        public boolean matches(Environment e) {
-            return matchesBase(e) && matchesConditions(e);
-        }
-
         public String getBase() {
             return base;
         }
 
+        @Override
+        public Selector optimizedBaseCheck() {
+            throw new UnsupportedOperationException();
+        }
+        
         public static Range fromLevel(int a, int b) {
             if (a > b)
