Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 7098)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 7099)
@@ -127,5 +127,5 @@
         Cascade c = env.mc.getCascade(env.layer);
 
-        final IconReference iconRef = c.get(keys[ICON_IMAGE_IDX], null, IconReference.class);
+        final IconReference iconRef = c.get(keys[ICON_IMAGE_IDX], null, IconReference.class, true);
         if (iconRef == null)
             return null;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 7098)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 7099)
@@ -419,5 +419,5 @@
     public static class ExpressionCondition extends Condition {
 
-        private Expression e;
+        private final Expression e;
 
         public ExpressionCondition(Expression e) {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 7098)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 7099)
@@ -47,9 +47,10 @@
     private static final List<Method> arrayFunctions;
     private static final List<Method> parameterFunctions;
-    private static final Functions FUNCTIONS_INSTANCE = new Functions();
+    private static final List<Method> parameterFunctionsEnv;
 
     static {
         arrayFunctions = new ArrayList<>();
         parameterFunctions = new ArrayList<>();
+        parameterFunctionsEnv = new ArrayList<>();
         for (Method m : Functions.class.getDeclaredMethods()) {
             Class<?>[] paramTypes = m.getParameterTypes();
@@ -57,5 +58,9 @@
                 arrayFunctions.add(m);
             } else {
-                parameterFunctions.add(m);
+                if (paramTypes[0].equals(Environment.class)) {
+                    parameterFunctionsEnv.add(m);
+                } else {
+                    parameterFunctions.add(m);
+                }
             }
         }
@@ -91,8 +96,18 @@
     }
 
