Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 3824)
@@ -26,5 +26,5 @@
 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
-import org.openstreetmap.josm.gui.mappaint.ElemStyle;
+import org.openstreetmap.josm.gui.mappaint.StyleCache;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Predicate;
@@ -299,5 +299,5 @@
      * MAPPAINT
      *--------*/
-    public ElemStyle mappaintStyle = null;
+    public StyleCache mappaintStyle = null;
     public int mappaintDrawnCode = 0;
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java	(revision 3824)
@@ -1,6 +1,4 @@
-/* License: GPL. Copyright 2007 by Immanuel Scholz and others */
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.data.osm.visitor.paint;
-
-/* To enable debugging or profiling remove the double / signs */
 
 import java.awt.Graphics2D;
@@ -38,5 +36,5 @@
 import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
-import org.openstreetmap.josm.gui.mappaint.SimpleNodeElemStyle;
+import org.openstreetmap.josm.gui.mappaint.StyleCache;
 
 public class MapPaintVisitor implements PaintVisitor {
@@ -70,5 +68,5 @@
     }
 
-    public ElemStyle getPrimitiveStyle(OsmPrimitive osm, boolean nodefault) {
+    public StyleCache getPrimitiveStyle(OsmPrimitive osm, boolean nodefault) {
         if(osm.mappaintStyle == null)
         {
@@ -79,21 +77,27 @@
                 }
             }
-            if (osm.mappaintStyle == null) {
+            if (osm.mappaintStyle.equals(StyleCache.EMPTY_STYLECACHE)) {
                 if(osm instanceof Node)
-                    osm.mappaintStyle = SimpleNodeElemStyle.INSTANCE;
+                    osm.mappaintStyle = StyleCache.SIMPLE_NODE_STYLECACHE;// SimpleNodeElemStyle.INSTANCE;
                 else if (osm instanceof Way)
-                    osm.mappaintStyle = LineElemStyle.UNTAGGED_WAY;
-            }
-        }
-        if(nodefault && osm.mappaintStyle == LineElemStyle.UNTAGGED_WAY)
-            return null;
+                    osm.mappaintStyle = StyleCache.UNTAGGED_WAY_STYLECACHE;//LineElemStyle.UNTAGGED_WAY;
+            }
+        }
+        if (nodefault && osm.mappaintStyle.equals(StyleCache.UNTAGGED_WAY_STYLECACHE))
+            return StyleCache.EMPTY_STYLECACHE;
         return osm.mappaintStyle;
     }
 
     public IconElemStyle getPrimitiveNodeStyle(OsmPrimitive osm) {
-        if(osm.mappaintStyle == null && styles != null)
-            osm.mappaintStyle = styles.getIcon(osm);
-
-        return (IconElemStyle)osm.mappaintStyle;
+        if(osm.mappaintStyle == null && styles != null) {
+            IconElemStyle icon = styles.getIcon(osm);
+            osm.mappaintStyle = StyleCache.create(icon);
+            return icon;
+        }
+        for (ElemStyle s : osm.mappaintStyle.getStyles()) {
+            if (s instanceof IconElemStyle)
+                return (IconElemStyle) s;
+        }
+        return null;
     }
 
@@ -115,9 +119,11 @@
             return;
 
-        ElemStyle nodeStyle = getPrimitiveStyle(n, false);
-
-        if (isZoomOk(nodeStyle)) {
-            nodeStyle.paintPrimitive(n, paintSettings, painter, data.isSelected(n),
-            false);
+        StyleCache sc = getPrimitiveStyle(n, false);
+
+        for (ElemStyle s : sc.getStyles()) {
+            if (isZoomOk(s)) {
+                s.paintPrimitive(n, paintSettings, painter, data.isSelected(n), false);
+            }
+
         }
     }
@@ -158,19 +164,11 @@
             return;
 
-        ElemStyle wayStyle = getPrimitiveStyle(w, false);
-
-        if(!isZoomOk(wayStyle))
-            return;
-
-        if(wayStyle instanceof LineElemStyle) {
-            wayStyle.paintPrimitive(w, paintSettings, painter, data.isSelected(w), false);
-        } else if (wayStyle instanceof AreaElemStyle) {
-            AreaElemStyle areaStyle = (AreaElemStyle) wayStyle;
-            /* way with area style */
-            if (fillAreas > dist)
-            {
-                areaStyle.paintPrimitive(w, paintSettings, painter, data.isSelected(w), false);
-            }
-            areaStyle.getLineStyle().paintPrimitive(w, paintSettings, painter, data.isSelected(w), false);
+        StyleCache sc = getPrimitiveStyle(w, false);
+        for (ElemStyle s : sc.getStyles()) {
+            if(!isZoomOk(s))
+                return;
+            if (fillAreas > dist || !(s instanceof AreaElemStyle)) {
+                s.paintPrimitive(w, paintSettings, painter, data.isSelected(w), false);
+            }
         }
     }
@@ -369,13 +367,27 @@
         multipolygon.load(r);
 
-        ElemStyle wayStyle = getPrimitiveStyle(r, false);
+        AreaElemStyle areaStyle = null;
+        LineElemStyle lineStyle = null;
+        for (ElemStyle s : getPrimitiveStyle(r, false).getStyles()) {
+            if (s instanceof AreaElemStyle) {
+                areaStyle = (AreaElemStyle) s;
+            } else if (s instanceof LineElemStyle) {
+                lineStyle = (LineElemStyle) s;
+            }
+        }
 
         boolean disabled = r.isDisabled();
         // If area style was not found for relation then use style of ways
