Index: src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(Revision 3995)
+++ src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(Arbeitskopie)
@@ -5,6 +5,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map.Entry;
@@ -21,6 +22,7 @@
 
 public class ElemStyles {
     private List<StyleSource> styleSources;
+    private HashMap<String, HashMap<OsmPrimitive, Environment>> envs;
     private boolean drawMultipolygon;
 
     private int cacheIdx;
@@ -28,6 +30,7 @@
     public ElemStyles()
     {
         styleSources = new ArrayList<StyleSource>();
+        envs = new HashMap<String, HashMap<OsmPrimitive, Environment>>();
     }
 
     public void clearCached() {
@@ -83,9 +86,7 @@
 
     private Pair<StyleList, Range> getImpl(OsmPrimitive osm, double scale, NavigatableComponent nc) {
         if (osm instanceof Node)
-        {
             return generateStyles(osm, scale, null, false);
-        }
         else if (osm instanceof Way)
         {
             Pair<StyleList, Range> p = generateStyles(osm, scale, null, false);
@@ -121,9 +122,9 @@
                         Pair<StyleList, Range> mpElemStyles = getStyleCacheWithRange(r, scale, nc);
                         LineElemStyle mpLine = Utils.find(mpElemStyles.a, LineElemStyle.class);
                         if (mpLine != null) {
-                                p.a = new StyleList(p.a, mpLine);
-                                p.b = Range.cut(p.b, mpElemStyles.b);
-                                break;
+                            p.a = new StyleList(p.a, mpLine);
+                            p.b = Range.cut(p.b, mpElemStyles.b);
+                            break;
                         } else if (wayColor == null) {
                             AreaElemStyle mpArea = Utils.find(mpElemStyles.a, AreaElemStyle.class);
                             if (mpArea != null) {
@@ -198,6 +199,13 @@
         return null;
     }
 
+    public Environment getEnvironment(OsmPrimitive osm, MultiCascade mc, String layer, StyleSource source) {
+        return (envs.containsKey(layer) && envs.get(layer).containsKey(osm)
+                ? envs.get(layer).get(osm)
+                        : new Environment(osm, mc, layer, source)
+        );
+    }
+
     /**
      * @param multipolyOuterWay support for a very old multipolygon tagging style
      * where you add the tags both to the outer and the inner way.
@@ -219,10 +227,18 @@
         }
 
         for (Entry<String, Cascade> e : mc.getLayers()) {
-            if ("*".equals(e.getKey()))
+            if ("*".equals(e.getKey())) {
                 continue;
+            }
             env.layer = e.getKey();
             Cascade c = e.getValue();
+
+            if (envs.containsKey(env.layer)) {
+                envs.get(env.layer).put(env.osm, env);
+            } else {
+                envs.put(env.layer, new HashMap<OsmPrimitive, Environment>());
+            }
+
             if (osm instanceof Way) {
                 addIfNotNull(sl, AreaElemStyle.create(c));
                 addIfNotNull(sl, LineElemStyle.createLine(env));
Index: src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java	(Revision 3995)
+++ src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java	(Arbeitskopie)
@@ -108,7 +108,18 @@
         public String compose(OsmPrimitive primitive) {
             if (defaultLabelTag == null) return null;
             if (primitive == null) return null;
-            return primitive.get(defaultLabelTag);
+
+            String res = new String("");
+            if (defaultLabelTag.indexOf(' ') >= 0) {
+                String tags[] = defaultLabelTag.split(" ");
+                for (String tag : tags) {
+                    res += (primitive.get(tag)==null) ? tag : primitive.get(tag);
+                    res += ' ';
+                }
+            } else {
+                res = primitive.get(defaultLabelTag);
+            }
+            return res;
         }
 
         public String getDefaultLabelTag() {
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(Revision 3995)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(Arbeitskopie)
@@ -57,6 +57,24 @@
         public static class EvalFunctions {
             Environment env;
 
+            private Environment getEnvironment(String key, String layer) {
+                Environment res = env;
+
+                if (layer == null) {
+                    layer = env.layer;
+                }
+
+                while (key.startsWith("parent.")) {
+                    if (res != null) {
+                        res = (Environment) res.mc.getCascade(layer).get("env-parent");
+
+                    }
+                    key = key.replaceFirst("parent[.]", "");
+                }
+
+                return (res==null)?env:res;
+            }
+
             public Object eval(Object o) {
                 return o;
             }
@@ -72,9 +90,8 @@
             public Float minus(float... args) {
                 if (args.length == 0)
                     return 0f;
-                if (args.length == 1) { // unary minus
+                if (args.length == 1)
                     return -args[0];
-                }
                 float res = args[0];
                 for (int i=1; i<args.length; ++i) {
                     res -= args[i];
@@ -134,12 +151,13 @@
 
             public Object prop(String key, String layer) {
                 Cascade c;
+                Environment e = getEnvironment(key, layer);
                 if (layer == null) {
-                    c = env.mc.getCascade(env.layer);
+                    c = e.mc.getCascade(e.layer);
                 } else {
-                    c = env.mc.getCascade(layer);
+                    c = e.mc.getCascade(layer);
                 }
-                return c.get(key);
+                return c.get(key.replaceAll("parent[.]", ""));
             }
 
             public Boolean is_prop_set(String key) {
@@ -148,25 +166,34 @@
 
             public Boolean is_prop_set(String key, String layer) {
                 Cascade c;
+                Environment e = getEnvironment(key, layer);
                 if (layer == null) {
                     // env.layer is null if expression is evaluated
                     // in ExpressionCondition, but MultiCascade.getCascade
                     // handles this
-                    c = env.mc.getCascade(env.layer);
+                    c = e.mc.getCascade(e.layer);
                 } else {
-                    c = env.mc.getCascade(layer);
+                    c = e.mc.getCascade(layer);
                 }
-                return c.containsKey(key);
+                return c.containsKey(key.replaceAll("parent[.]", ""));
             }
 
             public String get_tag_value(String key) {
-                return env.osm.get(key);
+                return getEnvironment(key, null).osm.get(key.replaceAll("parent[.]", ""));
             }
 
             public boolean has_tag_key(String key) {
-                return env.osm.hasKey(key);
+                return getEnvironment(key, null).osm.hasKey(key.replaceAll("parent[.]", ""));
             }
 
+            public String concat(Object... args) {
+                String res = new String("");
+                for (Object f : args) {
+                    res += f.toString();
+                }
+                return res;
+            }
+
             public boolean not(boolean b) {
                 return !b;
             }
@@ -212,7 +239,7 @@
                 } catch (ParseError ex) {
                     return null;
                 }
-                return m.match(env.osm);
+                return m.match(getEnvironment(s, null).osm);
             }
 
             public String JOSM_pref(String s, String def) {
@@ -285,8 +312,9 @@
                 throw  new RuntimeException(ex);
             }
             for (Method m : allMethods) {
-                if (!m.getName().equals(name))
+                if (!m.getName().equals(name)) {
                     continue;
+                }
                 Class<?>[] expectedParameterTypes = m.getParameterTypes();
                 Object[] convertedArgs = new Object[expectedParameterTypes.length];
 
@@ -303,8 +331,9 @@
                     }
                     convertedArgs[0] = arrayArg;
                 } else {
-                    if (args.size() != expectedParameterTypes.length)
+                    if (args.size() != expectedParameterTypes.length) {
                         continue;
+                    }
                     for (int i=0; i<args.size(); ++i) {
                         convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
                         if (convertedArgs[i] == null)
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(Revision 3995)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(Arbeitskopie)
@@ -109,23 +109,24 @@
         Environment env = new Environment(n, mc, "default", this);
 
         NEXT_RULE:
-        for (MapCSSRule r : rules) {
-            for (Selector s : r.selectors) {
-                if ((s instanceof GeneralSelector)) {
-                    GeneralSelector gs = (GeneralSelector) s;
-                    if (gs.base.equals(type))
-                     {
-                        for (Condition cnd : gs.conds) {
-                            if (!cnd.applies(env))
-                                continue NEXT_RULE;
+            for (MapCSSRule r : rules) {
+                for (Selector s : r.selectors) {
+                    if ((s instanceof GeneralSelector)) {
+                        GeneralSelector gs = (GeneralSelector) s;
+                        if (gs.base.equals(type))
+                        {
+                            for (Condition cnd : gs.conds) {
+                                if (!cnd.applies(env)) {
+                                    continue NEXT_RULE;
+                                }
+                            }
+                            for (Instruction i : r.declaration) {
+                                i.execute(env);
+                            }
                         }
-                        for (Instruction i : r.declaration) {
-                            i.execute(env);
-                        }
                     }
                 }
             }
-        }
         return mc.getCascade("default");
     }
 
@@ -139,6 +140,12 @@
         Environment env = new Environment(osm, mc, null, this);
         for (MapCSSRule r : rules) {
             for (Selector s : r.selectors) {
+                String sub = s.getSubpart();
+                if (sub == null) {
+                    sub = "default";
+                }
+                env.layer = sub;
+
                 if (s.applies(env)) {
                     if (s.getRange().contains(scale)) {
                         mc.range = Range.cut(mc.range, s.getRange());
@@ -147,11 +154,6 @@
                         continue;
                     }
 
-                    String sub = s.getSubpart();
-                    if (sub == null) {
-                        sub = "default";
-                    }
-
                     if (sub.equals("*")) {
                         for (Entry<String, Cascade> entry : mc.getLayers()) {
                             env.layer = entry.getKey();
@@ -163,7 +165,7 @@
                             }
                         }
                     }
-                    env.layer = sub;
+
                     for (Instruction i : r.declaration) {
                         i.execute(env);
                     }
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(Revision 3995)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(Arbeitskopie)
@@ -9,12 +9,13 @@
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.gui.mappaint.Range;
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Utils;
 
 public interface Selector {
-    
+
     public boolean applies(Environment e);
 
     public String getSubpart();
@@ -35,23 +36,25 @@
             if (!b.applies(e))
                 return false;
 
-            Environment e2 = new Environment(null, e.mc, e.layer, e.source);
+            Environment e2 = null;
             if (child) {
                 for (OsmPrimitive osm : e.osm.getReferrers()) {
-                    e2.osm = osm;
-                    if (a.applies(e2))
+                    e2 = MapPaintStyles.getStyles().getEnvironment(osm, e.mc, e.layer, e.source);
+                    if (a.applies(e2)) {
+                        e.mc.getOrCreateCascade(e2.layer).putOrClear("env-parent", e2);
                         return true;
+                    }
                 }
             } else {
                 if (e.osm instanceof Relation) {
                     for (OsmPrimitive chld : ((Relation) e.osm).getMemberPrimitives()) {
-                        e2.osm = chld;
+                        e2 = MapPaintStyles.getStyles().getEnvironment(chld, e.mc, e.layer, e.source);
                         if (a.applies(e2))
                             return true;
                     }
                 } else if (e.osm instanceof Way) {
                     for (Node n : ((Way) e.osm).getNodes()) {
-                        e2.osm = n;
+                        e2 = MapPaintStyles.getStyles().getEnvironment(n, e.mc, e.layer, e.source);
                         if (a.applies(e2))
                             return true;
                     }
