Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 12476)
@@ -582,6 +582,6 @@
         Rectangle2D bounds = text.font.getStringBounds(s, frc);
 
-        double x = Math.round(p.getInViewX()) + text.xOffset + bounds.getCenterX();
-        double y = Math.round(p.getInViewY()) + text.yOffset + bounds.getCenterY();
+        double x = Math.round(p.getInViewX()) + bs.xOffset + bounds.getCenterX();
+        double y = Math.round(p.getInViewY()) + bs.yOffset + bounds.getCenterY();
         /**
          *
@@ -1096,8 +1096,9 @@
      * Draws a text for the given primitive
      * @param osm The primitive to draw the text for
-     * @param text The text definition (font/position/.../text content) to draw.
+     * @param text The text definition (font/position/.../text content) to draw
+     * @param labelPositionStrategy The position of the text
      * @since 11722
      */
-    public void drawText(OsmPrimitive osm, TextLabel text) {
+    public void drawText(OsmPrimitive osm, TextLabel text, PositionForAreaStrategy labelPositionStrategy) {
         if (!isShowNames()) {
             return;
@@ -1114,5 +1115,5 @@
         forEachPolygon(osm, path -> {
             //TODO: Ignore areas that are out of bounds.
-            PositionForAreaStrategy position = text.getLabelPositionStrategy();
+            PositionForAreaStrategy position = labelPositionStrategy;
             MapViewPositionAndRotation center = position.findLabelPlacement(path, nb);
             if (center != null) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java	(revision 12476)
@@ -4,4 +4,5 @@
 import java.awt.Color;
 import java.awt.Rectangle;
+import java.awt.geom.Point2D;
 import java.util.Objects;
 
@@ -173,4 +174,12 @@
     public TextLabel text;
     /**
+     * The x offset of the text.
+     */
+    public int xOffset;
+    /**
+     * The y offset of the text. In screen space (inverted to user space)
+     */
+    public int yOffset;
+    /**
      * The {@link HorizontalTextAlignment} for this text.
      */
@@ -187,10 +196,14 @@
      * @param text The text to display
      * @param boxProvider The box provider to use
+     * @param offsetX x offset, in screen space
+     * @param offsetY y offset, in screen space
      * @param hAlign The {@link HorizontalTextAlignment}
      * @param vAlign The {@link VerticalTextAlignment}
      */
     public BoxTextElement(Cascade c, TextLabel text, BoxProvider boxProvider,
-            HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
+            int offsetX, int offsetY, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
         super(c, 5f);
+        xOffset = offsetX;
+        yOffset = offsetY;
         CheckParameterUtil.ensureParameterNotNull(text);
         CheckParameterUtil.ensureParameterNotNull(hAlign);
@@ -250,6 +263,7 @@
                 vAlign = VerticalTextAlignment.BOTTOM;
         }
-
-        return new BoxTextElement(c, text, boxProvider, hAlign, vAlign);
+        Point2D offset = TextLabel.getTextOffset(c);
+
+        return new BoxTextElement(c, text, boxProvider, (int) offset.getX(), (int) -offset.getY(), hAlign, vAlign);
     }
 
@@ -283,4 +297,6 @@
         return hAlign == that.hAlign &&
                vAlign == that.vAlign &&
+               xOffset == that.xOffset &&
+               yOffset == that.yOffset &&
                Objects.equals(text, that.text) &&
                Objects.equals(boxProvider, that.boxProvider);
@@ -289,5 +305,5 @@
     @Override
     public int hashCode() {
-        return Objects.hash(super.hashCode(), text, boxProvider, hAlign, vAlign);
+        return Objects.hash(super.hashCode(), text, boxProvider, hAlign, vAlign, xOffset, yOffset);
     }
 
@@ -295,5 +311,5 @@
     public String toString() {
         return "BoxTextElement{" + super.toString() + ' ' + text.toStringImpl()
-                + " box=" + getBox() + " hAlign=" + hAlign + " vAlign=" + vAlign + '}';
+                + " box=" + getBox() + " hAlign=" + hAlign + " vAlign=" + vAlign + " xOffset=" + xOffset + " yOffset=" + yOffset + '}';
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextElement.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextElement.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextElement.java	(revision 12476)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.gui.mappaint.Keyword;
 import org.openstreetmap.josm.gui.mappaint.styleelement.placement.CompletelyInsideAreaStrategy;
+import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy;
 
 /**
@@ -21,8 +22,28 @@
 
     private final TextLabel text;
+    /**
+     * The position strategy for this text label.
+     */
+    private final PositionForAreaStrategy labelPositionStrategy;
 
-    protected TextElement(Cascade c, TextLabel text) {
+    /**
+     * Create a new way/area text element definition
+     * @param c The cascade
+     * @param text The text
+     * @param labelPositionStrategy The position in the area.
+     */
+    protected TextElement(Cascade c, TextLabel text, PositionForAreaStrategy labelPositionStrategy) {
         super(c, 4.9f);
-        this.text = text;
+        this.text = Objects.requireNonNull(text, "text");
+        this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy");
+    }
+
+    /**
+     * Gets the strategy that defines where to place the label.
+     * @return The strategy. Never null.
+     * @since 12475
+     */
+    public PositionForAreaStrategy getLabelPositionStrategy() {
+        return labelPositionStrategy;
     }
 
@@ -37,5 +58,10 @@
             return null;
         final Cascade c = env.mc.getCascade(env.layer);
-        return new TextElement(c, text);
+
+        Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class);
+        PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword);
+        position = position.withAddedOffset(TextLabel.getTextOffset(c));
+
+        return new TextElement(c, text, position);
     }
 
@@ -58,5 +84,5 @@
             return null;
         }
-        return new TextElement(c, text.withPosition(CompletelyInsideAreaStrategy.INSTANCE));
+        return new TextElement(c, text, CompletelyInsideAreaStrategy.INSTANCE);
     }
 
@@ -64,5 +90,5 @@
     public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
             boolean selected, boolean outermember, boolean member) {
-        painter.drawText(primitive, text);
+        painter.drawText(primitive, text, getLabelPositionStrategy());
     }
 
