Index: /trunk/.classpath
===================================================================
--- /trunk/.classpath	(revision 4073)
+++ /trunk/.classpath	(revision 4074)
@@ -4,5 +4,5 @@
 	<classpathentry kind="src" path="test/unit"/>
 	<classpathentry kind="src" path="test/functional"/>
-	<classpathentry excluding="build/|data_nodist/|dist/|doc/|lib/|macosx/|src/|test/|test/build/|test/functional/|test/performance/|test/unit/|tools/|utils/" kind="src" path=""/>
+	<classpathentry excluding="build/|data_nodist/|dist/|doc/|lib/|macosx/|nb/|src/|test/|test/build/|test/functional/|test/performance/|test/unit/|tools/|utils/" kind="src" path=""/>
 	<classpathentry kind="src" path="test/performance"/>
 	<classpathentry kind="lib" path="lib/metadata-extractor-2.3.1-nosun.jar"/>
Index: /trunk/build.xml
===================================================================
--- /trunk/build.xml	(revision 4073)
+++ /trunk/build.xml	(revision 4074)
@@ -316,5 +316,3 @@
 
 	</target>
-
-
 </project>
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 4074)
@@ -17,6 +17,6 @@
 import java.util.Locale;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
-import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -1302,6 +1302,29 @@
             }
         }
-
         return result;
+    }
+
+    /**
+     * <p>Visits {@code visitor} for all referrers.</p>
+     * 
+     * @param visitor the visitor. Ignored, if null.
+     */
+    public void visitReferrers(Visitor visitor){
+        if (visitor == null) return;
+        if (this.referrers == null)
+            return;
+        else if (this.referrers instanceof OsmPrimitive) {
+            OsmPrimitive ref = (OsmPrimitive) this.referrers;
+            if (ref.dataSet == dataSet) {
+                ref.visit(visitor);
+            }
+        } else if (this.referrers instanceof OsmPrimitive[]) {
+            OsmPrimitive[] refs = (OsmPrimitive[]) this.referrers;
+            for (OsmPrimitive ref: refs) {
+                if (ref.dataSet == dataSet) {
+                    ref.visit(visitor);
+                }
+            }
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java	(revision 4074)
@@ -6,5 +6,4 @@
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
@@ -24,5 +23,4 @@
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
-import org.openstreetmap.josm.tools.Pair;
 
 public class MapPaintVisitor implements PaintVisitor {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 4074)
@@ -84,7 +84,5 @@
     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)
         {
@@ -235,6 +233,7 @@
 
         for (Entry<String, Cascade> e : mc.getLayers()) {
-            if ("*".equals(e.getKey()))
+            if ("*".equals(e.getKey())) {
                 continue;
+            }
             env.layer = e.getKey();
             Cascade c = e.getValue();
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java	(revision 4074)
@@ -114,4 +114,6 @@
      * @param c the style properties
      * @param defaultTextColor the default text color. Must not be null.
+     * @param defaultAnnotate true, if a text label shall be rendered by default, even if the style sheet
+     *   doesn't include respective style declarations
      * @return the text element or null, if the style properties don't include
      * properties for text rendering
@@ -212,10 +214,10 @@
         final TextElement other = (TextElement) obj;
         return  equal(labelCompositionStrategy, other.labelCompositionStrategy) &&
-                equal(font, other.font) &&
-                xOffset == other.xOffset &&
-                yOffset == other.yOffset &&
-                equal(color, other.color) &&
-                equal(haloRadius, other.haloRadius) &&
-                equal(haloColor, other.haloColor);
+        equal(font, other.font) &&
+        xOffset == other.xOffset &&
+        yOffset == other.yOffset &&
+        equal(color, other.color) &&
+        equal(haloRadius, other.haloRadius) &&
+        equal(haloColor, other.haloColor);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSRule.java	(revision 4074)
@@ -4,4 +4,5 @@
 import java.util.List;
 
+import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -16,4 +17,15 @@
     }
 
+    /**
+     * <p>Executes the instructions against the environment {@code env}</p>
+     * 
+     * @param env the environment
+     */
+    public void execute(Environment env) {
+        for (Instruction i : declaration) {
+            i.execute(env);
+        }
+    }
+
     @Override
     public String toString() {
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 4074)
@@ -134,12 +134,9 @@
                 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;
+                    if (gs.getBase().equals(type)) {
+                        if (!gs.matchesConditions(env)) {
+                            continue NEXT_RULE;
                         }
-                        for (Instruction i : r.declaration) {
-                            i.execute(env);
-                        }
+                        r.execute(env);
                     }
                 }
@@ -179,13 +176,9 @@
                                 continue;
                             }
