Index: examples/modify-feature-with-labels.html
===================================================================
--- examples/modify-feature-with-labels.html	(revision 0)
+++ examples/modify-feature-with-labels.html	(revision 0)
@@ -0,0 +1,276 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+            "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+  	<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
+  	<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
+    <title>Modify Feature</title>
+    <link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
+    <link rel="stylesheet" href="style.css" type="text/css" />
+    <style type="text/css">
+        #controls {
+            width: 512px;
+        }
+        #controlToggle {
+            padding-left: 1em;
+        }
+        #controlToggle li {
+            list-style: none;
+        }
+        fieldset {
+        	border:1px solid gray;
+			padding:6px;
+			width:500px;
+		}
+    </style>
+    <script src="../lib/Firebug/firebug.js"></script>
+    <script src="../lib/OpenLayers.js"></script>
+    <script type="text/javascript"><!--
+        var map, vectors, controls;
+        function init(){
+            map = new OpenLayers.Map('map');
+            var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
+                "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); 
+            
+            var context = {
+                 getLabel: function(feature) {
+                	return (feature.attributes.label ? feature.attributes.label : '')
+                 }
+             };
+
+            var style = new OpenLayers.Style({
+                strokeColor: "#2222FF",
+                strokeOpacity: 1,
+                strokeWidth: 2,
+                fillColor: "#AAAAFF",
+                fillOpacity: 0.5,
+                label : "${getLabel}",
+                labelMode: '${labelFollowPath}',
+                labelAlign: '${labelAlign}',
+                labelXOffset: "${labelXOffset}",
+                labelYOffset: "${labelYOffset}",
+
+                pointRadius: 6,
+
+               	fontSize: "${fontSize}"
+                //fontOpacity: 1                
+                //fontColor: "darkgray"                               
+                //fontWeight: "bold",
+            }, {context: context});
+
+            var styleMap = new OpenLayers.StyleMap({'default': style});        
+
+         	// allow testing of specific renderers via "?renderer=Canvas", etc
+            var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
+            renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
+            
+            vectors = new OpenLayers.Layer.Vector("Vector Layer", {
+                styleMap: styleMap,
+                renderers: renderer
+            });
+
+            vectors.events.register("beforefeatureadded", this, function(evt) {
+
+                evt.feature.attributes = {
+                	label: document.getElementById("label").value,
+                    fontSize: document.getElementById("fontSize").value,
+                    labelAlign: document.getElementById("labelAlignHoriz").value + 
+                    			document.getElementById("labelAlignVert").value,
+                    labelFollowPath: document.getElementById("alignOnGeom").checked ? 'path' : null,
+              		labelXOffset: document.getElementById("labelXOffset").value,
+              		labelYOffset: document.getElementById("labelYOffset").value
+                }                     
+            });
+
+            map.addLayers([wms, vectors]);
+            map.addControl(new OpenLayers.Control.LayerSwitcher());
+            map.addControl(new OpenLayers.Control.MousePosition());
+            
+            controls = {
+                point: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Point),
+                line: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Path),
+                polygon: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.Polygon),
+                regular: new OpenLayers.Control.DrawFeature(vectors,
+                            OpenLayers.Handler.RegularPolygon,
+                            {handlerOptions: {sides: 5}}),
+                modify: new OpenLayers.Control.ModifyFeature(vectors)
+            };
+            
+            for(var key in controls) {
+                map.addControl(controls[key]);
+            }
+
+            //var selectCtrl = new OpenLayers.Control.SelectFeature(vectors,
+            //    {clickout: true}
+            //);
+
+            //map.addControl(selectCtrl);
+            //selectCtrl.activate();
+
+            var arr = [
+            	new OpenLayers.Geometry.Point(-26, -8),
+            	new OpenLayers.Geometry.Point(-18, -1),            	
+            	new OpenLayers.Geometry.Point(-10, 6),
+            	new OpenLayers.Geometry.Point(-5, 7),
+            	new OpenLayers.Geometry.Point(1, 8),
+            	new OpenLayers.Geometry.Point(0, 10),
+            	new OpenLayers.Geometry.Point(7, 14),
+            	new OpenLayers.Geometry.Point(20, 18)
+            ]
+
+            var lineGeom = new OpenLayers.Geometry.LineString(arr);
+            //var curveGeom = new OpenLayers.Geometry.Curve(arr);
+            
+            var line = new OpenLayers.Feature.Vector(lineGeom);
+            //var curve = new OpenLayers.Feature.Vector(curveGeom);
+
+            vectors.addFeatures([line]);
+            
+            map.setCenter(new OpenLayers.LonLat(0, 0), 3);
+            document.getElementById('noneToggle').checked = true;
+        }
+        
+        function update() {
+            // reset modification mode
+            controls.modify.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
+            var rotate = document.getElementById("rotate").checked;
+            if(rotate) {
+                controls.modify.mode |= OpenLayers.Control.ModifyFeature.ROTATE;
+            }
+            var resize = document.getElementById("resize").checked;
+            if(resize) {
+                controls.modify.mode |= OpenLayers.Control.ModifyFeature.RESIZE;
+                var keepAspectRatio = document.getElementById("keepAspectRatio").checked;
+                if (keepAspectRatio) {
+                    controls.modify.mode &= ~OpenLayers.Control.ModifyFeature.RESHAPE;
+                }
+            }
+            var drag = document.getElementById("drag").checked;
+            if(drag) {
+                controls.modify.mode |= OpenLayers.Control.ModifyFeature.DRAG;
+            }
+            if (rotate || drag) {
+                controls.modify.mode &= ~OpenLayers.Control.ModifyFeature.RESHAPE;
+            }
+            var sides = parseInt(document.getElementById("sides").value);
+            sides = Math.max(3, isNaN(sides) ? 0 : sides);
+            controls.regular.handler.sides = sides;
+            var irregular =  document.getElementById("irregular").checked;
+            controls.regular.handler.irregular = irregular;
+        }
+
+        function toggleControl(element) {
+            for(key in controls) {
+                var control = controls[key];
+                if(element.value == key && element.checked) {
+                    control.activate();
+                } else {
+                    control.deactivate();
+                }
+            }
+        }
+        
+    --></script>
+  </head>
+  <body onload="init()">
+    <h1 id="title">OpenLayers Modify Feature Example</h1>
+    <div id="shortdesc">A demonstration of the ModifyFeature control for editing vector features.</div>
+    <div id="map" class="smallmap"></div>
+    <fieldset>
+    	<legend>Label</legend>
+    	<table width="100%">
+    		<tr><td width="50%"><input width="100%" id="label" type="text" value="input text" /></td>
+    			<td><input id="alignOnGeom" type="checkbox" checked />
+    				<label for="alignOnGeom">align on geometry</label></td>
+    		</tr><tr><td width="50%">font size: 
+    				<select id="fontSize" size="1">
+				      <option value="10px">10px</option>
+				      <option value="14px" selected>14px</option>
+				      <option value="18px">18px</option>
+				      <option value="22px">22px</option>
+				    </select></td>
+    			<td></td>
+    		</tr><tr><td width="50%">labelXOffset:
+    				<input id="labelXOffset" type="text" value="0" /></td>
+    			<td>horizontal align: 
+    				<select id="labelAlignHoriz" size="1">
+				      <option value="c" selected>center</option>
+				      <option value="l">left</option>				      
+				      <option value="r">right</option>
+				    </select></td>
+    		</tr><tr><td width="50%">labelYOffset:
+    				<input id="labelYOffset" type="text" value="0" /></td>
+    			<td>vertical align: 
+    				<select id="labelAlignVert" size="1">
+				      <option value="b" selected>bottom</option>
+				      <option value="m">middle</option>
+				      <option value="t">top</option>				      
+				    </select></td>
+    		</tr>
+    	</table>    	
+    </fieldset>
+    <div id="controls">
+        <ul id="controlToggle">
+            <li>
+                <input type="radio" name="type" value="none" id="noneToggle"
+                       onclick="toggleControl(this);" checked="checked" />
+                <label for="noneToggle">navigate</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="point" id="pointToggle" onclick="toggleControl(this);" />
+                <label for="pointToggle">draw point</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="line" id="lineToggle" onclick="toggleControl(this);" />
+                <label for="lineToggle">draw line</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="polygon" id="polygonToggle" onclick="toggleControl(this);" />
+                <label for="polygonToggle">draw polygon</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="regular" id="regularToggle" onclick="toggleControl(this);" />
+                <label for="regularToggle">draw regular polygon</label>
+                <label for="sides"> - sides</label>
+                <input id="sides" type="text" size="2" maxlength="2"
+                       name="sides" value="5" onchange="update()" />
+                <ul>
+                    <li>
+                        <input id="irregular" type="checkbox"
+                               name="irregular" onchange="update()" />
+                        <label for="irregular">irregular</label>
+                    </li>
+                </ul>
+            </li>
+            <li>
+                <input type="radio" name="type" value="modify" id="modifyToggle"
+                       onclick="toggleControl(this);" />
+                <label for="modifyToggle">modify feature</label>
+                <ul>
+                    <li>
+                        <input id="rotate" type="checkbox"
+                               name="rotate" onchange="update()" />
+                        <label for="rotate">allow rotation</label>
+                    </li>
+                    <li>
+                        <input id="resize" type="checkbox"
+                               name="resize" onchange="update()" />
+                        <label for="resize">allow resizing</label>
+                        (<input id="keepAspectRatio" type="checkbox"
+                               name="keepAspectRatio" onchange="update()" checked="checked" />
+                        <label for="keepAspectRatio">keep aspect ratio</label>)
+                    </li>
+                    <li>
+                        <input id="drag" type="checkbox"
+                               name="drag" onchange="update()" />
+                        <label for="drag">allow dragging</label>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </div>
+  </body>
+</html>
Index: lib/OpenLayers/Renderer.js
===================================================================
--- lib/OpenLayers/Renderer.js	(revision 10081)
+++ lib/OpenLayers/Renderer.js	(working copy)
@@ -185,7 +185,7 @@
                         var res = this.getResolution();
                         location.move(xOffset*res, yOffset*res);
                     }