@@ -73,15 +99,16 @@
         if (!super.equals(obj)) return false;
         TextElement that = (TextElement) obj;
-        return Objects.equals(text, that.text);
+        return Objects.equals(labelPositionStrategy, that.labelPositionStrategy)
+            && Objects.equals(text, that.text);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(super.hashCode(), text);
+        return Objects.hash(super.hashCode(), text, labelPositionStrategy);
     }
 
     @Override
     public String toString() {
-        return "TextElement{" + super.toString() + "text=" + text + '}';
+        return "TextElement{" + super.toString() + "text=" + text + " labelPositionStrategy=" + labelPositionStrategy + '}';
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java	(revision 12476)
@@ -4,4 +4,5 @@
 import java.awt.Color;
 import java.awt.Font;
+import java.awt.geom.Point2D;
 import java.util.Objects;
 
@@ -15,5 +16,4 @@
 import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.StaticLabelCompositionStrategy;
 import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.TagLookupCompositionStrategy;
-import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Utils;
@@ -39,12 +39,4 @@
     public Font font;
     /**
-     * The x offset of the text.
-     */
-    public int xOffset;
-    /**
-     * The y offset of the text.
-     */
-    public int yOffset;
-    /**
      * The color to draw the text in, includes alpha.
      */
@@ -58,9 +50,4 @@
      */
     public Color haloColor;
-
-    /**
-     * The position strategy for this text label.
-     */
-    private final PositionForAreaStrategy labelPositionStrategy;
 
     /**
@@ -70,21 +57,15 @@
      * If null, no label is rendered.
      * @param font the font to be used. Must not be null.
-     * @param xOffset x offset
-     * @param yOffset y offset
      * @param color the color to be used. Must not be null
      * @param haloRadius halo radius
      * @param haloColor halo color
-     * @param labelPositionStrategy The position in the area.
-     */
-    protected TextLabel(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius,
-            Color haloColor, PositionForAreaStrategy labelPositionStrategy) {
+     */
+    protected TextLabel(LabelCompositionStrategy strategy, Font font, Color color, Float haloRadius,
+            Color haloColor) {
         this.labelCompositionStrategy = strategy;
         this.font = Objects.requireNonNull(font, "font");
-        this.xOffset = xOffset;
-        this.yOffset = yOffset;
         this.color = Objects.requireNonNull(color, "color");
         this.haloRadius = haloRadius;
         this.haloColor = haloColor;
-        this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy");
     }
 
@@ -97,27 +78,7 @@
         this.labelCompositionStrategy = other.labelCompositionStrategy;
         this.font = other.font;
-        this.xOffset = other.xOffset;
-        this.yOffset = other.yOffset;
         this.color = other.color;
         this.haloColor = other.haloColor;
         this.haloRadius = other.haloRadius;
-        this.labelPositionStrategy = other.labelPositionStrategy;
-    }
-
-    /**
-     * Copy constructor that changes the position strategy.
-     *
-     * @param other the other element.
-     * @param labelPositionStrategy the position
-     */
-    private TextLabel(TextLabel other, PositionForAreaStrategy labelPositionStrategy) {
-        this.labelCompositionStrategy = other.labelCompositionStrategy;
-        this.font = other.font;
-        this.xOffset = other.xOffset;
-        this.yOffset = other.yOffset;
-        this.color = other.color;
-        this.haloColor = other.haloColor;
-        this.haloRadius = other.haloRadius;
-        this.labelPositionStrategy = labelPositionStrategy;
     }
 
@@ -176,4 +137,28 @@
         Font font = StyleElement.getFont(c, s);
 
+        Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class);
+        float alpha = c.get(TEXT_OPACITY, 1f, Float.class);
+        color = Utils.alphaMultiply(color, alpha);
+
+        Float haloRadius = c.get(TEXT_HALO_RADIUS, null, Float.class);
+        if (haloRadius != null && haloRadius <= 0) {
+            haloRadius = null;
+        }
+        Color haloColor = null;
+        if (haloRadius != null) {
+            haloColor = c.get(TEXT_HALO_COLOR, Utils.complement(color), Color.class);
+            float haloAlphaFactor = c.get(TEXT_HALO_OPACITY, 1f, Float.class);
+            haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor);
+        }
+
+        return new TextLabel(strategy, font, color, haloRadius, haloColor);
+    }
+
+    /**
+     * Gets the text-offset property from a cascade
+     * @param c The cascade
+     * @return The text offset property
+     */
+    public static Point2D getTextOffset(Cascade c) {
         float xOffset = 0;
         float yOffset = 0;
@@ -189,24 +174,5 @@
         xOffset = c.get(TEXT_OFFSET_X, xOffset, Float.class);
         yOffset = c.get(TEXT_OFFSET_Y, yOffset, Float.class);
-
-        Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class);
-        float alpha = c.get(TEXT_OPACITY, 1f, Float.class);
-        color = Utils.alphaMultiply(color, alpha);
-
-        Float haloRadius = c.get(TEXT_HALO_RADIUS, null, Float.class);
-        if (haloRadius != null && haloRadius <= 0) {
-            haloRadius = null;
-        }
-        Color haloColor = null;
-        if (haloRadius != null) {
-            haloColor = c.get(TEXT_HALO_COLOR, Utils.complement(color), Color.class);
-            float haloAlphaFactor = c.get(TEXT_HALO_OPACITY, 1f, Float.class);
-            haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor);
-        }
-
-        Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class);
-        PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword);
-
-        return new TextLabel(strategy, font, (int) xOffset, -(int) yOffset, color, haloRadius, haloColor, position);
+        return new Point2D.Double(xOffset, yOffset);
     }
 
