Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 5801)
@@ -57,4 +57,5 @@
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
+import org.openstreetmap.josm.gui.mappaint.RepeatImageElemStyle.LineImageAlignment;
 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
 import org.openstreetmap.josm.gui.mappaint.TextElement;
@@ -595,15 +596,48 @@
     }
 
+    @Deprecated
     public void drawLinePattern(Way way, Image pattern) {
-        final int width = pattern.getWidth(null);
-        final int height = pattern.getHeight(null);
+        drawRepeatImage(way, pattern, 0f, 0f, LineImageAlignment.TOP);
+    }
+
+    /**
+     * Draw an image along a way repeatedly.
+     *
+     * @param way the way
+     * @param pattern the image
+     * @param offset offset from the way
+     * @param spacing spacing between two images
+     * @param align alignment of the image. The top, center or bottom edge
+     * can be aligned with the way.
+     */
+    public void drawRepeatImage(Way way, Image pattern, float offset, float spacing, LineImageAlignment align) {
+        final int imgWidth = pattern.getWidth(null);
+        final double repeat = imgWidth + spacing;
+        final int imgHeight = pattern.getHeight(null);
 
         Point lastP = null;
-        double wayLength = 0;
-
-        Iterator<Node> it = way.getNodes().iterator();
+        double currentWayLength = 0;
+
+        int dy1, dy2;
+        switch (align) {
+            case TOP:
+                dy1 = 0;
+                dy2 = imgHeight;
+                break;
+            case CENTER:
+                dy1 = - imgHeight / 2;
+                dy2 = imgHeight + dy1;
+                break;
+            case BOTTOM:
+                dy1 = -imgHeight;
+                dy2 = 0;
+                break;
+            default:
+                throw new AssertionError();
+        }
+
+        OffsetIterator it = new OffsetIterator(way.getNodes(), offset);
         while (it.hasNext()) {
-            Node n = it.next();
-            Point thisP = nc.getPoint(n);
+            Point thisP = it.next();
 
             if (lastP != null) {
@@ -613,5 +647,5 @@
                 final double dy = thisP.y - lastP.y;
 
-                double dist = wayLength == 0 ? 0 : width - (wayLength % width);
+                double pos = currentWayLength == 0 ? 0 : repeat - (currentWayLength % repeat);
 
                 AffineTransform saveTransform = g.getTransform();
@@ -619,25 +653,29 @@
                 g.rotate(Math.atan2(dy, dx));
 
-                if (dist > 0) {
-                    g.drawImage(pattern, 0, 0, (int) dist, height,
-                            width - (int) dist, 0, width, height, null);
-                }
-                while (dist < segmentLength) {
-                    if (dist + width > segmentLength) {
-                        g.drawImage(pattern, (int) dist, 0, (int) segmentLength, height,
-                                0, 0, (int) segmentLength - (int) dist, height, null);
+                // draw the rest of the image from the last segment in case it
+                // is cut off
+                if (pos > spacing) {
+                    g.drawImage(pattern, 0, dy1, (int) (pos - spacing), dy2,
+                            (int) (imgWidth + spacing - pos), 0, imgWidth, imgHeight, null);
+                }
+                // draw remaining images for this segment
+                while (pos < segmentLength) {
+                    // cut off at the end?
+                    if (pos + imgWidth > segmentLength) {
+                        g.drawImage(pattern, (int) pos, dy1, (int) segmentLength, dy2,
+                                0, 0, (int) segmentLength - (int) pos, imgHeight, null);
                     } else {
-                        g.drawImage(pattern, (int) dist, 0, nc);
+                        g.drawImage(pattern, (int) pos, dy1, nc);
                     }
-                    dist += width;
+                    pos += repeat;
                 }
                 g.setTransform(saveTransform);
 
-                wayLength += segmentLength;
+                currentWayLength += segmentLength;
             }
             lastP = thisP;
         }
     }
-    
+
     @Override
     public void drawNode(Node n, Color color, int size, boolean fill) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 5801)
@@ -314,4 +314,5 @@
                 addIfNotNull(sl, AreaElemStyle.create(c));
                 addIfNotNull(sl, LinePatternElemStyle.create(env));
+                addIfNotNull(sl, RepeatImageElemStyle.create(env));
                 addIfNotNull(sl, LineElemStyle.createLine(env));
                 addIfNotNull(sl, LineElemStyle.createLeftCasing(env));
@@ -331,4 +332,5 @@
                     addIfNotNull(sl, AreaElemStyle.create(c));
                     addIfNotNull(sl, LinePatternElemStyle.create(env));
+                    addIfNotNull(sl, RepeatImageElemStyle.create(env));
                     addIfNotNull(sl, LineElemStyle.createLine(env));
                     addIfNotNull(sl, LineElemStyle.createCasing(env));
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 5801)
@@ -12,6 +12,6 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
+import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
 import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
-import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.RelativeFloat;
 import org.openstreetmap.josm.tools.Utils;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/LinePatternElemStyle.java	(revision 5801)
@@ -9,6 +9,9 @@
 
 /**
- * similar to mapnik's LinePatternSymbolizer
+ * Similar to mapnik's LinePatternSymbolizer.
+ *
+ * @deprecated superseded by #{@link RepeatImageElemStyle}
  */