+    /**
+     * List of functions that can be used in MapCSS expressions.
+     * 
+     * First parameter can be of type {@link Environment} (if needed). This is
+     * automatically filled in by JOSM and the user only sees the remaining
+     * arguments.
+     * When one of the user supplied arguments cannot be converted the
+     * expected type or is null, the function is not called and it returns null
+     * immediately. Add the annotation {@link NullableArguments} to allow
+     * null arguments.
+     * Every method must be static.
+     */
     @SuppressWarnings("UnusedDeclaration")
     public static class Functions {
-
-        Environment env;
 
         /**
@@ -265,5 +280,5 @@
             return Utils.color_int2float(c.getAlpha());
         }
-
+        
         /**
          * Assembles the strings to one.
@@ -287,6 +302,6 @@
          * Returns the value of the property {@code key}, e.g., {@code prop("width")}.
          */
-        public Object prop(String key) {
-            return prop(key, null);
+        public static Object prop(final Environment env, String key) {
+            return prop(env, key, null);
         }
 
@@ -294,5 +309,5 @@
          * Returns the value of the property {@code key} from layer {@code layer}.
          */
-        public Object prop(String key, String layer) {
+        public static Object prop(final Environment env, String key, String layer) {
             return env.getCascade(layer).get(key);
         }
@@ -301,6 +316,6 @@
          * Determines whether property {@code key} is set.
          */
-        public Boolean is_prop_set(String key) {
-            return is_prop_set(key, null);
+        public static Boolean is_prop_set(final Environment env, String key) {
+            return is_prop_set(env, key, null);
         }
 
@@ -308,5 +323,5 @@
          * Determines whether property {@code key} is set on layer {@code layer}.
          */
-        public Boolean is_prop_set(String key, String layer) {
+        public static Boolean is_prop_set(final Environment env, String key, String layer) {
             return env.getCascade(layer).containsKey(key);
         }
@@ -315,5 +330,5 @@
          * Gets the value of the key {@code key} from the object in question.
          */
-        public String tag(String key) {
+        public static String tag(final Environment env, String key) {
             return env.osm == null ? null : env.osm.get(key);
         }
@@ -322,5 +337,5 @@
          * Gets the first non-null value of the key {@code key} from the object's parent(s).
          */
-        public String parent_tag(String key) {
+        public static String parent_tag(final Environment env, String key) {
             if (env.parent == null) {
                 if (env.osm != null) {
@@ -338,5 +353,5 @@
         }
 
-        public String child_tag(String key) {
+        public static String child_tag(final Environment env, String key) {
             return env.child == null ? null : env.child.get(key);
         }
@@ -345,5 +360,5 @@
          * Determines whether the object has a tag with the given key.
          */
-        public boolean has_tag_key(String key) {
+        public static boolean has_tag_key(final Environment env, String key) {
             return env.osm.hasKey(key);
         }
@@ -352,5 +367,5 @@
          * Returns the index of node in parent way or member in parent relation.
          */
-        public Float index() {
+        public static Float index(final Environment env) {
             if (env.index == null) {
                 return null;
@@ -359,5 +374,5 @@
         }
 
-        public String role() {
+        public static String role(final Environment env) {
             return env.getRole();
         }
@@ -403,5 +418,5 @@
          * Determines whether the JOSM search with {@code searchStr} applies to the object.
          */
-        public Boolean JOSM_search(String searchStr) {
+        public static Boolean JOSM_search(final Environment env, String searchStr) {
             Match m;
             try {
@@ -498,5 +513,5 @@
          * @see OsmPrimitive#getUniqueId()
          */
-        public long osm_id() {
+        public static long osm_id(final Environment env) {
             return env.osm.getUniqueId();
         }
@@ -607,5 +622,9 @@
         for (Method m : parameterFunctions) {
             if (m.getName().equals(name) && args.size() == m.getParameterTypes().length)
-                return new ParameterFunction(m, args);
+                return new ParameterFunction(m, args, false);
+        }
+        for (Method m : parameterFunctionsEnv) {
+            if (m.getName().equals(name) && args.size() == m.getParameterTypes().length-1)
+                return new ParameterFunction(m, args, true);
         }
         return NullExpression.INSTANCE;
@@ -717,5 +736,5 @@
         }
     }
-
+    
     /**
      * Function that takes a certain number of argument with specific type.
@@ -727,26 +746,42 @@
 
         private final Method m;
+        private final boolean nullable;
         private final List<Expression> args;
         private final Class<?>[] expectedParameterTypes;
-
-        public ParameterFunction(Method m, List<Expression> args) {
+        private final boolean needsEnvironment;
+
+        public ParameterFunction(Method m, List<Expression> args, boolean needsEnvironment) {
             this.m = m;
+            this.nullable = m.getAnnotation(NullableArguments.class) != null;
             this.args = args;
-            expectedParameterTypes = m.getParameterTypes();
+            this.expectedParameterTypes = m.getParameterTypes();
+            this.needsEnvironment = needsEnvironment;
         }
 
         @Override
         public Object evaluate(Environment env) {
-            FUNCTIONS_INSTANCE.env = env;
-            Object[] convertedArgs = new Object[expectedParameterTypes.length];
-            for (int i = 0; i < args.size(); ++i) {
-                convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
-                if (convertedArgs[i] == null && m.getAnnotation(NullableArguments.class) == null) {
-                    return null;
+            Object[] convertedArgs;
+            
+            if (needsEnvironment) {
+                convertedArgs = new Object[args.size()+1];
+                convertedArgs[0] = env;
+                for (int i = 1; i < convertedArgs.length; ++i) {
+                    convertedArgs[i] = Cascade.convertTo(args.get(i-1).evaluate(env), expectedParameterTypes[i]);
+                    if (convertedArgs[i] == null && !nullable) {
+                        return null;
+                    }
+                }
+            } else {
+                convertedArgs = new Object[args.size()];
+                for (int i = 0; i < convertedArgs.length; ++i) {
+                    convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
+                    if (convertedArgs[i] == null && !nullable) {
+                        return null;
+                    }
                 }
             }
             Object result = null;
             try {
-                result = m.invoke(FUNCTIONS_INSTANCE, convertedArgs);
+                result = m.invoke(null, convertedArgs);
             } catch (IllegalAccessException | IllegalArgumentException ex) {
                 throw new RuntimeException(ex);
@@ -783,22 +818,24 @@
 
         private final Method m;
+        private final boolean nullable;
         private final List<Expression> args;
+        private final Class<?>[] expectedParameterTypes;
         private final Class<?> arrayComponentType;
-        private final Object[] convertedArgs;
 
         public ArrayFunction(Method m, List<Expression> args) {
             this.m = m;
+            this.nullable = m.getAnnotation(NullableArguments.class) != null;
             this.args = args;
-            Class<?>[] expectedParameterTypes = m.getParameterTypes();
-            convertedArgs = new Object[expectedParameterTypes.length];
-            arrayComponentType = expectedParameterTypes[0].getComponentType();
+            this.expectedParameterTypes = m.getParameterTypes();
+            this.arrayComponentType = expectedParameterTypes[0].getComponentType();
         }
 
         @Override
         public Object evaluate(Environment env) {
+            Object[] convertedArgs = new Object[expectedParameterTypes.length];
             Object arrayArg = Array.newInstance(arrayComponentType, args.size());
             for (int i = 0; i < args.size(); ++i) {
                 Object o = Cascade.convertTo(args.get(i).evaluate(env), arrayComponentType);
-                if (o == null && m.getAnnotation(NullableArguments.class) == null) {
+                if (o == null && !nullable) {
                     return null;
                 }
