Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 3987)
@@ -39,10 +39,9 @@
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.HorizontalTextAlignment;
+import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
-import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.VerticalTextAlignment;
 import org.openstreetmap.josm.gui.mappaint.TextElement;
 import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.LanguageInfo;
 import org.openstreetmap.josm.tools.Pair;
 
@@ -73,6 +72,4 @@
 
     private final boolean leftHandTraffic;
-
-    private final Collection<String> regionalNameOrder;
 
     private static final double PHI = Math.toRadians(20);
@@ -104,6 +101,4 @@
         this.segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
 
-        String[] names = {"name:" + LanguageInfo.getJOSMLocaleCode(), "name", "int_name", "ref", "operator", "brand", "addr:housenumber"};
-        this.regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names));
         this.circum = circum;
         this.leftHandTraffic = leftHandTraffic;
@@ -118,5 +113,5 @@
      * @param onewayReversed for oneway=-1 and similar
      */
-    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, 
+    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor,
             TextElement text, boolean showOrientation, boolean showHeadArrowOnly,
             boolean showOneway, boolean onewayReversed) {
@@ -253,5 +248,5 @@
         if (text == null)
             return;
-        String name = text.getString(way, this);
+        String name = text.getString(way);
         if (name == null || name.equals(""))
             return;
@@ -292,6 +287,6 @@
 
         if (p1[0] < p2[0] &&
-            p1[2] < Math.PI/2 &&
-            p1[2] > -Math.PI/2) {
+                p1[2] < Math.PI/2 &&
+                p1[2] > -Math.PI/2) {
             angleOffset = 0;
             offsetSign = 1;
@@ -347,6 +342,6 @@
             }
             return new double[] {poly.xpoints[i-1]+(totalLen - curLen)/segLen*dx,
-                                 poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
-                                 Math.atan2(dy, dx)};
+                    poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
+                    Math.atan2(dy, dx)};
         }
         return null;
@@ -495,7 +490,10 @@
             return;
 
-        String s = text.textKey == null ? getNodeName(n) : n.get(text.textKey);
-        if (s == null)
-            return;
+        /*
+         * abort if we can't compose the label to be rendered
+         */
+        if (text.labelCompositionStrategy == null) return;
+        String s = text.labelCompositionStrategy.compose(n);
+        if (s == null) return;
 
         Font defaultFont = g.getFont();
@@ -598,7 +596,10 @@
 
         if (text != null && isShowNames()) {
-            String name = text.textKey == null ? getAreaName(osm) : osm.get(text.textKey);
-            if (name == null)
-                return;
+            /*
+             * abort if we can't compose the label to be rendered
+             */
+            if (text.labelCompositionStrategy == null) return;
+            String name = text.labelCompositionStrategy.compose(osm);
+            if (name == null) return;
 
             Rectangle pb = polygon.getBounds();
@@ -931,32 +932,4 @@
     }
 
-    //TODO Not a good place for this method
-    public String getNodeName(Node n) {
-        String name = null;
-        if (n.hasKeys()) {
-            for (String rn : regionalNameOrder) {
-                name = n.get(rn);
-                if (name != null) {
-                    break;
-                }
-            }
-        }
-        return name;
-    }
-
-    //TODO Not a good place for this method
-    public String getAreaName(OsmPrimitive w) {
-        String name = null;
-        if (w.hasKeys()) {
-            for (String rn : regionalNameOrder) {
-                name = w.get(rn);
-                if (name != null) {
-                    break;
-                }
-            }
-        }
-        return name;
-    }
-
     public boolean isInactive() {
         return inactive;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3987)
@@ -5,4 +5,6 @@
 
 import java.awt.Font;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.openstreetmap.josm.Main;
@@ -17,5 +19,5 @@
     public float object_z_index;
     public boolean isModifier;  // false, if style can serve as main style for the
