Index: src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 5204)
+++ src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(working copy)
@@ -126,7 +126,7 @@
      *              e.g. oneway street or waterway
      * @param onewayReversed for oneway=-1 and similar
      */
-    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, int offset,
+    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, float offset,
             boolean showOrientation, boolean showHeadArrowOnly,
             boolean showOneway, boolean onewayReversed) {
 
@@ -258,7 +258,7 @@
     public class OffsetIterator implements Iterator<Point> {
 
         private List<Node> nodes;
-        private int offset;
+        private float offset;
         private int idx;
 
         private Point prev = null;
@@ -268,7 +268,7 @@
          */
         private int x_prev0, y_prev0;
 
-        public OffsetIterator(List<Node> nodes, int offset) {
+        public OffsetIterator(List<Node> nodes, float offset) {
             this.nodes = nodes;
             this.offset = offset;
             idx = 0;
@@ -281,7 +281,7 @@
 
         @Override
         public Point next() {
-            if (offset == 0) return nc.getPoint(nodes.get(idx++));
+            if (Math.abs(offset) < 0.1f) return nc.getPoint(nodes.get(idx++));
 
             Point current = nc.getPoint(nodes.get(idx));
 
@@ -860,7 +860,7 @@
 
             if ((pb.width >= nb.getWidth() && pb.height >= nb.getHeight()) && // quick check
                     area.contains(centeredNBounds) // slow but nice
-                    ) {
+            ) {
                 g.setColor(text.color);
                 Font defaultFont = g.getFont();
                 g.setFont (text.font);
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(revision 5204)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(working copy)
@@ -19,6 +19,7 @@
 import org.openstreetmap.josm.gui.mappaint.Cascade;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.Utils;
 
 public interface Expression {
@@ -115,6 +116,14 @@
                 return c;
             }
 
+            public Color html2color(String html) {
+                return ColorHelper.html2color(html);
+            }
+
+            public String color2html(Color c) {
+                return ColorHelper.color2html(c);
+            }
+
             public float red(Color c) {
                 return Utils.color_int2float(c.getRed());
             }
Index: src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(revision 5204)
+++ src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java	(working copy)
@@ -32,12 +32,12 @@
     private BasicStroke line;
     public Color color;
     public Color dashesBackground;
-    public int offset;
+    public float offset;
     public float realWidth; // the real width of this line in meter
 
     private BasicStroke dashesLine;
 
-    protected LineElemStyle(Cascade c, BasicStroke line, Color color, BasicStroke dashesLine, Color dashesBackground, int offset, float realWidth) {
+    protected LineElemStyle(Cascade c, BasicStroke line, Color color, BasicStroke dashesLine, Color dashesBackground, float offset, float realWidth) {
         super(c, 0f);
         this.line = line;
         this.color = color;
@@ -48,11 +48,29 @@
     }
 
     public static LineElemStyle createLine(Environment env) {
-        return createImpl(env, false);
+        return createImpl(env, "");
+    }
+
+    public static LineElemStyle createLeftCasing(Environment env) {
+        LineElemStyle leftCasing = createImpl(env, "left-casing-");
+        if (leftCasing != null) {
+            leftCasing.z_index += -90;
+            leftCasing.isModifier = true;
+        }
+        return leftCasing;
+    }
+
+    public static LineElemStyle createRightCasing(Environment env) {
+        LineElemStyle rightCasing = createImpl(env, "right-casing-");
+        if (rightCasing != null) {
+            rightCasing.z_index += -90;
+            rightCasing.isModifier = true;
+        }
+        return rightCasing;
     }
 
     public static LineElemStyle createCasing(Environment env) {
-        LineElemStyle casing =  createImpl(env, true);
+        LineElemStyle casing = createImpl(env, "casing-");
         if (casing != null) {
             casing.z_index += -100;
             casing.isModifier = true;
@@ -60,22 +78,15 @@
         return casing;
     }
 
-    private static LineElemStyle createImpl(Environment env, boolean casing) {
+    private static LineElemStyle createImpl(Environment env, String prefix) {
         Cascade c = env.mc.getCascade(env.layer);
         Cascade c_def = env.mc.getCascade("default");
 
-        String prefix = casing ? "casing-" : "";
-
-        Float width;
-        if (casing) {
-            Float widthOnDefault = getWidth(c_def, "width", null);
-            Float widthLine = getWidth(c, "width", widthOnDefault);
-            width = getWidth(c, "casing-width", widthLine);
-        } else {
-            Float widthOnDefault = getWidth(c_def, "width", null);
-            width = getWidth(c, "width", widthOnDefault);
+        Float widthOnDefault = getWidth(c_def, "width", null);
+        Float width = getWidth(c, "width", widthOnDefault);
+        if (!prefix.isEmpty()) {
+            width = getWidth(c, prefix + "width", width);
         }
-
         if (width == null)
             return null;
 
@@ -96,8 +107,37 @@
             }
         }
 
+        Float offsetOnDefault = getWidth(c_def, "offset", null);
+        Float offset = getWidth(c, "offset", offsetOnDefault);
+        if (offset == null) {
+            offset = 0f;
+        }
+        if (!prefix.isEmpty()) {
+            Float base_width = getWidth(c, "width", widthOnDefault);
+            Float base_offset = offset;
+            if (base_width == null || base_width < 2f) {
+                base_width = 2f;
+            }
+            /* pre-calculate an offset */
+            if (prefix.startsWith("left") || prefix.startsWith("right")) {
+                offset = base_width/2 + width/2;
+            } else {
+                offset = 0f;
+            }
+            /* overwrites (e.g. "4") or adjusts (e.g. "+4") a prefixed -offset */
+            if (getWidth(c, prefix + "offset", offset) != null) {
+                offset = getWidth(c, prefix + "offset", offset);
+            }
+            /* flip sign for the right-casing-offset */
+            if (prefix.startsWith("right")) {
+                offset *= -1f;
+            }
+            /* use base_offset as the reference center */
+            offset += base_offset;
+        }
+
         Color color = c.get(prefix + "color", null, Color.class);
-        if (!casing && color == null) {
+        if (prefix.isEmpty() && color == null) {
             color = c.get("fill-color", null, Color.class);
         }
         if (color == null) {
@@ -176,8 +216,6 @@
         BasicStroke line = new BasicStroke(width, cap, join, miterlimit, dashes, dashesOffset);
         BasicStroke dashesLine = null;
 
-        float offset = c.get("offset", 0f, Float.class);
-
         if (dashes != null && dashesBackground != null) {
             float[] dashes2 = new float[dashes.length];
             System.arraycopy(dashes, 0, dashes2, 1, dashes.length - 1);
@@ -185,7 +223,7 @@
             dashesLine = new BasicStroke(width, cap, join, miterlimit, dashes2, dashes2[0] + dashesOffset);
         }
 
-        return new LineElemStyle(c, line, color, dashesLine, dashesBackground, (int) offset, realWidth);
+        return new LineElemStyle(c, line, color, dashesLine, dashesBackground, offset, realWidth);
     }
 
     @Override
@@ -258,11 +296,11 @@
             return false;
         final LineElemStyle other = (LineElemStyle) obj;
         return  equal(line, other.line) &&
-            equal(color, other.color) &&
-            equal(dashesLine, other.dashesLine) &&
-            equal(dashesBackground, other.dashesBackground) &&
-            offset == other.offset &&
-            realWidth == other.realWidth;
+        equal(color, other.color) &&
+        equal(dashesLine, other.dashesLine) &&
+        equal(dashesBackground, other.dashesBackground) &&
+        offset == other.offset &&
+        realWidth == other.realWidth;
     }
 
     @Override
@@ -272,7 +310,7 @@
         hash = 29 * hash + color.hashCode();
         hash = 29 * hash + (dashesLine != null ? dashesLine.hashCode() : 0);
         hash = 29 * hash + (dashesBackground != null ? dashesBackground.hashCode() : 0);
-        hash = 29 * hash + offset;
+        hash = 29 * hash + Float.floatToIntBits(offset);
         hash = 29 * hash + Float.floatToIntBits(realWidth);
         return hash;
     }
@@ -280,30 +318,30 @@
     @Override
     public String toString() {
         return "LineElemStyle{" + super.toString() + "width=" + line.getLineWidth() +
-            " realWidth=" + realWidth + " color=" + Utils.toString(color) +
-            " dashed=" + Arrays.toString(line.getDashArray()) +
-            (line.getDashPhase() == 0f ? "" : " dashesOffses=" + line.getDashPhase()) +
-            " dashedColor=" + Utils.toString(dashesBackground) +
-            " linejoin=" + linejoinToString(line.getLineJoin()) +
-            " linecap=" + linecapToString(line.getEndCap()) +
-            (offset == 0 ? "" : " offset=" + offset) +
-            '}';
+        " realWidth=" + realWidth + " color=" + Utils.toString(color) +
+        " dashed=" + Arrays.toString(line.getDashArray()) +
+        (line.getDashPhase() == 0f ? "" : " dashesOffses=" + line.getDashPhase()) +
+        " dashedColor=" + Utils.toString(dashesBackground) +
+        " linejoin=" + linejoinToString(line.getLineJoin()) +
+        " linecap=" + linecapToString(line.getEndCap()) +
+        (offset == 0 ? "" : " offset=" + offset) +
+        '}';
     }
 
     public String linejoinToString(int linejoin) {
         switch (linejoin) {
-            case BasicStroke.JOIN_BEVEL: return "bevel";
-            case BasicStroke.JOIN_ROUND: return "round";
-            case BasicStroke.JOIN_MITER: return "miter";
-            default: return null;
+        case BasicStroke.JOIN_BEVEL: return "bevel";
+        case BasicStroke.JOIN_ROUND: return "round";
+        case BasicStroke.JOIN_MITER: return "miter";
+        default: return null;
         }
     }
     public String linecapToString(int linecap) {
         switch (linecap) {
-            case BasicStroke.CAP_BUTT: return "none";
-            case BasicStroke.CAP_ROUND: return "round";
-            case BasicStroke.CAP_SQUARE: return "square";
-            default: return null;
+        case BasicStroke.CAP_BUTT: return "none";
+        case BasicStroke.CAP_ROUND: return "round";
+        case BasicStroke.CAP_SQUARE: return "square";
+        default: return null;
         }
     }
 }
Index: src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 5204)
+++ src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(working copy)
@@ -310,6 +310,8 @@
                 addIfNotNull(sl, AreaElemStyle.create(c));
                 addIfNotNull(sl, LinePatternElemStyle.create(env));
                 addIfNotNull(sl, LineElemStyle.createLine(env));
+                addIfNotNull(sl, LineElemStyle.createLeftCasing(env));
+                addIfNotNull(sl, LineElemStyle.createRightCasing(env));
                 addIfNotNull(sl, LineElemStyle.createCasing(env));
                 addIfNotNull(sl, LineTextElemStyle.create(env));
             } else if (osm instanceof Node) {
@@ -346,9 +348,8 @@
      * Draw a default node symbol for nodes that have no style?
      */
     private boolean isDefaultNodes() {
-        if (defaultNodesIdx == cacheIdx) {
+        if (defaultNodesIdx == cacheIdx)
             return defaultNodes;
-        }
         defaultNodes = fromCanvas("default-points", true, Boolean.class);
         defaultNodesIdx = cacheIdx;
         return defaultNodes;
@@ -358,9 +359,8 @@
      * Draw a default line for ways that do not have an own line style?
      */
     private boolean isDefaultLines() {
-        if (defaultLinesIdx == cacheIdx) {
+        if (defaultLinesIdx == cacheIdx)
             return defaultLines;
-        }
         defaultLines = fromCanvas("default-lines", true, Boolean.class);
         defaultLinesIdx = cacheIdx;
         return defaultLines;
@@ -419,13 +419,11 @@
      * @return first AreaElemStyle found or {@code null}.
      */
     public static AreaElemStyle getAreaElemStyle(OsmPrimitive p, boolean pretendWayIsClosed) {
-        if (MapPaintStyles.getStyles() == null) {
+        if (MapPaintStyles.getStyles() == null)
             return null;
-        }
         for (ElemStyle s : MapPaintStyles.getStyles().generateStyles(p, 1.0, null, pretendWayIsClosed).a) {
-            if (s instanceof AreaElemStyle) {
+            if (s instanceof AreaElemStyle)
                 return (AreaElemStyle) s;
-            }
         }
         return null;
     }