-        if(styles != null && !(wayStyle instanceof AreaElemStyle)) {
+        if(styles != null && areaStyle == null) {
             for (Way w : multipolygon.getOuterWays()) {
-                wayStyle = styles.getArea(w);
+                for (ElemStyle s : styles.getArea(w).getStyles()) {
+                    if (s instanceof AreaElemStyle) {
+                        areaStyle = (AreaElemStyle) s;
+                    } else if (s instanceof LineElemStyle) {
+                        lineStyle = (LineElemStyle) s;
+                    }
+                }
                 disabled = disabled || w.isDisabled();
-                if(wayStyle != null) {
+                if(areaStyle != null) {
                     break;
                 }
@@ -383,6 +395,6 @@
         }
 
-        if (wayStyle instanceof AreaElemStyle) {
-            boolean zoomok = isZoomOk(wayStyle);
+        if (areaStyle != null) {
+            boolean zoomok = isZoomOk(areaStyle);
             boolean visible = false;
 
@@ -390,5 +402,4 @@
 
             if(zoomok && !disabled && !multipolygon.getOuterWays().isEmpty()) {
-                AreaElemStyle areaStyle = (AreaElemStyle)wayStyle;
                 for (PolyData pd : multipolygon.getCombinedPolygons()) {
                     Polygon p = pd.get();
@@ -399,5 +410,5 @@
                     boolean selected = pd.selected || data.isSelected(r);
                     painter.drawArea(p, selected ? paintSettings.getRelationSelectedColor()
-                    : areaStyle.color, painter.getAreaName(r));
+                                : areaStyle.color, painter.getAreaName(r));
                     visible = true;
                 }
@@ -407,21 +418,27 @@
                 return drawn;
             for (Way wInner : multipolygon.getInnerWays()) {
-                ElemStyle innerStyle = getPrimitiveStyle(wInner, true);
-                if(innerStyle == null) {
+                StyleCache inner = getPrimitiveStyle(wInner, true);
+                AreaElemStyle innerArea = null;
+                for (ElemStyle s : inner.getStyles()) {
+                    if (s instanceof AreaElemStyle) {
+                        innerArea = (AreaElemStyle) s;
+                        break;
+                    }
+                }
+
+                if(inner.getStyles().isEmpty()) {
                     if (data.isSelected(wInner) || disabled)
                         continue;
                     if(zoomok && (wInner.mappaintDrawnCode != paintid || multipolygon.getOuterWays().isEmpty())) {
-                        ((AreaElemStyle)wayStyle).getLineStyle().paintPrimitive(wInner, paintSettings,
-                        painter, (data.isSelected(wInner) || data.isSelected(r)), false);
+                        lineStyle.paintPrimitive(wInner, paintSettings,
+                                painter, (data.isSelected(wInner) || data.isSelected(r)), false);
                     }
                     wInner.mappaintDrawnCode = paintid;
                 }
-                else
-                {
-                    if(wayStyle.equals(innerStyle))
-                    {
+                else {
+                    if(areaStyle.equals(innerArea)) {
                         wInner.mappaintDrawnAreaCode = paintid;
-                        if(!data.isSelected(wInner))
-                        {
+                        
+                        if(!data.isSelected(wInner)) {
                             wInner.mappaintDrawnCode = paintid;
                             drawWay(wInner, 0);
@@ -431,15 +448,23 @@
             }
             for (Way wOuter : multipolygon.getOuterWays()) {
-                ElemStyle outerStyle = getPrimitiveStyle(wOuter, true);
-                if(outerStyle == null) {
+                StyleCache outer = getPrimitiveStyle(wOuter, true);
+                boolean hasOuterArea = false;
+                for (ElemStyle s : outer.getStyles()) {
+                    if (s instanceof AreaElemStyle) {
+                        hasOuterArea = true;
+                        break;
+                    }
+                }
+
+                if (outer.getStyles().isEmpty()) {
                     // Selected ways are drawn at the very end
                     if (data.isSelected(wOuter))
                         continue;
                     if(zoomok) {
-                        ((AreaElemStyle)wayStyle).getLineStyle().paintPrimitive(wOuter, paintSettings, painter,
-                        (data.isSelected(wOuter) || data.isSelected(r)), r.isSelected());
+                        lineStyle.paintPrimitive(wOuter, paintSettings, painter,
+                            (data.isSelected(wOuter) || data.isSelected(r)), r.isSelected());
                     }
                     wOuter.mappaintDrawnCode = paintid;
-                } else if(outerStyle instanceof AreaElemStyle) {
+                } else if (hasOuterArea) {
                     wOuter.mappaintDrawnAreaCode = paintid;
                     if(!data.isSelected(wOuter)) {
@@ -512,4 +537,5 @@
     /* Shows areas before non-areas */
     public void visitAll(final DataSet data, boolean virtual, Bounds bounds) {
+        //long start = System.currentTimeMillis();
         BBox bbox = new BBox(bounds);
         this.data = data;
@@ -616,17 +642,19 @@
                             OsmPrimitive osm = m.getMember();
                             if(osm.isDrawable()) {
-                                ElemStyle style = getPrimitiveStyle(m.getMember(), false);
+                                StyleCache sc = getPrimitiveStyle(m.getMember(), false);
                                 if(osm instanceof Way)
                                 {
-                                    if(style instanceof AreaElemStyle) {
-                                        ((AreaElemStyle)style).getLineStyle().paintPrimitive(osm, paintSettings, painter, true, true);
-                                    } else {
-                                        style.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
+                                    for (ElemStyle s : sc.getStyles()) {
+                                        if (!(s instanceof AreaElemStyle)) {
+                                            s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
+                                        }
                                     }
                                 }
                                 else if(osm instanceof Node)
                                 {
-                                    if(isZoomOk(style)) {
-                                        style.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
+                                    for (ElemStyle s : sc.getStyles()) {
+                                        if (isZoomOk(s)) {
+                                            s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
+                                        }
                                     }
                                 }
@@ -648,4 +676,5 @@
 
         painter.drawVirtualNodes(data.searchWays(bbox));
+        //System.err.println("PAINTING TOOK "+(System.currentTimeMillis() - start));
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 3824)
@@ -26,4 +26,6 @@
 import org.openstreetmap.josm.gui.mappaint.ElemStyles;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
+import org.openstreetmap.josm.gui.mappaint.StyleCache;
+import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype;
 
 public class MultipolygonTest extends Test {
@@ -53,5 +55,5 @@
     public void initialize() throws Exception {
         styles = MapPaintStyles.getStyles();
-    }
+}
 
     private List<List<Node>> joinWays(Collection<Way> ways) {
@@ -113,6 +115,6 @@
     public void visit(Way w) {
         if (styles != null && !w.isClosed()) {
-            ElemStyle e = styles.getArea(w);
-            if (e instanceof AreaElemStyle && !((AreaElemStyle)e).closed) {
+            AreaPrototype e = styles.getAreaProto(w);
+            if (e != null && ! e.closed) {
                 errors.add( new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED,  w));
             }
@@ -140,15 +142,27 @@
             List<List<Node>> innerWays = joinWays(polygon.getInnerWays()); // Side effect - sets nonClosedWays
             List<List<Node>> outerWays = joinWays(polygon.getOuterWays());
-
             if (styles != null) {
-                ElemStyle wayStyle = styles.get(r);
-
+                StyleCache sc = styles.get(r);
+
+                AreaElemStyle area = null;
+                for (ElemStyle s : sc.getStyles()) {
+                    if (s instanceof AreaElemStyle) {
+                        area = (AreaElemStyle) s;
+                        break;
+                    }
+                }
                 // If area style was not found for relation then use style of ways
-                if (!(wayStyle instanceof AreaElemStyle)) {
+                if (area == null) {
                     errors.add( new TestError(this, Severity.OTHER, tr("No style in multipolygon relation"),
                     NO_STYLE_POLYGON, r));
                     for (Way w : polygon.getOuterWays()) {
-                        wayStyle = styles.getArea(w);
-                        if(wayStyle != null) {
+
+                        for (ElemStyle s : styles.getArea(w).getStyles()) {
+                            if (s instanceof AreaElemStyle) {
+                                area = (AreaElemStyle) s;
+                                break;
+                            }
+                        }
+                        if (area != null) {
                             break;
                         }
@@ -156,8 +170,15 @@
                 }
 
-                if (wayStyle instanceof AreaElemStyle) {
+                if (area != null) {
                     for (Way wInner : polygon.getInnerWays()) {
-                        ElemStyle innerStyle = styles.get(wInner);
-                        if (wayStyle != null && wayStyle.equals(innerStyle)) {
+                        AreaElemStyle areaInner = null;
+                        for (ElemStyle s : styles.get(wInner).getStyles()) {
+                            if (s instanceof AreaElemStyle) {
+                                areaInner = (AreaElemStyle) s;
+                                break;
+                            }
+                        }
+
+                        if (areaInner != null && area.equals(areaInner)) {
                             List<OsmPrimitive> l = new ArrayList<OsmPrimitive>();
                             l.add(r);
@@ -168,6 +189,12 @@
                     }
                     for (Way wOuter : polygon.getOuterWays()) {
-                        ElemStyle outerStyle = styles.get(wOuter);
-                        if (outerStyle instanceof AreaElemStyle && !wayStyle.equals(outerStyle)) {
+                        AreaElemStyle areaOuter = null;
+                        for (ElemStyle s : styles.get(wOuter).getStyles()) {
+                            if (s instanceof AreaElemStyle) {
+                                areaOuter = (AreaElemStyle) s;
+                                break;
+                            }
+                        }
+                        if (areaOuter != null && !area.equals(areaOuter)) {
                             List<OsmPrimitive> l = new ArrayList<OsmPrimitive>();
                             l.add(r);
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java	(revision 3824)
@@ -1,52 +1,20 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.mappaint;
+
 import java.awt.Color;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
+import org.openstreetmap.josm.tools.Utils;
 
 public class AreaElemStyle extends ElemStyle
 {
     public Color color;
-    public boolean closed;
-    private LineElemStyle line;
 
-    public AreaElemStyle (AreaElemStyle a, long maxScale, long minScale) {
-        this.color = a.color;
-        this.closed = a.closed;
-        this.priority = a.priority;
-        this.maxScale = maxScale;
-        this.minScale = minScale;
-        this.conditions = a.conditions;
-        this.line = new LineElemStyle();
-        this.line.color = a.color;
-    }
-
-    public AreaElemStyle(AreaElemStyle a, LineElemStyle l)
-    {
-        this.color = a.color;
-        this.closed = a.closed;
-        this.priority = a.priority;
-        this.maxScale = a.maxScale;
-        this.minScale = a.minScale;
-        this.conditions = a.conditions;
-        this.line = l;
-        this.code = a.code;
-    }
-
-    public AreaElemStyle() { init(); }
-
-    public void init()
-    {
-        closed = false;
-        color = null;
-        priority = 0;
-    }
-
-    public LineElemStyle getLineStyle() {
-        return line;
+    public AreaElemStyle(long minScale, long maxScale, Color color) {
+        super(minScale, maxScale);
+        this.color = color;
     }
 
@@ -60,3 +28,22 @@
         }
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+        return Utils.equal(color, ((AreaElemStyle) obj).color);
+    }
+
+    @Override
+    public int hashCode() {
+        return color.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "AreaElemStyle{" + "color=" + color + '}';
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 3824)
@@ -2,11 +2,7 @@
 package org.openstreetmap.josm.gui.mappaint;
 
-import java.util.Collection;
-
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
-import org.openstreetmap.josm.gui.mappaint.xml.XmlCondition;
 
 abstract public class ElemStyle {
@@ -15,11 +11,15 @@
     public long maxScale;
 
-    public int priority;
-    public String code;
-    Collection<XmlCondition> conditions = null;
+    public ElemStyle(long minScale, long maxScale) {
+        this.minScale = minScale;
+        this.maxScale = maxScale;
+    }
 
     @Override
     public boolean equals(Object o) {
-        return (o instanceof ElemStyle) && (((ElemStyle) o).getCode().equals(getCode()));
+        if (!(o instanceof ElemStyle))
+            return false;
+        ElemStyle s = (ElemStyle) o;
+        return minScale == s.minScale && maxScale == s.maxScale;
     }
 
@@ -29,30 +29,4 @@
     }
 
-    public String getCode() {
-        if (code == null) {
-            code = "";
-            if (conditions != null) {
-                for (XmlCondition c: conditions) {
-                    code += c.toCode();
-                }
-            }
-        }
-        return code;
-    }
-    public boolean check(OsmPrimitive primitive)
-    {
-        if(conditions == null)
-            return true;
-        for(XmlCondition c : conditions)
-        {
-            String k = primitive.get(c.key);
-            String bv = OsmUtils.getNamedOsmBoolean(c.boolValue);
-            if(k == null || (c.value != null && !k.equals(c.value))
-                    || (bv != null && !bv.equals(OsmUtils.getNamedOsmBoolean(k))))
-                return false;
-        }
-        return true;
-    }
-
     public abstract void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member);
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 3824)
@@ -6,4 +6,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
@@ -14,4 +16,9 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.IconPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.LinePrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.LinemodPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.Prototype;
 import org.openstreetmap.josm.tools.FilteredCollection;
 import org.openstreetmap.josm.tools.Predicate;
@@ -42,10 +49,52 @@
     }
 
-    public ElemStyle get(OsmPrimitive osm) {
-        return (!osm.hasKeys()) ? null : ((osm instanceof Node) ? getNode(osm) : get(osm, false));
+    public static class WayPrototypesRecord {
+        LinePrototype line;
+        List<LinemodPrototype> linemods;
+        AreaPrototype area;
+
+        public List<ElemStyle> createStyles() {
+            List<ElemStyle> ret = new ArrayList<ElemStyle>();
+            if (area != null) {
+                ret.add(area.createStyle());
+            }
+            if (line != null) {
+                ret.add(line.createStyle());
+            } else {
+                if (area != null) {
+                    ret.add(LineElemStyle.createSimpleLineStyle(area.color));
+                } else {
+                    ret.add(LineElemStyle.UNTAGGED_WAY);
+                }
+            }
+
+            if (linemods != null) {
+                for (LinemodPrototype p : linemods) {
+                    LineElemStyle s = p.createStyle(line.getWidth());
+                    if (p.over) {
+                        ret.add(s);
+                    } else {
+                        ret.add(0, s);
+                    }
+                }
+            }
+            return ret;
+        }
     }
 
-    public ElemStyle getNode(OsmPrimitive osm) {
-        IconElemStyle icon = null;
+    public StyleCache get(OsmPrimitive osm) {
+        if (osm instanceof Node) {
+            IconPrototype icon = getNode(osm);
+            if (icon == null)
+                return StyleCache.EMPTY_STYLECACHE;
+            return StyleCache.create(icon.createStyle());
+        } else {
+            WayPrototypesRecord p = get(osm, false);
+            return StyleCache.create(p.createStyles());
+        }
+    }
+
+    public IconPrototype getNode(OsmPrimitive osm) {
+        IconPrototype icon = null;
         for (StyleSource s : getStyleSources()) {
             icon = s.getNode(osm, icon);
@@ -54,24 +103,10 @@
     }
 
-    public ElemStyle get(OsmPrimitive osm, boolean forceArea) {
-        if (!osm.hasKeys())
-            return null;
-        AreaElemStyle area = null;
-        LineElemStyle line = null;
-        ElemStyle result = null;
+    private WayPrototypesRecord get(OsmPrimitive osm, boolean forceArea) {
+        WayPrototypesRecord p = new WayPrototypesRecord();
         for (StyleSource s : getStyleSources()) {
-            result = s.get(osm, forceArea || !(osm instanceof Way) || ((Way) osm).isClosed(), area, line);
-            if (result instanceof LineElemStyle) {
-                area = null;
-                line = (LineElemStyle) result;
-            } else if (result instanceof AreaElemStyle) {
-                area = (AreaElemStyle) result;
-                if (area.getLineStyle() != null) {
-                    line = area.getLineStyle();
-                }
-            } else if (result != null)
-                throw new AssertionError();
+            s.get(osm, forceArea || !(osm instanceof Way) || ((Way) osm).isClosed(), p);
         }
-        return result;
+        return p;
     }
 
@@ -92,11 +127,20 @@
     }
 
-    public ElemStyle getArea(Way osm) {
+    public StyleCache getArea(Way osm) {
         if (osm.hasKeys()) {
             /* force area mode also for unclosed ways */
-            ElemStyle style = get(osm, true);
-            if (style != null && style instanceof AreaElemStyle) {
-                return style;
-            }
+            WayPrototypesRecord p = get(osm, true);
+            if (p.area != null)
+                return StyleCache.create(p.createStyles());
+        }
+        return StyleCache.EMPTY_STYLECACHE;
+    }
+
+    public AreaPrototype getAreaProto(Way osm) {
+        if (osm.hasKeys()) {
+            /* force area mode also for unclosed ways */
+            WayPrototypesRecord p = get(osm, true);
+            if (p.area != null)
+                return p.area;
         }
         return null;
@@ -104,5 +148,11 @@
 
     public IconElemStyle getIcon(OsmPrimitive osm) {
-        return osm.hasKeys() ? (IconElemStyle) getNode(osm) : null;
+        if (!osm.hasKeys())
+            return null;
+        NodeElemStyle icon = getNode(osm).createStyle();
+        if (icon instanceof IconElemStyle) {
+            return (IconElemStyle) icon;
+        }
+        return null;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/IconElemStyle.java	(revision 3824)
@@ -10,24 +10,11 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
 
-public class IconElemStyle extends ElemStyle
-{
+public class IconElemStyle extends NodeElemStyle {
     public ImageIcon icon;
     private ImageIcon disabledIcon;
-    public boolean annotate;
 
-    public IconElemStyle (IconElemStyle i, long maxScale, long minScale) {
-        this.icon = i.icon;
-        this.annotate = i.annotate;
-        this.priority = i.priority;
-        this.maxScale = maxScale;
-        this.minScale = minScale;
-        this.conditions = i.conditions;
-    }
-    public IconElemStyle() { init(); }
-
-    public void init() {
-        icon = null;
-        priority = 0;
-        annotate = true;
+    public IconElemStyle(long minScale, long maxScale, ImageIcon icon) {
+        super(minScale, maxScale);
+        this.icon = icon;
     }
 
@@ -39,10 +26,10 @@
         return disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(icon.getImage()));
     }
+
     @Override
     public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings settings, MapPainter painter, boolean selected, boolean member) {
         if (painter.isShowIcons()) {
             Node n = (Node) primitive;
-            String name = painter.isShowNames() && annotate?painter.getNodeName(n):null;
-            painter.drawNodeIcon(n, (painter.isInactive() || n.isDisabled())?getDisabledIcon():icon, selected, member, name);
+            painter.drawNodeIcon(n, (painter.isInactive() || n.isDisabled())?getDisabledIcon():icon, selected, member, getName(n, painter));
         } else {
             SimpleNodeElemStyle.INSTANCE.paintPrimitive(primitive, settings, painter, selected, member);
@@ -50,3 +37,25 @@
 
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+        
+        final IconElemStyle other = (IconElemStyle) obj;
+        // we should get the same image object due to caching
+        return this.icon.getImage() == other.icon.getImage();
+    }
+
+    @Override
+    public int hashCode() {
+        return icon.getImage().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "IconElemStyle{" + "icon=" + icon + '}';
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 3824)
@@ -3,5 +3,5 @@
 
 import java.awt.Color;
-import java.util.Collection;
+import java.util.Arrays;
 
 import org.openstreetmap.josm.data.osm.Node;
@@ -11,12 +11,16 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
-import org.openstreetmap.josm.tools.I18n;
+import org.openstreetmap.josm.tools.Utils;
 
-public class LineElemStyle extends ElemStyle implements Comparable<LineElemStyle> {
+public class LineElemStyle extends ElemStyle {
 
     public static final LineElemStyle UNTAGGED_WAY;
 
     static {
-        UNTAGGED_WAY = new LineElemStyle();
+        UNTAGGED_WAY = new LineElemStyle(0, Long.MAX_VALUE, -1, 0, PaintColors.UNTAGGED.get(), new float[0], null);
+    }
+
+    public static LineElemStyle createSimpleLineStyle(Color color) {
+        return new LineElemStyle(0, Long.MAX_VALUE, -1, 0, color, new float[0], null);
     }
 
@@ -27,113 +31,11 @@
     public Color dashedColor;
 
-    public boolean over;
-    public enum WidthMode { ABSOLUTE, PERCENT, OFFSET }
-    public WidthMode widthMode;
-
-    public Collection<LineElemStyle> overlays;
-
-    public LineElemStyle(LineElemStyle s, long maxScale, long minScale) {
-        this.width = s.width;
-        this.realWidth = s.realWidth;
-        this.color = s.color;
-        this.dashed = s.dashed;
-        this.dashedColor = s.dashedColor;
-        this.over = s.over;
-        this.widthMode = s.widthMode;
-
-        this.priority = s.priority;
-        this.maxScale = maxScale;
-        this.minScale = minScale;
-        this.conditions = s.conditions;
-    }
-
-    public LineElemStyle(LineElemStyle s, Collection<LineElemStyle> overlays) {
-        this.width = s.width;
-        this.realWidth = s.realWidth;
-        this.color = s.color;
-        this.dashed = s.dashed;
-        this.dashedColor = s.dashedColor;
-        this.over = s.over;
-        this.widthMode = s.widthMode;
-
-        this.priority = s.priority;
-        this.maxScale = s.maxScale;
-        this.minScale = s.minScale;
-        this.conditions = s.conditions;
-
-        this.overlays = overlays;
-        this.code = s.code;
-        for (LineElemStyle o : overlays) {
-            this.code += o.code;
-        }
-    }
-
-    public LineElemStyle() { init(); }
-
-    public void init()
-    {
-        width = -1;
-        realWidth = 0;
-        dashed = new float[0];
-        dashedColor = null;
-        priority = 0;
-        color = PaintColors.UNTAGGED.get();
-        over = true; // only used for line modifications
-        widthMode = WidthMode.ABSOLUTE;
-        overlays = null;
-    }
-
-    // get width for overlays
-    public int getWidth(int ref)
-    {
-        int res;
-        if(widthMode == WidthMode.ABSOLUTE) {
-            res = width;
-        } else if(widthMode == WidthMode.OFFSET) {
-            res = ref + width;
-        } else
-        {
-            if(width < 0) {
-                res = 0;
-            } else {
-                res = ref*width/100;
-            }
-        }
-        return res <= 0 ? 1 : res;
-    }
-
-    public int compareTo(LineElemStyle s) {
-        if(s.priority != priority)
-            return s.priority > priority ? 1 : -1;
-            if(!over && s.over)
-                return -1;
-            // we have no idea how to order other objects :-)
-            return 0;
-    }
-
-    public float[] getDashed() {
-        return dashed;
-    }
-
-    public void setDashed(float[] dashed) {
-        if (dashed.length == 0) {
-            this.dashed = dashed;
-            return;
-        }
-
-        boolean found = false;
-        for (int i=0; i<dashed.length; i++) {
-            if (dashed[i] > 0) {
-                found = true;
-            }
-            if (dashed[i] < 0) {
-                System.out.println(I18n.tr("Illegal dash pattern, values must be positive"));
-            }
-        }
-        if (found) {
-            this.dashed = dashed;
-        } else {
-            System.out.println(I18n.tr("Illegal dash pattern, at least one value must be > 0"));
-        }
+    public LineElemStyle(long minScale, long maxScale, int width, int realWidth, Color color, float[] dashed, Color dashedColor) {
+        super(minScale, maxScale);
+        setWidth(width);
+        this.realWidth = realWidth;
+        this.color = color;
+        this.dashed = dashed;
+        this.dashedColor = dashedColor;
     }
 
@@ -189,39 +91,6 @@
         }
 
-        /* draw overlays under the way */
-        if(overlays != null) {
-            for(LineElemStyle s : overlays) {
-                if(!s.over) {
-                    painter.drawWay(w,
-                        markColor != null ?
-                            (s.color != null ? new Color(markColor.getRed(), markColor.getGreen(), markColor.getBlue(), s.color.getAlpha()) : markColor) :
-                            s.color,
-                        s.getWidth(myWidth),
-                        s.getDashed(),
-                        w.isDisabled() ? paintSettings.getInactiveColor() : s.dashedColor,
-                        false, false, false);
-                }
-            }
-        }
-
-        /* draw the way */
         painter.drawWay(w, markColor != null ? markColor : color, myWidth, dashed, myDashedColor, showDirection,
                     selected ? false : reversedDirection, showOnlyHeadArrowOnly);
-
-        /* draw overlays above the way */
-        if(overlays != null)  {
-            for(LineElemStyle s : overlays) {
-                if(s.over) {
-                    painter.drawWay(w,
-                        markColor != null ?
-                            (s.color != null ? new Color(markColor.getRed(), markColor.getGreen(), markColor.getBlue(), s.color.getAlpha()) : markColor) :
-                            s.color,
-                        s.getWidth(myWidth),
-                        s.getDashed(),
-                        s.dashedColor,
-                        false, false, false);
-                }
-            }
-        }
 
         if(paintSettings.isShowOrderNumber()) {
@@ -247,3 +116,33 @@
         this.width = width;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+        final LineElemStyle other = (LineElemStyle) obj;
+        return width == other.width &&
+                realWidth == other.realWidth &&
+                Utils.equal(color, other.color) &&
+                Arrays.equals(dashed, other.dashed) &&
+                Utils.equal(dashedColor, other.dashedColor);
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 29 * hash + this.width;
+        hash = 29 * hash + this.realWidth;
+        hash = 29 * hash + this.color.hashCode();
+        hash = 29 * hash + Arrays.hashCode(this.dashed);
+        hash = 29 * hash + (this.dashedColor != null ? this.dashedColor.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return "LineElemStyle{" + "width=" + width + " realWidth=" + realWidth + " color=" + color + " dashed=" + Arrays.toString(dashed) + " dashedColor=" + dashedColor + '}';
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 3824)
@@ -0,0 +1,25 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint;
+
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
+
+abstract public class NodeElemStyle extends ElemStyle {
+    public boolean annotate;
+    public String annotation_key;
+
+    public NodeElemStyle(long minScale, long maxScale) {
+        super(minScale, maxScale);
+    }
+
+    protected String getName(Node n, MapPainter painter) {
+        if (painter.isShowNames() && annotate) {
+            if (annotation_key != null) {
+                return n.get(annotation_key);
+            } else {
+                return painter.getNodeName(n);
+            }
+        }
+        return null;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/SimpleNodeElemStyle.java	(revision 3824)
@@ -8,14 +8,14 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
 
-public class SimpleNodeElemStyle extends ElemStyle {
+public class SimpleNodeElemStyle extends NodeElemStyle {
 
     public static final SimpleNodeElemStyle INSTANCE = new SimpleNodeElemStyle();
 
     private SimpleNodeElemStyle() {
-        minScale = 0;
-        maxScale = 1500;
+        super(0, Long.MAX_VALUE);
+        annotate = true;
     }
 
-    private static final int max(int a, int b, int c, int d) {
+    private static int max(int a, int b, int c, int d) {
         return Math.max(Math.max(a, b), Math.max(c, d));
     }
@@ -25,9 +25,7 @@
             boolean selected, boolean member) {
         Node n = (Node)primitive;
-        String name = painter.isShowNames()?painter.getNodeName(n):null;
-
 
         if (n.isHighlighted()) {
-            painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode(), name);
+            painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode(), getName(n, painter));
         } else {
 
@@ -65,7 +63,6 @@
                                     settings.isFillUnselectedNode();
 
-            painter.drawNode(n, color, size, fill, name);
+            painter.drawNode(n, color, size, fill, getName(n, painter));
         }
     }
-
 }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleCache.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleCache.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleCache.java	(revision 3824)
@@ -0,0 +1,81 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Storage;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
+
+public class StyleCache {
+
+    private List<ElemStyle> styles;
+
+    private final static Storage<StyleCache> internPool = new Storage<StyleCache>(); // TODO: clean up the intern pool from time to time (after purge or layer removal)
+
+    public final static StyleCache EMPTY_STYLECACHE = create();
+    public final static StyleCache SIMPLE_NODE_STYLECACHE = create(SimpleNodeElemStyle.INSTANCE);
+    public final static StyleCache UNTAGGED_WAY_STYLECACHE = create(LineElemStyle.UNTAGGED_WAY);
+
+    
+    private StyleCache() {
+        styles = new ArrayList<ElemStyle>();
+    }
+
+    public static StyleCache create() {
+        StyleCache sc = new StyleCache();
+        sc.styles = new ArrayList<ElemStyle>();
+        return sc.intern();
+    }
+
+    public static StyleCache create(ElemStyle... styles) {
+        StyleCache sc = new StyleCache();
+        sc.styles = Arrays.asList(styles);
+        return sc.intern();
+    }
+
+    public static StyleCache create(Collection<ElemStyle> styles) {
+        StyleCache sc = new StyleCache();
+        sc.styles = new ArrayList<ElemStyle>(styles);
+        return sc.intern();
+    }
+
+    public Collection<ElemStyle> getStyles() {
+        return Collections.unmodifiableList(styles);
+    }
+
+    /**
+     * like String.intern() (reduce memory consumption)
+     */
+    public StyleCache intern() {
+        return internPool.putUnique(this);
+    }
+
+    public void paint(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member) {
+        for (ElemStyle s : styles) {
+            s.paintPrimitive(primitive, paintSettings, painter, selected, member);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        return styles.equals(((StyleCache) obj).styles);
+    }
+
+    @Override
+    public int hashCode() {
+        return styles.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "SC{" + styles + '}';
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 3824)
@@ -15,4 +15,10 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.mappaint.ElemStyles.WayPrototypesRecord;
+import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.IconPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.LinePrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.LinemodPrototype;
+import org.openstreetmap.josm.gui.mappaint.xml.Prototype;
 import org.openstreetmap.josm.gui.mappaint.xml.XmlCondition;
 import org.openstreetmap.josm.gui.preferences.SourceEntry;
@@ -20,12 +26,12 @@
 public class StyleSource extends SourceEntry {
 
-    public final HashMap<String, IconElemStyle> icons = new HashMap<String, IconElemStyle>();
-    public final HashMap<String, LineElemStyle> lines = new HashMap<String, LineElemStyle>();
-    public final HashMap<String, LineElemStyle> modifiers = new HashMap<String, LineElemStyle>();
-    public final HashMap<String, AreaElemStyle> areas = new HashMap<String, AreaElemStyle>();
-    public final LinkedList<IconElemStyle> iconsList = new LinkedList<IconElemStyle>();
-    public final LinkedList<LineElemStyle> linesList = new LinkedList<LineElemStyle>();
-    public final LinkedList<LineElemStyle> modifiersList = new LinkedList<LineElemStyle>();
-    public final LinkedList<AreaElemStyle> areasList = new LinkedList<AreaElemStyle>();
+    public final HashMap<String, IconPrototype> icons = new HashMap<String, IconPrototype>();
+    public final HashMap<String, LinePrototype> lines = new HashMap<String, LinePrototype>();
+    public final HashMap<String, LinemodPrototype> modifiers = new HashMap<String, LinemodPrototype>();
+    public final HashMap<String, AreaPrototype> areas = new HashMap<String, AreaPrototype>();
+    public final LinkedList<IconPrototype> iconsList = new LinkedList<IconPrototype>();
+    public final LinkedList<LinePrototype> linesList = new LinkedList<LinePrototype>();
+    public final LinkedList<LinemodPrototype> modifiersList = new LinkedList<LinemodPrototype>();
+    public final LinkedList<AreaPrototype> areasList = new LinkedList<AreaPrototype>();
 
     public boolean hasError = false;
@@ -39,8 +45,8 @@
     }
 
-    public IconElemStyle getNode(OsmPrimitive primitive, IconElemStyle icon) {
+    public IconPrototype getNode(OsmPrimitive primitive, IconPrototype icon) {
         for (String key : primitive.keySet()) {
             String val = primitive.get(key);
-            IconElemStyle style;
+            IconPrototype style;
             if ((style = icons.get("n" + key + "=" + val)) != null) {
                 if (icon == null || style.priority >= icon.priority) {
@@ -59,5 +65,5 @@
             }
         }
-        for (IconElemStyle s : iconsList) {
+        for (IconPrototype s : iconsList) {
             if ((icon == null || s.priority >= icon.priority) && s.check(primitive)) {
                 icon = s;
@@ -72,56 +78,57 @@
      *  multipolygon relations.
      */
-    public ElemStyle get(OsmPrimitive primitive, boolean closed, AreaElemStyle area, LineElemStyle line) {
+    public void get(OsmPrimitive primitive, boolean closed, WayPrototypesRecord p) {
         String lineIdx = null;
-        HashMap<String, LineElemStyle> overlayMap = new HashMap<String, LineElemStyle>();
+        HashMap<String, LinemodPrototype> overlayMap = new HashMap<String, LinemodPrototype>();
         for (String key : primitive.keySet()) {
             String val = primitive.get(key);
-            AreaElemStyle styleArea;
-            LineElemStyle styleLine;
+            AreaPrototype styleArea;
+            LinePrototype styleLine;
+            LinemodPrototype styleLinemod;
             String idx = "n" + key + "=" + val;
-            if ((styleArea = areas.get(idx)) != null && (area == null || styleArea.priority >= area.priority) && (closed || !styleArea.closed)) {
-                area = styleArea;
-            }
-            if ((styleLine = lines.get(idx)) != null && (line == null || styleLine.priority >= line.priority)) {
-                line = styleLine;
+            if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) {
+                p.area = styleArea;
+            }
+            if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) {
+                p.line = styleLine;
                 lineIdx = idx;
             }
-            if ((styleLine = modifiers.get(idx)) != null) {
-                overlayMap.put(idx, styleLine);
+            if ((styleLinemod = modifiers.get(idx)) != null) {
+                overlayMap.put(idx, styleLinemod);
             }
             idx = "b" + key + "=" + OsmUtils.getNamedOsmBoolean(val);
-            if ((styleArea = areas.get(idx)) != null && (area == null || styleArea.priority >= area.priority) && (closed || !styleArea.closed)) {
-                area = styleArea;
-            }
-            if ((styleLine = lines.get(idx)) != null && (line == null || styleLine.priority >= line.priority)) {
-                line = styleLine;
+            if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) {
+                p.area = styleArea;
+            }
+            if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) {
+                p.line = styleLine;
                 lineIdx = idx;
             }
-            if ((styleLine = modifiers.get(idx)) != null) {
-                overlayMap.put(idx, styleLine);
+            if ((styleLinemod = modifiers.get(idx)) != null) {
+                overlayMap.put(idx, styleLinemod);
             }
             idx = "x" + key;
-            if ((styleArea = areas.get(idx)) != null && (area == null || styleArea.priority >= area.priority) && (closed || !styleArea.closed)) {
-                area = styleArea;
-            }
-            if ((styleLine = lines.get(idx)) != null && (line == null || styleLine.priority >= line.priority)) {
-                line = styleLine;
+            if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) {
+                p.area = styleArea;
+            }
+            if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) {
+                p.line = styleLine;
                 lineIdx = idx;
             }
-            if ((styleLine = modifiers.get(idx)) != null) {
-                overlayMap.put(idx, styleLine);
-            }
-        }
-        for (AreaElemStyle s : areasList) {
-            if ((area == null || s.priority >= area.priority) && (closed || !s.closed) && s.check(primitive)) {
-                area = s;
-            }
-        }
-        for (LineElemStyle s : linesList) {
-            if ((line == null || s.priority >= line.priority) && s.check(primitive)) {
-                line = s;
-            }
-        }
-        for (LineElemStyle s : modifiersList) {
+            if ((styleLinemod = modifiers.get(idx)) != null) {
+                overlayMap.put(idx, styleLinemod);
+            }
+        }
+        for (AreaPrototype s : areasList) {
+            if ((p.area == null || s.priority >= p.area.priority) && (closed || !s.closed) && s.check(primitive)) {
+                p.area = s;
+            }
+        }
+        for (LinePrototype s : linesList) {
+            if ((p.line == null || s.priority >= p.line.priority) && s.check(primitive)) {
+                p.line = s;
+            }
+        }
+        for (LinemodPrototype s : modifiersList) {
             if (s.check(primitive)) {
                 overlayMap.put(s.getCode(), s);
@@ -129,21 +136,13 @@
         }
         overlayMap.remove(lineIdx); // do not use overlay if linestyle is from the same rule (example: railway=tram)
-        if (!overlayMap.isEmpty() && line != null) {
-            List<LineElemStyle> tmp = new LinkedList<LineElemStyle>();
-            if (line.overlays != null) {
-                tmp.addAll(line.overlays);
+        if (!overlayMap.isEmpty() && p.line != null) {
+            List<LinemodPrototype> tmp = new LinkedList<LinemodPrototype>();
+            if (p.linemods != null) {
+                tmp.addAll(p.linemods);
             }
             tmp.addAll(overlayMap.values());
             Collections.sort(tmp);
-            line = new LineElemStyle(line, tmp);
-        }
-        if (area != null) {
-            if (line != null) {
-                return new AreaElemStyle(area, line);
-            } else {
-                return area;
-            }
-        }
-        return line;
+            p.linemods = tmp;
+        }
     }
 
@@ -155,5 +154,5 @@
                 String key = iterator.next();
                 String val = o.get(key);
-                AreaElemStyle s = areas.get("n" + key + "=" + val);
+                AreaPrototype s = areas.get("n" + key + "=" + val);
                 if (s == null || (s.closed && noclosed)) {
                     s = areas.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val));
@@ -166,5 +165,5 @@
                 }
             }
-            for (AreaElemStyle s : areasList) {
+            for (AreaPrototype s : areasList) {
                 if (!(s.closed && noclosed) && s.check(o)) {
                     return true;
@@ -179,58 +178,34 @@
     }
 
-    public void add(XmlCondition c, Collection<XmlCondition> conditions, LineElemStyle style) {
-        if(conditions != null)
-        {
-            style.conditions = conditions;
-            linesList.add(style);
-        }
-        else {
-            String key = c.getKey();
-            style.code = key;
-            lines.put(key, style);
-        }
-    }
-
-    public void addModifier(XmlCondition c, Collection<XmlCondition> conditions, LineElemStyle style) {
-        if(conditions != null)
-        {
-            style.conditions = conditions;
-            modifiersList.add(style);
-        }
-        else
-        {
-            String key = c.getKey();
-            style.code = key;
-            modifiers.put(key, style);
-        }
-    }
-
-    public void add(XmlCondition c, Collection<XmlCondition> conditions, AreaElemStyle style) {
-        if(conditions != null)
-        {
-            style.conditions = conditions;
-            areasList.add(style);
-        }
-        else
-        {
-            String key = c.getKey();
-            style.code = key;
-            areas.put(key, style);
-        }
-    }
-
-    public void add(XmlCondition c, Collection<XmlCondition> conditions, IconElemStyle style) {
-        if(conditions != null)
-        {
-            style.conditions = conditions;
-            iconsList.add(style);
-        }
-        else
-        {
-            String key = c.getKey();
-            style.code = key;
-            icons.put(key, style);
-        }
-    }
+    public void add(XmlCondition c, Collection<XmlCondition> conditions, Prototype prot) {
+         if(conditions != null)
+         {
+            prot.conditions = conditions;
+            if (prot instanceof IconPrototype) {
+                iconsList.add((IconPrototype) prot);
+            } else if (prot instanceof LinemodPrototype) {
+                modifiersList.add((LinemodPrototype) prot);
+            } else if (prot instanceof LinePrototype) {
+                linesList.add((LinePrototype) prot);
+            } else if (prot instanceof AreaPrototype) {
+                areasList.add((AreaPrototype) prot);
+            } else
+                throw new RuntimeException();
+         }
+         else {
+             String key = c.getKey();
+            prot.code = key;
+            if (prot instanceof IconPrototype) {
+                icons.put(key, (IconPrototype) prot);
+            } else if (prot instanceof LinemodPrototype) {
+               modifiers.put(key, (LinemodPrototype) prot);
+            } else if (prot instanceof LinePrototype) {
+                lines.put(key, (LinePrototype) prot);
+            } else if (prot instanceof AreaPrototype) {
+                areas.put(key, (AreaPrototype) prot);
+            } else
+                throw new RuntimeException();
+         }
+     }
 
     /**
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/AreaPrototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/AreaPrototype.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/AreaPrototype.java	(revision 3824)
@@ -0,0 +1,32 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.xml;
+
+import java.awt.Color;
+
+import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
+
+public class AreaPrototype extends Prototype {
+    public Color color;
+    public boolean closed;
+
+    public AreaPrototype (AreaPrototype a, long maxScale, long minScale) {
+        super(maxScale, minScale);
+        this.color = a.color;
+        this.closed = a.closed;
+        this.priority = a.priority;
+        this.conditions = a.conditions;
+    }
+
+    public AreaPrototype() { init(); }
+
+    public void init()
+    {
+        closed = false;
+        color = null;
+        priority = 0;
+    }
+
+    public AreaElemStyle createStyle() {
+        return new AreaElemStyle(minScale, maxScale, color);
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/IconPrototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/IconPrototype.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/IconPrototype.java	(revision 3824)
@@ -0,0 +1,40 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.xml;
+
+import javax.swing.ImageIcon;
+
+import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
+import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
+import org.openstreetmap.josm.gui.mappaint.SimpleNodeElemStyle;
+
+public class IconPrototype extends Prototype {
+    
+    public ImageIcon icon;
+    public boolean annotate;
+
+    public IconPrototype (IconPrototype i, long maxScale, long minScale) {
+        super(maxScale, minScale);
+        this.icon = i.icon;
+        this.annotate = i.annotate;
+        this.priority = i.priority;
+        this.conditions = i.conditions;
+    }
+
+    public IconPrototype() { init(); }
+
+    public void init() {
+        icon = null;
+        priority = 0;
+        annotate = true;
+    }
+
+    public NodeElemStyle createStyle() {
+        if (icon == null) {
+            return SimpleNodeElemStyle.INSTANCE;
+        } else {
+            IconElemStyle i = new IconElemStyle(minScale, maxScale, icon);
+            i.annotate = annotate;
+            return i;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java	(revision 3824)
@@ -0,0 +1,81 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.xml;
+
+import java.awt.Color;
+
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
+import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
+import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
+import org.openstreetmap.josm.tools.I18n;
+
+public class LinePrototype extends Prototype {
+
+    protected int width;
+    public int realWidth; //the real width of this line in meter
+    public Color color;
+    protected float[] dashed;
+    public Color dashedColor;
+
+    public LinePrototype(LinePrototype s, long maxScale, long minScale) {
+        super(maxScale, minScale);
+        this.width = s.width;
+        this.realWidth = s.realWidth;
+        this.color = s.color;
+        this.dashed = s.dashed;
+        this.dashedColor = s.dashedColor;
+        this.priority = s.priority;
+        this.conditions = s.conditions;
+    }
+
+    public LinePrototype() { init(); }
+
+    public void init()
+    {
+        width = -1;
+        realWidth = 0;
+        dashed = new float[0];
+        dashedColor = null;
+        priority = 0;
+        color = PaintColors.UNTAGGED.get();
+    }
+
+    public float[] getDashed() {
+        return dashed;
+    }
+
+    public void setDashed(float[] dashed) {
+        if (dashed.length == 0) {
+            this.dashed = dashed;
+            return;
+        }
+
+        boolean found = false;
+        for (int i=0; i<dashed.length; i++) {
+            if (dashed[i] > 0) {
+                found = true;
+            }
+            if (dashed[i] < 0) {
+                System.out.println(I18n.tr("Illegal dash pattern, values must be positive"));
+            }
+        }
+        if (found) {
+            this.dashed = dashed;
+        } else {
+            System.out.println(I18n.tr("Illegal dash pattern, at least one value must be > 0"));
+        }
+    }
+
+    public int getWidth() {
+        if (width == -1)
+            return MapPaintSettings.INSTANCE.getDefaultSegmentWidth();
+        return width;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public LineElemStyle createStyle() {
+        return new LineElemStyle(minScale, maxScale, width, realWidth, color, dashed, dashedColor);
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinemodPrototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinemodPrototype.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinemodPrototype.java	(revision 3824)
@@ -0,0 +1,75 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.xml;
+
+import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
+
+public class LinemodPrototype extends LinePrototype implements Comparable<LinemodPrototype> {
+
+    public boolean over;
+
+    public enum WidthMode { ABSOLUTE, PERCENT, OFFSET }
+    public WidthMode widthMode;
+
+    public LinemodPrototype(LinemodPrototype s, long maxScale, long minScale) {
+        super(s, maxScale, minScale);
+        this.over = s.over;
+        this.widthMode = s.widthMode;
+    }
+
+    public LinemodPrototype() { init(); }
+
+    @Override
+    public void init()
+    {
+        super.init();
+        over = true;
+        widthMode = WidthMode.ABSOLUTE;
+    }
+
+    // get width for overlays
+    public int getWidth(int ref)
+    {
+        int res;
+        if(widthMode == WidthMode.ABSOLUTE) {
+            res = width;
+        } else if(widthMode == WidthMode.OFFSET) {
+            res = ref + width;
+        } else
+        {
+            if(width < 0) {
+                res = 0;
+            } else {
+                res = ref*width/100;
+            }
+        }
+        return res <= 0 ? 1 : res;
+    }
+
+    @Override
+    public int getWidth() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int compareTo(LinemodPrototype s) {
+        if(s.priority != priority)
+            return s.priority > priority ? 1 : -1;
+            if(!over && s.over)
+                return -1;
+            // we have no idea how to order other objects :-)
+            return 0;
+    }
+
+    /**
+     * this method cannot be used for LinemodPrototypes
+     *  - use createStyle(int) instead
+     */
+    @Override
+    public LineElemStyle createStyle() {
+        throw new UnsupportedOperationException();
+    }
+
+    public LineElemStyle createStyle(int refWidth) {
+        return new LineElemStyle(minScale, maxScale, getWidth(refWidth), realWidth, color, dashed, dashedColor);
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/Prototype.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/Prototype.java	(revision 3824)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/Prototype.java	(revision 3824)
@@ -0,0 +1,63 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.xml;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmUtils;
+
+abstract public class Prototype {
+    // zoom range to display the feature
+    public long minScale;
+    public long maxScale;
+
+    public int priority;
+    public String code;
+    public Collection<XmlCondition> conditions = null;
+
+    public Prototype(long maxScale, long minScale) {
+        this.maxScale = maxScale;
+        this.minScale = minScale;
+    }
+
+    public Prototype() {
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof Prototype) && (((Prototype) o).getCode().equals(getCode()));
+    }
+
+    @Override
+    public int hashCode() {
+        return getClass().hashCode();
+    }
+
+    public String getCode() {
+        if(code == null) {
+            code = "";
+            if (conditions != null) {
+                for(XmlCondition r: conditions) {
+                    code += r.toCode();
+                }
+            }
+        }
+        return code;
+    }
+
+    public boolean check(OsmPrimitive primitive)
+    {
+        if(conditions == null)
+            return true;
+        for(XmlCondition r : conditions)
+        {
+            String k = primitive.get(r.key);
+            String bv = OsmUtils.getNamedOsmBoolean(r.boolValue);
+            if(k == null || (r.value != null && !k.equals(r.value))
+                    || (bv != null && !bv.equals(OsmUtils.getNamedOsmBoolean(k))))
+                return false;
+        }
+        return true;
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java	(revision 3823)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java	(revision 3824)
@@ -9,7 +9,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
-import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
-import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.gui.mappaint.StyleSource;
@@ -31,8 +28,8 @@
         long scaleMax;
         long scaleMin;
-        LineElemStyle line = new LineElemStyle();
-        LineElemStyle linemod = new LineElemStyle();
-        AreaElemStyle area = new AreaElemStyle();
-        IconElemStyle icon = new IconElemStyle();
+        LinePrototype line = new LinePrototype();
+        LinemodPrototype linemod = new LinemodPrototype();
+        AreaPrototype area = new AreaPrototype();
+        IconPrototype icon = new IconPrototype();
         public void init()
         {
@@ -81,5 +78,5 @@
     }
 
-    private void startElementLine(String qName, Attributes atts, LineElemStyle line) {
+    private void startElementLine(String qName, Attributes atts, LinePrototype line) {
         for (int count=0; count<atts.getLength(); count++)
         {
@@ -87,19 +84,5 @@
             {
                 String val = atts.getValue(count);
-                if(val.startsWith("+"))
-                {
-                    line.setWidth(Integer.parseInt(val.substring(1)));
-                    line.widthMode = LineElemStyle.WidthMode.OFFSET;
-                }
-                else if(val.startsWith("-"))
-                {
-                    line.setWidth(Integer.parseInt(val));
-                    line.widthMode = LineElemStyle.WidthMode.OFFSET;
-                }
-                else if(val.endsWith("%"))
-                {
-                    line.setWidth(Integer.parseInt(val.substring(0, val.length()-1)));
-                    line.widthMode = LineElemStyle.WidthMode.PERCENT;
-                } else {
+                if (! (val.startsWith("+") || val.startsWith("-") || val.endsWith("%"))) {
                     line.setWidth(Integer.parseInt(val));
                 }
@@ -130,8 +113,36 @@
             } else if(atts.getQName(count).equals("priority")) {
                 line.priority = Integer.parseInt(atts.getValue(count));
+            } else if (!(atts.getQName(count).equals("mode") && line instanceof LinemodPrototype)){
+                error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
+            }
+        }
+    }
+
+    private void startElementLinemod(String qName, Attributes atts, LinemodPrototype line) {
+        startElementLine(qName, atts, line);
+        for (int count=0; count<atts.getLength(); count++)
+        {
+            if(atts.getQName(count).equals("width"))
+            {
+                String val = atts.getValue(count);
+                if(val.startsWith("+"))
+                {
+                    line.setWidth(Integer.parseInt(val.substring(1)));
+                    line.widthMode = LinemodPrototype.WidthMode.OFFSET;
+                }
+                else if(val.startsWith("-"))
+                {
+                    line.setWidth(Integer.parseInt(val));
+                    line.widthMode = LinemodPrototype.WidthMode.OFFSET;
+                }
+                else if(val.endsWith("%"))
+                {
+                    line.setWidth(Integer.parseInt(val.substring(0, val.length()-1)));
+                    line.widthMode = LinemodPrototype.WidthMode.PERCENT;
+                } else {
+                    line.setWidth(Integer.parseInt(val));
+                }
             } else if(atts.getQName(count).equals("mode")) {
                 line.over = !atts.getValue(count).equals("under");
-            } else {
-                error("The element \"" + qName + "\" has unknown attribute \"" + atts.getQName(count) + "\"!");
             }
         }
@@ -189,13 +200,9 @@
                 hadLine = inLine = true;
                 startElementLine(qName, atts, rule.line);
-                if(rule.line.widthMode != LineElemStyle.WidthMode.ABSOLUTE) {
-                    error("Relative widths are not possible for normal lines");
-                    rule.line.widthMode = LineElemStyle.WidthMode.ABSOLUTE;
-                }
             }
             else if (qName.equals("linemod"))
             {
                 hadLineMod = inLineMod = true;
-                startElementLine(qName, atts, rule.linemod);
+                startElementLinemod(qName, atts, rule.linemod);
             }
             else if (qName.equals("icon"))
@@ -245,20 +252,20 @@
             {
                 style.add(rule.cond, rule.conditions,
-                        new LineElemStyle(rule.line, rule.scaleMax, rule.scaleMin));
+                        new LinePrototype(rule.line, rule.scaleMax, rule.scaleMin));
             }
             if(hadLineMod)
             {
-                style.addModifier(rule.cond, rule.conditions,
-                        new LineElemStyle(rule.linemod, rule.scaleMax, rule.scaleMin));
+                style.add(rule.cond, rule.conditions,
+                        new LinemodPrototype(rule.linemod, rule.scaleMax, rule.scaleMin));
             }
             if(hadIcon)
             {
                 style.add(rule.cond, rule.conditions,
-                        new IconElemStyle(rule.icon, rule.scaleMax, rule.scaleMin));
+                        new IconPrototype(rule.icon, rule.scaleMax, rule.scaleMin));
             }
             if(hadArea)
             {
                 style.add(rule.cond, rule.conditions,
-                        new AreaElemStyle(rule.area, rule.scaleMax, rule.scaleMin));
+                        new AreaPrototype(rule.area, rule.scaleMax, rule.scaleMin));
             }
             inRule = false;
