Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 3879)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 3880)
@@ -14,5 +14,7 @@
 import java.awt.TexturePaint;
 import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
 import java.awt.font.LineMetrics;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Rectangle2D;
@@ -37,9 +39,9 @@
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.HorizontalTextAlignment;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
-import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.TextElement;
+import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.VerticalTextAlignment;
+import org.openstreetmap.josm.gui.mappaint.TextElement;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.LanguageInfo;
-import org.openstreetmap.josm.tools.Utils;
 
 public class MapPainter {
@@ -106,5 +108,5 @@
     }
 
-    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, boolean showDirection,
+    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, TextElement text, boolean showDirection,
             boolean reversedDirection, boolean showHeadArrowOnly) {
 
@@ -163,4 +165,5 @@
         }
         displaySegments(path, arrows, color, line, dashes, dashedColor);
+        drawTextOnPath(way, text);
     }
 
@@ -193,5 +196,99 @@
     }
 
-    public void drawNodeIcon(Node n, ImageIcon icon, float iconAlpha, boolean selected, boolean member, TextElement text) {
+    private void drawTextOnPath(Way way, TextElement text) {
+        if (text == null)
+            return;
+        String name = getAreaName(way);
+        if (name == null || name.equals(""))
+            return;
+
+        Polygon poly = new Polygon();
+        Point lastPoint = null;
+        Iterator<Node> it = way.getNodes().iterator();
+        double pathLength = 0;
+        int dx, dy;
+        while (it.hasNext()) {
+            Node n = it.next();
+            Point p = nc.getPoint(n);
+            poly.addPoint(p.x, p.y);
+
+            if(lastPoint != null) {
+                dx = p.x - lastPoint.x;
+                dy = p.y - lastPoint.y;
+                pathLength += Math.sqrt(dx*dx + dy*dy);
+            }
+            lastPoint = p;
+        }
+
+        FontMetrics fontMetrics = g.getFontMetrics(text.font); // if slow, use cache
+        Rectangle2D rec = fontMetrics.getStringBounds(name, g); // if slow, approximate by strlen()*maxcharbounds(font)
+
+        if (rec.getWidth() > pathLength)
+            return;
+
+        double t1 = (pathLength/2 - rec.getWidth()/2) / pathLength;
+        double t2 = (pathLength/2 + rec.getWidth()/2) / pathLength;
+
+        double[] p1 = pointAt(t1, poly, pathLength);
+        double[] p2 = pointAt(t2, poly, pathLength);
+
+        double angleOffset;
+        double offsetSign;
+        double tStart;
+
+        if (p1[0] < p2[0] &&
+            p1[2] < Math.PI/2 &&
+            p1[2] > -Math.PI/2) {
+            angleOffset = 0;
+            offsetSign = 1;
+            tStart = t1;
+        } else {
+            angleOffset = Math.PI;
+            offsetSign = -1;
+            tStart = t2;
+        }
+
+        FontRenderContext frc = g.getFontRenderContext();
+        GlyphVector gv = text.font.createGlyphVector(frc, name);
+
+        for (int i=0; i<gv.getNumGlyphs(); ++i) {
+            Rectangle2D rect = gv.getGlyphLogicalBounds(i).getBounds2D();
+            double t = tStart + offsetSign * (rect.getX() + rect.getWidth()/2) / pathLength;
+            double[] p = pointAt(t, poly, pathLength);
+            AffineTransform trfm = AffineTransform.getTranslateInstance(p[0] - rect.getX(), p[1]);
+            trfm.rotate(p[2]+angleOffset);
+            double off = -rect.getY() - rect.getHeight()/2 + text.yOffset;
+            trfm.translate(-rect.getWidth()/2, off);
+            gv.setGlyphTransform(i, trfm);
+        }
+        g.setColor(text.color);
+        g.drawGlyphVector(gv, 0, 0);
+
+    }
+
+    private double[] pointAt(double t, Polygon poly, double pathLength) {
+        double totalLen = t * pathLength;
+        double curLen = 0;
+        int dx, dy;
+        double segLen;
+
+        // Yes, it is ineffecient to iterate from the beginning for each glyph.
+        // Can be optimized if it turns out to be slow.
+        for (int i = 1; i < poly.npoints; ++i) {
+            dx = poly.xpoints[i] - poly.xpoints[i-1];
+            dy = poly.ypoints[i] - poly.ypoints[i-1];
+            segLen = Math.sqrt(dx*dx + dy*dy);
+            if (totalLen > curLen + segLen) {
+                curLen += segLen;
+                continue;
+            }
+            return new double[] {poly.xpoints[i-1]+(totalLen - curLen)/segLen*dx,
+                                 poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
+                                 Math.atan2(dy, dx)};
+        }
+        return null;
+    }
+
+    public void drawNodeIcon(Node n, ImageIcon icon, float iconAlpha, boolean selected, boolean member, NodeTextElement text) {
         Point p = nc.getPoint(n);
         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
@@ -211,5 +308,5 @@
     }
 
-    public void drawNodeSymbol(Node n, Symbol s, Color fillColor, Color strokeColor, TextElement text) {
+    public void drawNodeSymbol(Node n, Symbol s, Color fillColor, Color strokeColor, NodeTextElement text) {
         Point p = nc.getPoint(n);
         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
@@ -253,5 +350,5 @@
      * @param color The color of the node.
      */
-    public void drawNode(Node n, Color color, int size, boolean fill, TextElement text) {
+    public void drawNode(Node n, Color color, int size, boolean fill, NodeTextElement text) {
         if (size > 1) {
             Point p = nc.getPoint(n);
@@ -274,5 +371,5 @@
     }
 
-    private void drawNodeText(Node n, TextElement text, Point p, int w_half, int h_half) {
+    private void drawNodeText(Node n, NodeTextElement text, Point p, int w_half, int h_half) {
         if (!isShowNames() || text == null)
             return;
@@ -345,10 +442,10 @@
     }
 
-    public void drawArea(Way w, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
+    public void drawArea(Way w, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
         Polygon polygon = getPolygon(w);
-        drawArea(polygon, color, fillImage, fillImageAlpha, name);
-    }
-
-    protected void drawArea(Polygon polygon, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
+        drawArea(w, polygon, color, fillImage, fillImageAlpha, text);
+    }
+
+    protected void drawArea(OsmPrimitive osm, Polygon polygon, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
 
         if (fillImage == null) {
@@ -366,5 +463,9 @@
         }
 
-        if (name != null) {
+        if (text != null && isShowNames()) {
+            String name = text.textKey == null ? getAreaName(osm) : osm.get(text.textKey);
+            if (name == null)
+                return;
+
             Rectangle pb = polygon.getBounds();
             FontMetrics fontMetrics = g.getFontMetrics(orderFont); // if slow, use cache
@@ -403,5 +504,5 @@
     }
 
-    public void drawArea(Relation r, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
+    public void drawArea(Relation r, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
         Multipolygon multipolygon = new Multipolygon(nc);
         multipolygon.load(r);
@@ -412,5 +513,5 @@
                     continue;
                 }
-                drawArea(p, color, fillImage, fillImageAlpha, getAreaName(r));
+                drawArea(r, p, color, fillImage, fillImageAlpha, text);
             }
         }