@@ -223,22 +189,4 @@
     }
 
-    /**
-     * Gets the strategy that defines where to place the label.
-     * @return The strategy. Never null.
-     * @since 11722
-     */
-    public PositionForAreaStrategy getLabelPositionStrategy() {
-        return labelPositionStrategy;
-    }
-
-    /**
-     * Creates a new text label with a different position strategy
-     * @param labelPositionStrategy The new position strategy to use
-     * @return The new label
-     */
-    public TextLabel withPosition(PositionForAreaStrategy labelPositionStrategy) {
-        return new TextLabel(this, labelPositionStrategy);
-    }
-
     @Override
     public String toString() {
@@ -249,12 +197,6 @@
         StringBuilder sb = new StringBuilder(96);
         sb.append("labelCompositionStrategy=").append(labelCompositionStrategy)
-          .append(" font=").append(font);
-        if (xOffset != 0) {
-            sb.append(" xOffset=").append(xOffset);
-        }
-        if (yOffset != 0) {
-            sb.append(" yOffset=").append(yOffset);
-        }
-        sb.append(" color=").append(Utils.toString(color));
+          .append(" font=").append(font)
+          .append(" color=").append(Utils.toString(color));
         if (haloRadius != null) {
             sb.append(" haloRadius=").append(haloRadius)
@@ -266,5 +208,5 @@
     @Override
     public int hashCode() {
-        return Objects.hash(labelCompositionStrategy, font, xOffset, yOffset, color, haloRadius, haloColor);
+        return Objects.hash(labelCompositionStrategy, font, color, haloRadius, haloColor);
     }
 
@@ -274,7 +216,5 @@
         if (obj == null || getClass() != obj.getClass()) return false;
         TextLabel textLabel = (TextLabel) obj;
-        return xOffset == textLabel.xOffset &&
-                yOffset == textLabel.yOffset &&
-                Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) &&
+        return Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) &&
                 Objects.equals(font, textLabel.font) &&
                 Objects.equals(color, textLabel.color) &&
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/CompletelyInsideAreaStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/CompletelyInsideAreaStrategy.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/CompletelyInsideAreaStrategy.java	(revision 12476)
@@ -3,4 +3,5 @@
 
 import java.awt.Rectangle;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 
@@ -20,7 +21,12 @@
      * An instance of this class.
      */