+@Deprecated
 public class LinePatternElemStyle extends ElemStyle {
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/RepeatImageElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/RepeatImageElemStyle.java	(revision 5801)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/RepeatImageElemStyle.java	(revision 5801)
@@ -0,0 +1,95 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint;
+
+import static org.openstreetmap.josm.tools.Utils.equal;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
+import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
+import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+public class RepeatImageElemStyle extends ElemStyle implements StyleKeys {
+
+    public enum LineImageAlignment { TOP, CENTER, BOTTOM }
+
+    public MapImage pattern;
+    public float offset;
+    public float spacing;
+    public LineImageAlignment align;
+
+    public RepeatImageElemStyle(Cascade c, MapImage pattern, float offset, float spacing, LineImageAlignment align) {
+        super(c, 2.9f);
+        CheckParameterUtil.ensureParameterNotNull(pattern);
+        CheckParameterUtil.ensureParameterNotNull(align);
+        this.pattern = pattern;
+        this.offset = offset;
+        this.spacing = spacing;
+        this.align = align;
+    }
+
+    public static RepeatImageElemStyle create(Environment env) {
+        // FIXME: make use of NodeElemStyle.createIcon, in order to have
+        // -width, -height and -opacity properties.
+        Cascade c = env.mc.getCascade(env.layer);
+
+        IconReference iconRef = c.get(REPEAT_IMAGE, null, IconReference.class);
+        if (iconRef == null)
+            return null;
+        MapImage pattern = new MapImage(iconRef.iconName, iconRef.source);
+        Float offset = c.get(REPEAT_IMAGE_OFFSET, 0f, Float.class);
+        Float spacing = c.get(REPEAT_IMAGE_SPACING, 0f, Float.class);
+
+        LineImageAlignment align = LineImageAlignment.CENTER;
+        Keyword alignKW = c.get(REPEAT_IMAGE_ALIGN, Keyword.CENTER, Keyword.class);
+        if (equal(alignKW.val, "top")) {
+            align = LineImageAlignment.TOP;
+        } else if (equal(alignKW.val, "bottom")) {
+            align = LineImageAlignment.BOTTOM;
+        }
+
+        return new RepeatImageElemStyle(c, pattern, offset, spacing, align);
+    }
+
+    @Override
+    public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter, boolean selected, boolean member) {
+        Way w = (Way)primitive;
+        painter.drawRepeatImage(w, pattern.getImage(), offset, spacing, align);
+    }
+
+    @Override
+    public boolean isProperLineStyle() {
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+        final RepeatImageElemStyle other = (RepeatImageElemStyle) obj;
+        if (!this.pattern.equals(other.pattern)) return false;
+        if (this.offset != other.offset) return false;
+        if (this.spacing != other.spacing) return false;
+        if (this.align != other.align) return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 83 * hash + this.pattern.hashCode();
+        hash = 83 * hash + Float.floatToIntBits(this.offset);
+        hash = 83 * hash + Float.floatToIntBits(this.spacing);
+        hash = 83 * hash + this.align.hashCode();
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return "RepeatImageStyle{" + super.toString() + "pattern=[" + pattern +
+                "], offset=" + offset + ", spacing=" + spacing + ", align=" + align + "}";
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java	(revision 5801)
@@ -4,21 +4,25 @@
 public interface StyleKeys {
 
-    public static final String COLOR = "color";
-    public static final String DASHES = "dashes";
-    public static final String DASHES_BACKGROUND_COLOR = "dashes-background-color";
-    public static final String DASHES_BACKGROUND_OPACITY = "dashes-background-opacity";
-    public static final String DASHES_OFFSET = "dashes-offset";
-    public static final String FILL_COLOR = "fill-color";
-    public static final String FILL_IMAGE = "fill-image";
-    public static final String FILL_OPACITY = "fill-opacity";
-    public static final String ICON_IMAGE = "icon-image";
-    public static final String MODIFIER = "modifier";
-    public static final String OBJECT_Z_INDEX = "object-z-index";
-    public static final String OFFSET = "offset";
-    public static final String OPACITY = "opacity";
-    public static final String REAL_WIDTH = "real-width";
-    public static final String TEXT_POSITION = "text-position";
-    public static final String TEXT = "text";
-    public static final String WIDTH = "width";
-    public static final String Z_INDEX = "z-index";
+    String COLOR = "color";
+    String DASHES = "dashes";
+    String DASHES_BACKGROUND_COLOR = "dashes-background-color";
+    String DASHES_BACKGROUND_OPACITY = "dashes-background-opacity";
+    String DASHES_OFFSET = "dashes-offset";
+    String FILL_COLOR = "fill-color";
+    String FILL_IMAGE = "fill-image";
+    String FILL_OPACITY = "fill-opacity";
+    String ICON_IMAGE = "icon-image";
+    String MODIFIER = "modifier";
+    String OBJECT_Z_INDEX = "object-z-index";
+    String OFFSET = "offset";
+    String OPACITY = "opacity";
+    String REAL_WIDTH = "real-width";
+    String TEXT_POSITION = "text-position";
+    String TEXT = "text";
+    String WIDTH = "width";
+    String Z_INDEX = "z-index";
+    String REPEAT_IMAGE = "repeat-image";
+    String REPEAT_IMAGE_OFFSET = "repeat-image-offset";
+    String REPEAT_IMAGE_SPACING = "repeat-image-spacing";
+    String REPEAT_IMAGE_ALIGN = "repeat-image-align";
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java	(revision 5800)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java	(revision 5801)
@@ -73,5 +73,5 @@
                 value = val;
             }
-            if (key.equals(ICON_IMAGE) || key.equals(FILL_IMAGE) || key.equals("pattern-image")) {
+            if (key.equals(ICON_IMAGE) || key.equals(FILL_IMAGE) || key.equals("pattern-image") || key.equals(REPEAT_IMAGE)) {
                 if (value instanceof String) {
                     value = new IconReference((String) value, env.source);
