Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 15195)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 15196)
@@ -29,4 +29,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.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.search.SearchCompiler;
@@ -571,4 +573,23 @@
 
         /**
+         * Returns true if role is in relation. Returns false if not a relation or it does not have the role.
+         * @param env the environment
+         * @param roles The roles to count in the relation
+         * @return The number of relation members with the specified role
+         * @since 15196
+         */
+        public static int count_roles(final Environment env, String... roles) { // NO_UCD (unused code)
+            int rValue = 0;
+            if (env.osm instanceof Relation) {
+                List<String> roleList = Arrays.asList(roles);
+                Relation rel = (Relation) env.osm;
+                for (RelationMember member : rel.getMembers()) {
+                    if (roleList.contains(member.getRole())) rValue++;
+                }
+            }
+            return rValue;
+        }
+
+        /**
          * Returns the area of a closed way or multipolygon in square meters or {@code null}.
          * @param env the environment
Index: /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java	(revision 15195)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java	(revision 15196)
@@ -14,8 +14,11 @@
 import org.junit.Rule;
 import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmUtils;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.mappaint.Environment;
@@ -405,4 +408,45 @@
 
     @Test
+    public void testCountRoles() throws Exception {
+        DataSet ds = new DataSet();
+        Way way1 = TestUtils.newWay("highway=residential name=1",
+                new Node(new LatLon(0, 0)), new Node((new LatLon(0.001, 0.001))));
+        for (Node node : way1.getNodes()) {
+            ds.addPrimitive(node);
+        }
+        ds.addPrimitive(way1);
+
+        Relation rel1 = TestUtils.newRelation("type=destination_sign", new RelationMember("", way1));
+        ds.addPrimitive(rel1);
+
+        /* Check with empty role and one object */
+        Environment e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertEquals(1, ExpressionFactory.Functions.count_roles(e, ""));
+
+        /* Check with non-empty role and one object */
+        e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertEquals(0, ExpressionFactory.Functions.count_roles(e, "from"));
+
+        /* Check with empty role and two objects */
+        Way way2 = TestUtils.newWay("highway=residential name=2", way1.firstNode(), way1.lastNode());
+        ds.addPrimitive(way2);
+        rel1.addMember(new RelationMember("", way2));
+        e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertEquals(2, ExpressionFactory.Functions.count_roles(e, ""));
+
+        /* Check with non-empty role and two objects */
+        rel1.setMember(0, new RelationMember("from", way1));
+        e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertEquals(1, ExpressionFactory.Functions.count_roles(e, "from"));
+
+        /* Check with multiple roles */
+        assertEquals(1, ExpressionFactory.Functions.count_roles(e, "from", "to"));
+
+        /* Check with non-relation */
+        e = new Environment(way1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertEquals(0, ExpressionFactory.Functions.count_roles(e, "from", "to"));
+    }
+
+    @Test
     public void testSiblingSelectorInterpolation() throws Exception {
         ChildOrParentSelector s1 = (Selector.ChildOrParentSelector) getParser(