-                    this.drawText(feature.id, style, location);
+                    this.drawText(feature.id, style, location, feature.geometry);
                 } else {
                     this.removeText(feature.id);
                 }
Index: lib/OpenLayers/Renderer/SVG.js
===================================================================
--- lib/OpenLayers/Renderer/SVG.js	(revision 10081)
+++ lib/OpenLayers/Renderer/SVG.js	(working copy)
@@ -687,12 +687,17 @@
      * style -
      * location - {<OpenLayers.Geometry.Point>}
      */
-    drawText: function(featureId, style, location) {
+    drawText: function(featureId, style, location, geometry) {
         var resolution = this.getResolution();
+
+        if (style.labelMode === 'path') {
+	        var x = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
+        	var y = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
+        } else {
+	        var x = (location.x / resolution + this.left);
+	        var y = (location.y / resolution - this.top);        	
+        }
         
-        var x = (location.x / resolution + this.left);
-        var y = (location.y / resolution - this.top);
-        
         var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
         var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
 
@@ -734,15 +739,88 @@
             tspan.setAttributeNS(null, "baseline-shift",
                 OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
         }
+        
+        if (style.labelMode === 'path') {
+        	var pathNodeId = featureId + this.LABEL_ID_SUFFIX + "_path";
+        	var textPathNodeId = featureId + this.LABEL_ID_SUFFIX + "_textpath";
 
-        tspan.textContent = style.label;
+        	var pathNode = this.nodeFactory(pathNodeId, "path");
+            var textPathNode = this.nodeFactory(textPathNodeId, "textPath");
+            
+            drawn = this.drawTextPath(pathNode, geometry);
+            if (drawn) {                        
+	            pathNode.setAttributeNS(null, "fill", "none");
+	            
+	            textPathNode.setAttributeNS(this.xlinkns, "xlink:href", "#"+pathNodeId);            
+	            textPathNode.setAttributeNS(null, "startOffset",
+	                OpenLayers.Renderer.SVG.LABEL_ALIGN_START_OFFSET[align[0]] || "middle");
+	
+	            textPathNode.textContent = style.label;  
+	            
+	            if(!pathNode.parentNode) {
+	                this.textRoot.appendChild(pathNode);
+	            }            
+	            if (!textPathNode.parentNode)
+	            	label.appendChild(textPathNode);
+            }            
+        } else {
+        	
+        	tspan.textContent = style.label;
+            
+            if(!tspan.parentNode) {
+                label.appendChild(tspan);
+            }   	
+        }
         
         if(!label.parentNode) {
-            label.appendChild(tspan);
             this.textRoot.appendChild(label);
         }   
     },
     
+    /**
+     * Method: drawTextPath
+     * This method is only called by the renderer itself.
+     * 
+     * Parameters: 
+     * node - {DOMElement}
+     * geometry - {<OpenLayers.Geometry>}
+     * 
+     * Returns:
+     * {DOMElement} or null if the renderer could not draw all components
+     *     of the polygon, or false if nothing could be drawn
+     */ 
+    drawTextPath: function(node, geometry) {
+        var componentsResult;
+        var components;
+        
+        switch (geometry.CLASS_NAME) {	    	
+	        case "OpenLayers.Geometry.Polygon":
+	        	return this.drawPolygon(node, geometry);
+	        case "OpenLayers.Geometry.Surface":
+	        	return this.drawSurface(node, geometry);
+	        case "OpenLayers.Geometry.LinearRing":
+	        case "OpenLayers.Geometry.LineString":
+	        	components = [geometry.components];	            
+	            break;
+	        case "OpenLayers.Geometry.Point":
+	        case "OpenLayers.Geometry.Rectangle":
+	        default:
+	        	components = false;
+	    }
+        
+        if (!components)
+        	return false;
+        
+         componentsResult = this.getComponentsString(
+            geometry.components, " ");        
+        if (componentsResult.path) {
+            node.setAttributeNS(null, "d", "M"+componentsResult.path);
+            return (componentsResult.complete ? node : null);  
+        } else {
+            return false;
+        }          
+    },
+    
     /** 
      * Method: getComponentString
      * 
@@ -970,6 +1048,16 @@
 };
 
 /**
+ * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
+ * {Object}
+ */
+OpenLayers.Renderer.SVG.LABEL_ALIGN_START_OFFSET = {
+    "l": "0%",
+    "c": "50%",
+    "r": "100%"
+};
+
+/**
  * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
  * {Object}
  */