-                            for (Instruction i : r.declaration) {
-                                i.execute(env);
-                            }
+                            r.execute(env);
                         }
                     }
                     env.layer = sub;
-                    for (Instruction i : r.declaration) {
-                        i.execute(env);
-                    }
+                    r.execute(env);
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 4073)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 4074)
@@ -10,4 +10,5 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.gui.mappaint.Range;
@@ -67,4 +68,77 @@
         }
 
+        /**
+         * <p>Finds the first referrer matching {@link #left}</p>
+         * 
+         * <p>The visitor works on an environment and it saves the matching
+         * referrer in {@code e.parent} and its relative position in the
+         * list referrers "child list" in {@code e.index}.</p>
+         * 
+         * <p>If after execution {@code e.parent} is null, no matching
+         * referrer was found.</p>
+         *
+         */
+        private  class MatchingReferrerFinder extends AbstractVisitor{
+            private Environment e;
+
+            /**
+             * Constructor
+             * @param e the environment against which we match
+             */
+            public MatchingReferrerFinder(Environment e){
+                this.e = e;
+            }
+
+            @Override
+            public void visit(Node n) {
+                // node should never be a referrer
+                throw new AssertionError();
+            }
+
+            @Override
+            public void visit(Way w) {
+                /*
+                 * If e.parent is already set to the first matching referrer. We skip any following
+                 * referrer injected into the visitor.
+                 */
+                if (e.parent != null) return;
+
+                if (!left.matches(e.withPrimitive(w)))
+                    return;
+                for (int i=0; i<w.getNodesCount(); i++) {
+                    Node n = w.getNode(i);
+                    if (n.equals(e.osm)) {
+                        if (link.matches(e.withParent(w).withIndex(i).withLinkContext())) {
+                            e.parent = w;
+                            e.index = i;
+                            return;
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void visit(Relation r) {
+                /*
+                 * If e.parent is already set to the first matching referrer. We skip any following
+                 * referrer injected into the visitor.
+                 */
+                if (e.parent != null) return;
+
+                if (!left.matches(e.withPrimitive(r)))
+                    return;
+                for (int i=0; i < r.getMembersCount(); i++) {
+                    RelationMember m = r.getMember(i);
+                    if (m.getMember().equals(e.osm)) {
+                        if (link.matches(e.withParent(r).withIndex(i).withLinkContext())) {
+                            e.parent = r;
+                            e.index = i;
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+
         @Override
         public boolean matches(Environment e) {
@@ -73,32 +147,8 @@
 
             if (!parentSelector) {
-                for (OsmPrimitive ref : e.osm.getReferrers()) {
-                    if (!left.matches(e.withPrimitive(ref)))
-                        continue;
-                    if (ref instanceof Way) {
-                        List<Node> wayNodes = ((Way) ref).getNodes();
-                        for (int i=0; i<wayNodes.size(); i++) {
-                            if (wayNodes.get(i).equals(e.osm)) {
-                                if (link.matches(e.withParent(ref).withIndex(i).withLinkContext())) {
-                                    e.parent = ref;
-                                    e.index = i;
-                                    return true;
-                                }
-                            }
-                        }
-                    } else if (ref instanceof Relation) {
-                        List<RelationMember> members = ((Relation) ref).getMembers();
-                        for (int i=0; i<members.size(); i++) {
-                            RelationMember m = members.get(i);
-                            if (m.getMember().equals(e.osm)) {
-                                if (link.matches(e.withParent(ref).withIndex(i).withLinkContext())) {
-                                    e.parent = ref;
-                                    e.index = i;
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
+                MatchingReferrerFinder collector = new MatchingReferrerFinder(e);
+                e.osm.visitReferrers(collector);
+                if (e.parent != null)
+                    return true;
             } else {
                 if (e.osm instanceof Way) {
@@ -181,7 +231,7 @@
 
     public static class GeneralSelector implements Selector {
-        public String base;
+        private String base;
         public Range range;
-        protected List<Condition> conds;
+        private List<Condition> conds;
         private String subpart;
 
@@ -198,5 +248,9 @@
                 range = new Range();
             }
-            this.conds = conds;
+            if (conds == null || conds.isEmpty()) {
+                this.conds = null;
+            } else {
+                this.conds = conds;
+            }
             this.subpart = subpart;
         }
@@ -211,8 +265,20 @@
         }
 
-        @Override
-        public boolean matches(Environment e) {
-            if (!baseApplies(e.osm))
-                return false;
+        public boolean matchesBase(Environment e){
+            if (base.equals("*"))
+                return true;
+            if (base.equals("area")) {
+                if (e.osm instanceof Way)
+                    return true;
+                if (e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon())
+                    return true;
+            }
+            if (base.equals(OsmPrimitiveType.from(e.osm).getAPIName()))
+                return true;
+            return false;
+        }
+
+        public boolean matchesConditions(Environment e){
+            if (conds == null) return true;
             for (Condition c : conds) {
                 if (!c.applies(e))
@@ -222,16 +288,12 @@
         }
 
-        private boolean baseApplies(OsmPrimitive osm) {
-            if (base.equals("*"))
-                return true;
-            if (base.equals("area")) {
-                if (osm instanceof Way)
-                    return true;
-                if (osm instanceof Relation && ((Relation) osm).isMultipolygon())
-                    return true;
-            }
-            if (base.equals(OsmPrimitiveType.from(osm).getAPIName()))
-                return true;
-            return false;
+        @Override
+        public boolean matches(Environment e) {
+            if (!matchesBase(e)) return false;
+            return matchesConditions(e);
+        }
+
+        public String getBase() {
+            return base;
         }
 
Index: /trunk/test/config/test-unit-env.properties
===================================================================
--- /trunk/test/config/test-unit-env.properties	(revision 4073)
+++ /trunk/test/config/test-unit-env.properties	(revision 4074)
@@ -9,4 +9,4 @@
 # This is the home directory for JOSM plugins: ${josm.home}\plugins\*.jar
 #
-josm.home=C:\\data\\projekte\\osm\\tag-editor-plugin
+josm.home=C:\\data\\projekte\\osm\\repositories\\josm-github-Gubaer\\test\\config\\unit-josm.home
 
Index: /trunk/test/functional/mapcss/performance/PerformanceTest.groovy
===================================================================
--- /trunk/test/functional/mapcss/performance/PerformanceTest.groovy	(revision 4074)
+++ /trunk/test/functional/mapcss/performance/PerformanceTest.groovy	(revision 4074)
@@ -0,0 +1,132 @@
+
+// License: GPL. For details, see LICENSE file.
+package mapcss.performance;
+
+import static org.junit.Assert.*
+
+import java.awt.Graphics2D
+import java.awt.image.BufferedImage
+
+import org.junit.*
+import org.openstreetmap.josm.Main
+import org.openstreetmap.josm.data.Bounds
+import org.openstreetmap.josm.data.osm.DataSet
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintVisitor
+import org.openstreetmap.josm.gui.MainApplication
+import org.openstreetmap.josm.gui.layer.OsmDataLayer
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource
+import org.openstreetmap.josm.gui.preferences.SourceEntry
+import org.openstreetmap.josm.io.OsmReader
+
+/**
+ * This performance tests measures the time for a full run of MapPaintVisitor.visitAll()
+ * against a test data set using a test style.
+ * 
+ */
+class PerformanceTest {
+
+    /* ------------------------ configuration section  ---------------------------- */
+    /**
+    * The path to the JOSM home environment
+    */
+   def static JOSM_HOME="/my/josm/home/dir"
+   
+   /**
+    * The path to the style file used for rendering.
+    */
+   def static STYLE_FILE="/my/test-style.mapcss"
+
+   /**
+    * The data file to be rendered
+    */
+   def static DATA_FILE = "/my/test-data.osm"
+    /* ------------------------ / configuration section  ---------------------------- */     
+    
+    def DataSet ds
+    
+    def static boolean checkTestEnvironment() {
+          File f = new File(JOSM_HOME)
+          if  (!f.isDirectory() || !f.exists()) {
+              fail("JOSM_HOME refers to '${JOSM_HOME}. This is either not a directory or doesn't exist.\nPlease update configuration settings in the unit test file.")              
+          }
+          
+          f = new File(STYLE_FILE);
+          if ( !f.isFile() || ! f.exists()) {
+              fail("STYLE_FILE refers to '${STYLE_FILE}. This is either not a file or doesn't exist.\nPlease update configuration settings in the unit test file.")
+          }
+          
+          f = new File(DATA_FILE);
+          if ( !f.isFile() || ! f.exists()) {
+              fail("DATA_FILE refers to '${DATA_FILE}. This is either not a file or doesn't exist.\nPlease update configuration settings in the unit test file.")
+          }
+    }
+    
+    @BeforeClass
+    public static void createJOSMFixture(){
+        checkTestEnvironment()
+        System.setProperty("josm.home", JOSM_HOME)
+        MainApplication.main(new String[0])
+    }
+    
+    def timed(Closure c){
+        long before = System.currentTimeMillis()
+        c()
+        long after = System.currentTimeMillis()
+        return after - before
+    }
+    
+    def  loadStyle() {
+        print "Loading style '$STYLE_FILE' ..."
+        MapCSSStyleSource source = new MapCSSStyleSource(
+            new SourceEntry(
+                new File(STYLE_FILE).toURI().toURL().toString(),
+                "test style",
+                "a test style",
+                true // active
+            )
+        )
+        source.loadStyleSource()
+        if (!source.errors.isEmpty()) {
+            fail("Failed to load style file ''${STYLE_FILE}''. Errors: ${source.errors}")
+        }
+        MapPaintStyles.getStyles().clear()
+        MapPaintStyles.getStyles().add(source)
+        println "DONE"
+    }
+    
+    def loadData() {
+        print "Loading data file '$DATA_FILE' ..."
+        new File(DATA_FILE).withInputStream {
+            InputStream is ->
+            ds = OsmReader.parseDataSet(is,null)
+        }
+        Main.main.addLayer(new OsmDataLayer(ds,"test layer",null /* no file */));
+        println "DONE"
+    }
+    
+    @Test
+    public void measureTimeForStylePreparation() {
+        loadStyle()
+        loadData()
+        
+        def mv = Main.map.mapView
+        
+        BufferedImage img = mv.createImage(mv.getWidth(), mv.getHeight())
+        Graphics2D g = img.createGraphics()
+        g.setClip(0,0, mv.getWidth(), mv.getHeight())
+        def visitor = new MapPaintVisitor()
+        visitor.setNavigatableComponent(Main.map.mapView)
+        visitor.setGraphics(g)
+
+        print "Rendering ..."
+        long time = timed {
+            visitor.visitAll(ds, false, new Bounds(-90,-180,90,180))
+        }
+        println "DONE"
+        println "data file : ${DATA_FILE}"
+        println "style file: ${STYLE_FILE}"
+        println ""
+        println "Rendering took $time ms."       
+    }
+}
Index: /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy	(revision 4073)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy	(revision 4074)
@@ -1,5 +1,4 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.mappaint
-
 import java.awt.Color
 
@@ -8,4 +7,5 @@
 import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy
 import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.TagKeyReference
 class MapCSSWithExtendedTextDirectivesTest {
     
@@ -21,5 +21,5 @@
         c.put("text", new Keyword("auto"))
         
-        TextElement te = TextElement.create(c, Color.WHITE)
+        TextElement te = TextElement.create(c, Color.WHITE, false /* no default annotate */)
         assert te.labelCompositionStrategy != null
         assert te.labelCompositionStrategy instanceof DeriveLabelFromNameTagsCompositionStrategy
@@ -29,18 +29,7 @@
     public void createTextElementComposingTextFromTag() {
         Cascade c = new Cascade()
-        c.put("text", "my_name")
+        c.put("text", new TagKeyReference("my_name"))
         
-        TextElement te = TextElement.create(c, Color.WHITE)
-        assert te.labelCompositionStrategy != null
-        assert te.labelCompositionStrategy instanceof TagLookupCompositionStrategy
-        assert te.labelCompositionStrategy.getDefaultLabelTag() == "my_name"
-    }
-    
-    @Test
-    public void createTextElementComposingTextFromTag_2() {
-        Cascade c = new Cascade()
-        c.put("text", new Keyword("my_name"))
-        
-        TextElement te = TextElement.create(c, Color.WHITE)
+        TextElement te = TextElement.create(c, Color.WHITE, false /* no default annotate */)
         assert te.labelCompositionStrategy != null
         assert te.labelCompositionStrategy instanceof TagLookupCompositionStrategy
@@ -52,5 +41,5 @@
         Cascade c = new Cascade()
         
-        TextElement te = TextElement.create(c, Color.WHITE)
+        TextElement te = TextElement.create(c, Color.WHITE, false /* no default annotate */)
         assert te.labelCompositionStrategy == null
     }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy	(revision 4073)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy	(revision 4074)
@@ -101,2 +101,3 @@
     }    
 }
+
Index: /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy	(revision 4073)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy	(revision 4074)
@@ -90,2 +90,3 @@
     
 }
+
Index: /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy	(revision 4073)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy	(revision 4074)
@@ -56,2 +56,3 @@
     }
 }
+