-                                // primitive; true, if it is a highlight or modifier
+    // primitive; true, if it is a highlight or modifier
 
     public ElemStyle(float z_index, float object_z_index, boolean isModifier) {
@@ -60,9 +62,84 @@
     }
 
+    /* ------------------------------------------------------------------------------- */
+    /* cached values                                                                   */
+    /* ------------------------------------------------------------------------------- */
+    /*
+     * Two preference values and the set of created fonts are cached in order to avoid
+     * expensive lookups and to avoid too many font objects
+     * (in analogy to flyweight pattern).
+     * 
+     * FIXME: cached preference values are not updated if the user changes them during
+     * a JOSM session. Should have a listener listening to preference changes.
+     */
+    static private String DEFAULT_FONT_NAME = null;
+    static private Float DEFAULT_FONT_SIZE = null;
+    static private void initDefaultFontParameters() {
+        if (DEFAULT_FONT_NAME != null) return; // already initialized - skip initialization
+        DEFAULT_FONT_NAME = Main.pref.get("mappaint.font", "Helvetica");
+        DEFAULT_FONT_SIZE = (float) Main.pref.getInteger("mappaint.fontsize", 8);
+    }
+
+    static private class FontDescriptor {
+        public String name;
+        public int style;
+        public int size;
+
+        public FontDescriptor(String name, int style, int size){
+            this.name = name;
+            this.style = style;
+            this.size = size;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result + size;
+            result = prime * result + style;
+            return result;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            FontDescriptor other = (FontDescriptor) obj;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            if (size != other.size)
+                return false;
+            if (style != other.style)
+                return false;
+            return true;
+        }
+    }
+
+    static private final Map<FontDescriptor, Font> FONT_MAP = new HashMap<FontDescriptor, Font>();
+    static private Font getCachedFont(FontDescriptor fd) {
+        Font f = FONT_MAP.get(fd);
+        if (f != null) return f;
+        f = new Font(fd.name, fd.style, fd.size);
+        FONT_MAP.put(fd, f);
+        return f;
+    }
+
+    static private Font getCachedFont(String name, int style, int size){
+        return getCachedFont(new FontDescriptor(name, style, size));
+    }
+
     protected static Font getFont(Cascade c) {
-        String name = c.get("font-family", Main.pref.get("mappaint.font", "Helvetica"), String.class);
-        float size = c.get("font-size", (float) Main.pref.getInteger("mappaint.fontsize", 8), Float.class);
+        initDefaultFontParameters(); // populated cached preferences, if necesary
+        String name = c.get("font-family", DEFAULT_FONT_NAME, String.class);
+        float size = c.get("font-size", DEFAULT_FONT_SIZE, Float.class);
         int weight = Font.PLAIN;
-        Keyword weightKW = c.get("font-wheight", null, Keyword.class);
+        Keyword weightKW = c.get("font-weight", null, Keyword.class);
         if (weightKW != null && equal(weightKW, "bold")) {
             weight = Font.BOLD;
@@ -73,5 +150,5 @@
             style = Font.ITALIC;
         }
-        return new Font(name, weight | style, Math.round(size));
+        return getCachedFont(name, style | weight, Math.round(size));
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java	(revision 3987)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/LabelCompositionStrategy.java	(revision 3987)
@@ -0,0 +1,245 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.tools.LanguageInfo;
+
+/**
+ * <p>Provides an abstract parent class and three concrete sub classes for various
+ * strategies on how to compose the text label which can be rendered close to a node
+ * or within an area in an OSM map.</p>
+ * 
+ * <p>The three strategies below support three rules for composing a label:
+ * <ul>
+ *   <li>{@link StaticLabelCompositionStrategy} - the label is given by a static text
+ *   specified in the MapCSS style file</li>
+ * 
+ *   <li>{@link TagLookupCompositionStrategy} - the label is given by the content of a
+ *   tag whose name specified in the MapCSS style file</li>
+ * 
+ *   <li>{@link DeriveLabelFromNameTagsCompositionStrategy} - the label is given by the value
+ *   of one
+ *   of the configured "name tags". The list of relevant name tags can be configured
+ *   in the JOSM preferences
+ *   content of a tag whose name specified in the MapCSS style file, see the preference
+ *   option <tt>mappaint.nameOrder</tt>.</li>
+ * </ul>
+ * </p>
+ *
+ */
+public abstract class LabelCompositionStrategy {
+
+    /**
+     * Replies the text value to be rendered as label for the primitive {@code primitive}.
+     *
+     * @param primitive the primitive
+     *
+     * @return the text value to be rendered or null, if primitive is null or
+     * if no suitable value could be composed
+     */
+    abstract public String compose(OsmPrimitive primitive);
+
+    static public class StaticLabelCompositionStrategy extends LabelCompositionStrategy {
+        private String defaultLabel;
+        public StaticLabelCompositionStrategy(String defaultLabel){
+            this.defaultLabel = defaultLabel;
+        }
+
+        @Override
+        public String compose(OsmPrimitive primitive) {
+            return defaultLabel;
+        }
+
+        public String getDefaultLabel() {
+            return defaultLabel;
+        }
+
+        @Override
+        public String toString() {
+            return "{"  + getClass().getSimpleName() + " defaultLabel=" + defaultLabel + "}";
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((defaultLabel == null) ? 0 : defaultLabel.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            StaticLabelCompositionStrategy other = (StaticLabelCompositionStrategy) obj;
+            if (defaultLabel == null) {
+                if (other.defaultLabel != null)
+                    return false;
+            } else if (!defaultLabel.equals(other.defaultLabel))
+                return false;
+            return true;
+        }
+    }
+
+    static public class TagLookupCompositionStrategy extends LabelCompositionStrategy {
+
+        private String defaultLabelTag;
+        public TagLookupCompositionStrategy(String defaultLabelTag){
+            if (defaultLabelTag != null) {
+                defaultLabelTag = defaultLabelTag.trim();
+                if (defaultLabelTag.isEmpty()) {
+                    defaultLabelTag = null;
+                }
+            }
+            this.defaultLabelTag = defaultLabelTag;
+        }
+
+        @Override
+        public String compose(OsmPrimitive primitive) {
+            if (defaultLabelTag == null) return null;
+            if (primitive == null) return null;
+            return primitive.get(defaultLabelTag);
+        }
+
+        public String getDefaultLabelTag() {
+            return defaultLabelTag;
+        }
+
+        @Override
+        public String toString() {
+            return "{" + getClass().getSimpleName() + " defaultLabelTag=" + defaultLabelTag + "}";
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((defaultLabelTag == null) ? 0 : defaultLabelTag.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            TagLookupCompositionStrategy other = (TagLookupCompositionStrategy) obj;
+            if (defaultLabelTag == null) {
+                if (other.defaultLabelTag != null)
+                    return false;
+            } else if (!defaultLabelTag.equals(other.defaultLabelTag))
+                return false;
+            return true;
+        }
+    }
+
+    static public class DeriveLabelFromNameTagsCompositionStrategy extends LabelCompositionStrategy {
+
+        /**
+         * The list of default name tags from which a label candidate is derived.
+         */
+        static public final String[] DEFAULT_NAME_TAGS = {
+            "name:" + LanguageInfo.getJOSMLocaleCode(),
+            "name",
+            "int_name",
+            "ref",
+            "operator",
+            "brand",
+            "addr:housenumber"
+        };
+
+        private  List<String> nameTags = new ArrayList<String>();
+
+        /**
+         * <p>Creates the strategy and initializes its name tags from the preferences.</p>
+         * 
+         * <p><strong>Note:</strong> If the list of name tags in the preferences changes, strategy instances
+         * are not notified. It's up to the client to listen to preference changes and
+         * invoke {@link #initNameTagsFromPreferences()} accordingly.</p>
+         * 
+         */
+        public DeriveLabelFromNameTagsCompositionStrategy() {
+            initNameTagsFromPreferences();
+        }
+
+        /**
+         * Sets the name tags to be looked up in order to build up the label
+         * 
+         * @param nameTags the name tags. null values are ignore.
+         */
+        public void setNameTags(List<String> nameTags){
+            if (nameTags == null) {
+                nameTags = Collections.emptyList();
+            }
+            this.nameTags = new ArrayList<String>();
+            for(String tag: nameTags) {
+                if (tag == null) {
+                    continue;
+                }
+                tag = tag.trim();
+                if (tag.isEmpty()) {
+                    continue;
+                }
+                this.nameTags.add(tag);
+            }
+        }
+
+        /**
+         * Replies an unmodifiable list of the name tags used to compose the label.
+         * 
+         * @return the list of name tags
+         */
+        public List<String> getNameTags() {
+            return Collections.unmodifiableList(nameTags);
+        }
+
+        /**
+         * Initializes the name tags to use from a list of default name tags (see
+         * {@link #DEFAULT_NAME_TAGS}) and from name tags configured in the preferences
+         * using the preference key <tt>mappaint.nameOrder</tt>.
+         */
+        public void initNameTagsFromPreferences() {
+            if (Main.pref == null){
+                this.nameTags = new ArrayList<String>(Arrays.asList(DEFAULT_NAME_TAGS));
+            } else {
+                this.nameTags = new ArrayList<String>(
+                        Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(DEFAULT_NAME_TAGS))
+                );
+            }
+        }
+
+        private String getPrimitiveName(OsmPrimitive n) {
+            String name = null;
+            if (!n.hasKeys()) return null;
+            for (String rn : nameTags) {
+                name = n.get(rn);
+                if (name != null) return name;
+            }
+            return null;
+        }
+
+        @Override
+        public String compose(OsmPrimitive primitive) {
+            if (primitive == null) return null;
+            return getPrimitiveName(primitive);
+        }
+
+        @Override
+        public String toString() {
+            return "{" + getClass().getSimpleName() +"}";
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java	(revision 3987)
@@ -7,4 +7,6 @@
 import java.util.Map.Entry;
 
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
 /**
  * Several layers / cascades, e.g. one for the main Line and one for each overlay.
@@ -13,5 +15,5 @@
  */
 public class MultiCascade {
-    
+
     private Map<String, Cascade> layers;
     public Range range;
@@ -28,6 +30,5 @@
      */
     public Cascade getOrCreateCascade(String layer) {
-        if (layer == null)
-            throw new IllegalArgumentException();
+        CheckParameterUtil.ensureParameterNotNull(layer);
         Cascade c = layers.get(layer);
         if (c == null) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 3987)
@@ -26,4 +26,5 @@
  */
 public class NodeElemStyle extends ElemStyle {
+    //static private final Logger logger = Logger.getLogger(NodeElemStyle.class.getName());
 
     public ImageIcon icon;
@@ -141,5 +142,18 @@
     }
 
+    /*
+     * Caches the default text color from the preferences.
+     *
+     * FIXME: the cache isn't updated if the user changes the preference during a JOSM
+     * session. There should be preference listener updating this cache.
+     */
+    static private Color DEFAULT_TEXT_COLOR = null;
+    static private void initDefaultParameters() {
+        if (DEFAULT_TEXT_COLOR != null) return;
+        DEFAULT_TEXT_COLOR = PaintColors.TEXT.get();
+    }
+
     private static NodeElemStyle create(Environment env, boolean allowOnlyText) {
+        initDefaultParameters();
         Cascade c = env.mc.getCascade(env.layer);
 
@@ -167,5 +181,10 @@
 
         NodeTextElement text = null;
-        TextElement te = TextElement.create(c, PaintColors.TEXT.get());
+        TextElement te = TextElement.create(c, DEFAULT_TEXT_COLOR);
+        // optimization: if we neither have a symbol, nor an icon, nor a text element
+        // we don't have to check for the remaining style properties and we don't
+        // have to allocate a node element style.
+        if (symbol == null && icon == null && te == null) return null;
+
         if (te != null) {
             HorizontalTextAlignment hAlign = HorizontalTextAlignment.RIGHT;
@@ -193,5 +212,5 @@
             text = new NodeTextElement(te, hAlign, vAlign);
         }
-        
+
         return new NodeElemStyle(c, icon, iconAlpha, symbol, text);
     }
@@ -225,5 +244,5 @@
         } else
             return null;
-        
+
         Float sizeOnDefault = c_def.get("symbol-size", null, Float.class);
         if (sizeOnDefault != null && sizeOnDefault <= 0) {
@@ -259,6 +278,7 @@
 
         Color fillColor = c.get("symbol-fill-color", null, Color.class);
-        if (stroke == null && fillColor == null)
+        if (stroke == null && fillColor == null) {
             fillColor = Color.BLUE;
+        }
 
         if (fillColor != null) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java	(revision 3987)
@@ -6,14 +6,25 @@
 import java.awt.Color;
 import java.awt.Font;
+
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
-
+import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy;
+import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Utils;
 
+/**
+ * Represents the rendering style for a textual label placed somewhere on the map.
+ *
+ */
 public class TextElement {
-    // textKey == null means automatic generation of text string, otherwise
-    // the corresponding tag value is used
-    public String textKey;
+    //static private final Logger logger = Logger.getLogger(TextElement.class.getName());
+
+    static private final LabelCompositionStrategy AUTO_LABEL_COMPOSITION_STRATEGY = new DeriveLabelFromNameTagsCompositionStrategy();
+
+    /** the strategy for building the actual label value for a given a {@link OsmPrimitive}.
+     * Check for null before accessing.
+     */
+    public LabelCompositionStrategy labelCompositionStrategy;
+    /** the font to be used when rendering*/
     public Font font;
     public int xOffset;
@@ -23,8 +34,20 @@
     public Color haloColor;
 
-    public TextElement(String textKey, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) {
+    /**
+     * Creates a new text element
+     * 
+     * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered.
+     * If null, no label is rendered.
+     * @param font the font to be used. Must not be null.
+     * @param xOffset
+     * @param yOffset
+     * @param color the color to be used. Must not be null
+     * @param haloRadius
+     * @param haloColor
+     */
+    public TextElement(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) {
         CheckParameterUtil.ensureParameterNotNull(font);
         CheckParameterUtil.ensureParameterNotNull(color);
-        this.textKey = textKey;
+        labelCompositionStrategy = strategy;
         this.font = font;
         this.xOffset = xOffset;
@@ -35,6 +58,11 @@
     }
 
+    /**
+     * Copy constructor
+     * 
+     * @param other the other element.
+     */
     public TextElement(TextElement other) {
-        this.textKey = other.textKey;
+        this.labelCompositionStrategy = other.labelCompositionStrategy;
         this.font = other.font;
         this.xOffset = other.xOffset;
@@ -45,15 +73,37 @@
     }
 
-    public static TextElement create(Cascade c, Color defTextColor) {
-
-        String textKey = null;
+    /**
+     * Derives a suitable label composition strategy from the style properties in
+     * {@code c}.
+     * 
+     * @param c the style properties
+     * @return the label composition strategy
+     */
+    protected static LabelCompositionStrategy buildLabelCompositionStrategy(Cascade c){
         Keyword textKW = c.get("text", null, Keyword.class, true);
         if (textKW == null) {
-            textKey = c.get("text", null, String.class);
-            if (textKey == null)
-                return null;
-        } else if (!textKW.val.equals("auto"))
-            return null;
+            String textKey = c.get("text", null, String.class);
+            if (textKey == null) return null;
+            return new TagLookupCompositionStrategy(textKey);
+        } else if (textKW.val.equals("auto"))
+            return AUTO_LABEL_COMPOSITION_STRATEGY;
+        else
+            return new TagLookupCompositionStrategy(textKW.val);
+    }
 
+    /**
+     * Builds a text element from style properties in {@code c} and the
+     * default text color {@code defaultTextColor}
+     * 
+     * @param c the style properties
+     * @param defaultTextColor the default text color. Must not be null.
+     * @return the text element or null, if the style properties don't include
+     * properties for text rendering
+     * @throws IllegalArgumentException thrown if {@code defaultTextColor} is null
+     */
+    public static TextElement create(Cascade c, Color defaultTextColor)  throws IllegalArgumentException{
+        CheckParameterUtil.ensureParameterNotNull(defaultTextColor);
+
+        LabelCompositionStrategy strategy = buildLabelCompositionStrategy(c);
         Font font = ElemStyle.getFont(c);
 
@@ -71,6 +121,6 @@
         xOffset = c.get("text-offset-x", xOffset, Float.class);
         yOffset = c.get("text-offset-y", yOffset, Float.class);
-        
-        Color color = c.get("text-color", defTextColor, Color.class);
+
+        Color color = c.get("text-color", defaultTextColor, Color.class);
         float alpha = c.get("text-opacity", 1f, Float.class);
         color = new Color(color.getRed(), color.getGreen(),
@@ -89,19 +139,27 @@
         }
 
-        return new TextElement(textKey, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor);
+        return new TextElement(strategy, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor);
+    }
+
+    /**
+     * Replies the label to be rendered for the primitive {@code osm}.
+     * 
+     * @param osm the the OSM object
+     * @return the label, or null, if {@code osm} is null or if no label can be
+     * derived for {@code osm}
+     */
+    public String getString(OsmPrimitive osm) {
+        if (labelCompositionStrategy == null) return null;
+        return labelCompositionStrategy.compose(osm);
     }
 
     @Override
-    public boolean equals(Object obj) {
-        if (obj == null || getClass() != obj.getClass())
-            return false;
-        final TextElement other = (TextElement) obj;
-        return  equal(textKey, other.textKey) &&
-                equal(font, other.font) &&
-                xOffset == other.xOffset &&
-                yOffset == other.yOffset &&
-                equal(color, other.color) &&
-                equal(haloRadius, other.haloRadius) &&
-                equal(haloColor, other.haloColor);
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("{TextElement ");
+        sb.append("strategy=");
+        sb.append(labelCompositionStrategy == null ? "null" : labelCompositionStrategy.toString());
+        sb.append("}");
+        return sb.toString();
     }
 
@@ -109,5 +167,5 @@
     public int hashCode() {
         int hash = 3;
-        hash = 79 * hash + (textKey != null ? textKey.hashCode() : 0);
+        hash = 79 * hash + (labelCompositionStrategy != null ? labelCompositionStrategy.hashCode() : 0);
         hash = 79 * hash + font.hashCode();
         hash = 79 * hash + xOffset;
@@ -119,11 +177,16 @@
     }
 
-    public String getString(OsmPrimitive osm, MapPainter painter) {
-        if (textKey == null)
-            return painter.getAreaName(osm);
-        else
-            return osm.get(textKey);
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        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);
     }
-
-
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 3986)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 3987)
@@ -28,5 +28,6 @@
 
 public class MapCSSStyleSource extends StyleSource {
-    
+    //static private final Logger logger = Logger.getLogger(MapCSSStyleSource.class.getName());
+
     final public List<MapCSSRule> rules;
     private Color backgroundColorOverride;
@@ -66,4 +67,5 @@
     }
 
+    @Override
     public InputStream getSourceInputStream() throws IOException {
         MirroredInputStream in = new MirroredInputStream(url);
@@ -128,4 +130,5 @@
     }
 
+    @Override
     public Color getBackgroundColorOverride() {
         return backgroundColorOverride;
@@ -160,5 +163,5 @@
                             }
                         }
-                    } 
+                    }
                     env.layer = sub;
                     for (Instruction i : r.declaration) {