-    public static final CompletelyInsideAreaStrategy INSTANCE = new CompletelyInsideAreaStrategy();
+    public static final CompletelyInsideAreaStrategy INSTANCE = new CompletelyInsideAreaStrategy(0, 0);
 
-    protected CompletelyInsideAreaStrategy() {
+    protected final double offsetX;
+    protected final double offsetY;
+
+    protected CompletelyInsideAreaStrategy(double offsetX, double offsetY) {
+        this.offsetX = offsetX;
+        this.offsetY = offsetY;
     }
 
@@ -89,7 +95,8 @@
     }
 
-    private static MapViewPositionAndRotation centerOf(MapViewState mapViewState, Rectangle centeredNBounds) {
-        return new MapViewPositionAndRotation(
-                mapViewState.getForView(centeredNBounds.getCenterX(), centeredNBounds.getCenterY()), 0);
+    private MapViewPositionAndRotation centerOf(MapViewState mapViewState, Rectangle centeredNBounds) {
+        double x = centeredNBounds.getCenterX() + offsetX;
+        double y = centeredNBounds.getCenterY() + offsetY;
+        return new MapViewPositionAndRotation(mapViewState.getForView(x, y), 0);
     }
 
@@ -98,3 +105,45 @@
         return false;
     }
+
+    @Override
+    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
+        if (Math.abs(addToOffset.getX()) < 1e-5 && Math.abs(addToOffset.getY()) < 1e-5) {
+            return this;
+        } else {
+            return new CompletelyInsideAreaStrategy(offsetX + addToOffset.getX(), offsetY + addToOffset.getY());
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "CompletelyInsideAreaStrategy [offsetX=" + offsetX + ", offsetY=" + offsetY + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        temp = Double.doubleToLongBits(offsetX);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        temp = Double.doubleToLongBits(offsetY);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        CompletelyInsideAreaStrategy other = (CompletelyInsideAreaStrategy) obj;
+        return Double.doubleToLongBits(offsetX) == Double.doubleToLongBits(other.offsetX)
+                && Double.doubleToLongBits(offsetY) != Double.doubleToLongBits(other.offsetY);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/OnLineStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/OnLineStrategy.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/OnLineStrategy.java	(revision 12476)
@@ -4,4 +4,5 @@
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
@@ -332,3 +333,45 @@
         return Math.atan2(end.getInViewY() - start.getInViewY(), end.getInViewX() - start.getInViewX());
     }
+
+    @Override
+    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
+        if (Math.abs(addToOffset.getY()) < 1e-5) {
+            return this;
+        } else {
+            return new OnLineStrategy(addToOffset.getY() + this.yOffset);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "OnLineStrategy [yOffset=" + yOffset + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        temp = Double.doubleToLongBits(yOffset);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        OnLineStrategy other = (OnLineStrategy) obj;
+        if (Double.doubleToLongBits(yOffset) != Double.doubleToLongBits(other.yOffset)) {
+            return false;
+        }
+        return true;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PartiallyInsideAreaStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PartiallyInsideAreaStrategy.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PartiallyInsideAreaStrategy.java	(revision 12476)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.mappaint.styleelement.placement;
 
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 
@@ -20,7 +21,8 @@
      * An instance of this class.
      */
-    public static final PartiallyInsideAreaStrategy INSTANCE = new PartiallyInsideAreaStrategy();
+    public static final PartiallyInsideAreaStrategy INSTANCE = new PartiallyInsideAreaStrategy(0, 0);
 
-    private PartiallyInsideAreaStrategy() {
+    private PartiallyInsideAreaStrategy(double offsetX, double offsetY) {
+        super(offsetX, offsetY);
     }
 
@@ -44,3 +46,17 @@
         }
     }
+
+    @Override
+    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
+        if (Math.abs(addToOffset.getX()) < 1e-5 && Math.abs(addToOffset.getY()) < 1e-5) {
+            return this;
+        } else {
+            return new PartiallyInsideAreaStrategy(offsetX + addToOffset.getX(), offsetY + addToOffset.getY());
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "PartiallyInsideAreaStrategy [offsetX=" + offsetX + ", offsetY=" + offsetY + "]";
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PositionForAreaStrategy.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PositionForAreaStrategy.java	(revision 12475)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PositionForAreaStrategy.java	(revision 12476)
@@ -3,4 +3,5 @@
 
 import java.awt.font.GlyphVector;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.List;
@@ -79,3 +80,11 @@
         }
     }
+
+    /**
+     * Create a new instance of the same strategy adding a offset
+     * @param addToOffset The offset to add
+     * @return The new strategy
+     * @since 12476
+     */
+    PositionForAreaStrategy withAddedOffset(Point2D addToOffset);
 }
