source: Dev/branches/rest-dojo-ui/client/dojox/gfx/vml.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 39.4 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/Color", "dojo/_base/sniff",
2                "dojo/_base/config", "dojo/dom", "dojo/dom-geometry", "dojo/_base/window",
3                "./_base", "./shape", "./path", "./arc", "./gradient", "./matrix"],
4  function(lang, declare, arr, Color, has, config, dom, domGeom, win, g, gs, pathLib, arcLib, gradient, m){
5/*=====
6        dojox.gfx.vml = {
7        // module:
8        //              dojox/gfx/vml
9        // summary:
10        //              This the default graphics rendering bridge for IE6-7.
11        //              This renderer is very slow.  For best performance on IE6-8, use Silverlight plugin.
12        //              IE9+ defaults to the standard W3C SVG renderer.
13        };
14        g = dojox.gfx;
15        pathLib.Path = dojox.gfx.path.Path;
16        pathLib.TextPath = dojox.gfx.path.TextPath;
17        vml.Shape = dojox.gfx.canvas.Shape;
18        gs.Shape = dojox.gfx.shape.Shape;
19        gs.Rect = dojox.gfx.shape.Rect;
20        gs.Ellipse = dojox.gfx.shape.Ellipse;
21        gs.Circle = dojox.gfx.shape.Circle;
22        gs.Line = dojox.gfx.shape.Line;
23        gs.PolyLine = dojox.gfx.shape.PolyLine;
24        gs.Image = dojox.gfx.shape.Image;
25        gs.Text = dojox.gfx.shape.Text;
26        gs.Surface = dojox.gfx.shape.Surface;
27  =====*/
28        var vml = g.vml = {};
29
30        // dojox.gfx.vml.xmlns: String: a VML's namespace
31        vml.xmlns = "urn:schemas-microsoft-com:vml";
32
33        document.namespaces.add("v", vml.xmlns);
34        var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"],
35                i = 0, l = 1, s = document.createStyleSheet();
36        if(has("ie") >= 8){
37                i = 1;
38                l = vmlElems.length;
39        }
40        for (; i < l; ++i) {
41                s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block");
42        }
43
44        // dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML alignment
45        vml.text_alignment = {start: "left", middle: "center", end: "right"};
46
47        vml._parseFloat = function(str) {
48                // summary: a helper function to parse VML-specific floating-point values
49                // str: String: a representation of a floating-point number
50                return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str);  // Number
51        };
52
53        vml._bool = {"t": 1, "true": 1};
54
55        declare("dojox.gfx.vml.Shape", gs.Shape, {
56                // summary: VML-specific implementation of dojox.gfx.Shape methods
57
58                setFill: function(fill){
59                        // summary: sets a fill object (VML)
60                        // fill: Object: a fill object
61                        //      (see dojox.gfx.defaultLinearGradient,
62                        //      dojox.gfx.defaultRadialGradient,
63                        //      dojox.gfx.defaultPattern,
64                        //      or dojo.Color)
65
66                        if(!fill){
67                                // don't fill
68                                this.fillStyle = null;
69                                this.rawNode.filled = "f";
70                                return this;
71                        }
72                        var i, f, fo, a, s;
73                        if(typeof fill == "object" && "type" in fill){
74                                // gradient
75                                switch(fill.type){
76                                        case "linear":
77                                                var matrix = this._getRealMatrix(), bbox = this.getBoundingBox(),
78                                                        tbbox = this._getRealBBox ? this._getRealBBox() : this.getTransformedBoundingBox();
79                                                s = [];
80                                                if(this.fillStyle !== fill){
81                                                        this.fillStyle = g.makeParameters(g.defaultLinearGradient, fill);
82                                                }
83                                                f = g.gradient.project(matrix, this.fillStyle,
84                                                                {x: bbox.x, y: bbox.y},
85                                                                {x: bbox.x + bbox.width, y: bbox.y + bbox.height},
86                                                                tbbox[0], tbbox[2]);
87                                                a = f.colors;
88                                                if(a[0].offset.toFixed(5) != "0.00000"){
89                                                        s.push("0 " + g.normalizeColor(a[0].color).toHex());
90                                                }
91                                                for(i = 0; i < a.length; ++i){
92                                                        s.push(a[i].offset.toFixed(5) + " " + g.normalizeColor(a[i].color).toHex());
93                                                }
94                                                i = a.length - 1;
95                                                if(a[i].offset.toFixed(5) != "1.00000"){
96                                                        s.push("1 " + g.normalizeColor(a[i].color).toHex());
97                                                }
98                                                fo = this.rawNode.fill;
99                                                fo.colors.value = s.join(";");
100                                                fo.method = "sigma";
101                                                fo.type = "gradient";
102                                                fo.angle = (270 - m._radToDeg(f.angle)) % 360;
103                                                fo.on = true;
104                                                break;
105                                        case "radial":
106                                                f = g.makeParameters(g.defaultRadialGradient, fill);
107                                                this.fillStyle = f;
108                                                var l = parseFloat(this.rawNode.style.left),
109                                                        t = parseFloat(this.rawNode.style.top),
110                                                        w = parseFloat(this.rawNode.style.width),
111                                                        h = parseFloat(this.rawNode.style.height),
112                                                        c = isNaN(w) ? 1 : 2 * f.r / w;
113                                                a = [];
114                                                // add a color at the offset 0 (1 in VML coordinates)
115                                                if(f.colors[0].offset > 0){
116                                                        a.push({offset: 1, color: g.normalizeColor(f.colors[0].color)});
117                                                }
118                                                // massage colors
119                                                arr.forEach(f.colors, function(v, i){
120                                                        a.push({offset: 1 - v.offset * c, color: g.normalizeColor(v.color)});
121                                                });
122                                                i = a.length - 1;
123                                                while(i >= 0 && a[i].offset < 0){ --i; }
124                                                if(i < a.length - 1){
125                                                        // correct excessive colors
126                                                        var q = a[i], p = a[i + 1];
127                                                        p.color = Color.blendColors(q.color, p.color, q.offset / (q.offset - p.offset));
128                                                        p.offset = 0;
129                                                        while(a.length - i > 2) a.pop();
130                                                }
131                                                // set colors
132                                                i = a.length - 1, s = [];
133                                                if(a[i].offset > 0){
134                                                        s.push("0 " + a[i].color.toHex());
135                                                }
136                                                for(; i >= 0; --i){
137                                                        s.push(a[i].offset.toFixed(5) + " " + a[i].color.toHex());
138                                                }
139                                                fo = this.rawNode.fill;
140                                                fo.colors.value = s.join(";");
141                                                fo.method = "sigma";
142                                                fo.type = "gradientradial";
143                                                if(isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)){
144                                                        fo.focusposition = "0.5 0.5";
145                                                }else{
146                                                        fo.focusposition = ((f.cx - l) / w).toFixed(5) + " " + ((f.cy - t) / h).toFixed(5);
147                                                }
148                                                fo.focussize = "0 0";
149                                                fo.on = true;
150                                                break;
151                                        case "pattern":
152                                                f = g.makeParameters(g.defaultPattern, fill);
153                                                this.fillStyle = f;
154                                                fo = this.rawNode.fill;
155                                                fo.type = "tile";
156                                                fo.src = f.src;
157                                                if(f.width && f.height){
158                                                        // in points
159                                                        fo.size.x = g.px2pt(f.width);
160                                                        fo.size.y = g.px2pt(f.height);
161                                                }
162                                                fo.alignShape = "f";
163                                                fo.position.x = 0;
164                                                fo.position.y = 0;
165                                                fo.origin.x = f.width  ? f.x / f.width  : 0;
166                                                fo.origin.y = f.height ? f.y / f.height : 0;
167                                                fo.on = true;
168                                                break;
169                                }
170                                this.rawNode.fill.opacity = 1;
171                                return this;
172                        }
173                        // color object
174                        this.fillStyle = g.normalizeColor(fill);
175                        fo = this.rawNode.fill;
176                        if(!fo){
177                                fo = this.rawNode.ownerDocument.createElement("v:fill");
178                        }
179                        fo.method = "any";
180                        fo.type = "solid";
181                        fo.opacity = this.fillStyle.a;
182                        var alphaFilter = this.rawNode.filters["DXImageTransform.Microsoft.Alpha"];
183                        if(alphaFilter){
184                                alphaFilter.opacity = Math.round(this.fillStyle.a * 100);
185                        }
186                        this.rawNode.fillcolor = this.fillStyle.toHex();
187                        this.rawNode.filled = true;
188                        return this;    // self
189                },
190
191                setStroke: function(stroke){
192                        // summary: sets a stroke object (VML)
193                        // stroke: Object: a stroke object
194                        //      (see dojox.gfx.defaultStroke)
195
196                        if(!stroke){
197                                // don't stroke
198                                this.strokeStyle = null;
199                                this.rawNode.stroked = "f";
200                                return this;
201                        }
202                        // normalize the stroke
203                        if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
204                                stroke = {color: stroke};
205                        }
206                        var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
207                        s.color = g.normalizeColor(s.color);
208                        // generate attributes
209                        var rn = this.rawNode;
210                        rn.stroked = true;
211                        rn.strokecolor = s.color.toCss();
212                        rn.strokeweight = s.width + "px";       // TODO: should we assume that the width is always in pixels?
213                        if(rn.stroke) {
214                                rn.stroke.opacity = s.color.a;
215                                rn.stroke.endcap = this._translate(this._capMap, s.cap);
216                                if(typeof s.join == "number") {
217                                        rn.stroke.joinstyle = "miter";
218                                        rn.stroke.miterlimit = s.join;
219                                }else{
220                                        rn.stroke.joinstyle = s.join;
221                                        // rn.stroke.miterlimit = s.width;
222                                }
223                                rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
224                        }
225                        return this;    // self
226                },
227
228                _capMap: { butt: 'flat' },
229                _capMapReversed: { flat: 'butt' },
230
231                _translate: function(dict, value) {
232                        return (value in dict) ? dict[value] : value;
233                },
234
235                _applyTransform: function() {
236                        var matrix = this._getRealMatrix();
237                        if(matrix){
238                                var skew = this.rawNode.skew;
239                                if(typeof skew == "undefined"){
240                                        for(var i = 0; i < this.rawNode.childNodes.length; ++i){
241                                                if(this.rawNode.childNodes[i].tagName == "skew"){
242                                                        skew = this.rawNode.childNodes[i];
243                                                        break;
244                                                }
245                                        }
246                                }
247                                if(skew){
248                                        skew.on = "f";
249                                        var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8) + " " +
250                                                matrix.yx.toFixed(8) + " " + matrix.yy.toFixed(8) + " 0 0",
251                                                offset = Math.floor(matrix.dx).toFixed() + "px " + Math.floor(matrix.dy).toFixed() + "px",
252                                                s = this.rawNode.style,
253                                                l = parseFloat(s.left),
254                                                t = parseFloat(s.top),
255                                                w = parseFloat(s.width),
256                                                h = parseFloat(s.height);
257                                        if(isNaN(l)) l = 0;
258                                        if(isNaN(t)) t = 0;
259                                        if(isNaN(w) || !w) w = 1;
260                                        if(isNaN(h) || !h) h = 1;
261                                        var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
262                                        skew.matrix =  mt;
263                                        skew.origin = origin;
264                                        skew.offset = offset;
265                                        skew.on = true;
266                                }
267                        }
268                        if(this.fillStyle && this.fillStyle.type == "linear"){
269                                this.setFill(this.fillStyle);
270                        }
271                        return this;
272                },
273
274                _setDimensions: function(width, height){
275                        // summary: sets the width and height of the rawNode,
276                        //      if the surface sixe has been changed
277                        // width: String: width in pixels
278                        // height: String: height in pixels
279
280                        // default implementation does nothing
281                        return this; // self
282                },
283
284                setRawNode: function(rawNode){
285                        // summary:
286                        //      assigns and clears the underlying node that will represent this
287                        //      shape. Once set, transforms, gradients, etc, can be applied.
288                        //      (no fill & stroke by default)
289                        rawNode.stroked = "f";
290                        rawNode.filled  = "f";
291                        this.rawNode = rawNode;
292                        this.rawNode.__gfxObject__ = this.getUID();
293                },
294
295                // move family
296
297                _moveToFront: function(){
298                        // summary: moves a shape to front of its parent's list of shapes (VML)
299                        this.rawNode.parentNode.appendChild(this.rawNode);
300                        return this;
301                },
302                _moveToBack: function(){
303                        // summary: moves a shape to back of its parent's list of shapes (VML)
304                        var r = this.rawNode, p = r.parentNode, n = p.firstChild;
305                        p.insertBefore(r, n);
306                        if(n.tagName == "rect"){
307                                // surface has a background rectangle, which position should be preserved
308                                n.swapNode(r);
309                        }
310                        return this;
311                },
312
313                _getRealMatrix: function(){
314                        // summary: returns the cumulative ("real") transformation matrix
315                        //      by combining the shape's matrix with its parent's matrix
316                        return this.parentMatrix ? new m.Matrix2D([this.parentMatrix, this.matrix]) : this.matrix;      // dojox.gfx.Matrix2D
317                }
318        });
319
320        declare("dojox.gfx.vml.Group", vml.Shape, {
321                // summary: a group shape (VML), which can be used
322                //      to logically group shapes (e.g, to propagate matricies)
323                constructor: function(){
324                        gs.Container._init.call(this);
325                },
326                // apply transformation
327                _applyTransform: function(){
328                        // summary: applies a transformation matrix to a group
329                        var matrix = this._getRealMatrix();
330                        for(var i = 0; i < this.children.length; ++i){
331                                this.children[i]._updateParentMatrix(matrix);
332                        }
333                        return this;    // self
334                },
335                _setDimensions: function(width, height){
336                        // summary: sets the width and height of the rawNode,
337                        //      if the surface sixe has been changed
338                        // width: String: width in pixels
339                        // height: String: height in pixels
340                        var r = this.rawNode, rs = r.style,
341                                bs = this.bgNode.style;
342                        rs.width = width;
343                        rs.height = height;
344                        r.coordsize = width + " " + height;
345                        bs.width = width;
346                        bs.height = height;
347                        for(var i = 0; i < this.children.length; ++i){
348                                this.children[i]._setDimensions(width, height);
349                        }
350                        return this; // self
351                }
352        });
353        vml.Group.nodeType = "group";
354
355        declare("dojox.gfx.vml.Rect", [vml.Shape, gs.Rect], {
356                // summary: a rectangle shape (VML)
357                setShape: function(newShape){
358                        // summary: sets a rectangle shape object (VML)
359                        // newShape: Object: a rectangle shape object
360                        var shape = this.shape = g.makeParameters(this.shape, newShape);
361                        this.bbox = null;
362                        var r = Math.min(1, (shape.r / Math.min(parseFloat(shape.width), parseFloat(shape.height)))).toFixed(8);
363                        // a workaround for the VML's arcsize bug: cannot read arcsize of an instantiated node
364                        var parent = this.rawNode.parentNode, before = null;
365                        if(parent){
366                                if(parent.lastChild !== this.rawNode){
367                                        for(var i = 0; i < parent.childNodes.length; ++i){
368                                                if(parent.childNodes[i] === this.rawNode){
369                                                        before = parent.childNodes[i + 1];
370                                                        break;
371                                                }
372                                        }
373                                }
374                                parent.removeChild(this.rawNode);
375                        }
376                        if(has("ie") > 7){
377                                var node = this.rawNode.ownerDocument.createElement("v:roundrect");
378                                node.arcsize = r;
379                                node.style.display = "inline-block";
380                                this.rawNode = node;
381                                this.rawNode.__gfxObject__ = this.getUID();                                             
382                        }else{
383                                this.rawNode.arcsize = r;
384                        }
385                        if(parent){
386                                if(before){
387                                        parent.insertBefore(this.rawNode, before);
388                                }else{
389                                        parent.appendChild(this.rawNode);
390                                }
391                        }
392                        var style = this.rawNode.style;
393                        style.left   = shape.x.toFixed();
394                        style.top    = shape.y.toFixed();
395                        style.width  = (typeof shape.width == "string" && shape.width.indexOf("%") >= 0)  ? shape.width  : Math.max(shape.width.toFixed(),0);
396                        style.height = (typeof shape.height == "string" && shape.height.indexOf("%") >= 0) ? shape.height : Math.max(shape.height.toFixed(),0);
397                        // set all necessary styles, which are lost by VML (yes, it's a VML's bug)
398                        return this.setTransform(this.matrix).setFill(this.fillStyle).setStroke(this.strokeStyle);      // self
399                }
400        });
401        vml.Rect.nodeType = "roundrect"; // use a roundrect so the stroke join type is respected
402
403        declare("dojox.gfx.vml.Ellipse", [vml.Shape, gs.Ellipse], {
404                // summary: an ellipse shape (VML)
405                setShape: function(newShape){
406                        // summary: sets an ellipse shape object (VML)
407                        // newShape: Object: an ellipse shape object
408                        var shape = this.shape = g.makeParameters(this.shape, newShape);
409                        this.bbox = null;
410                        var style = this.rawNode.style;
411                        style.left   = (shape.cx - shape.rx).toFixed();
412                        style.top    = (shape.cy - shape.ry).toFixed();
413                        style.width  = (shape.rx * 2).toFixed();
414                        style.height = (shape.ry * 2).toFixed();
415                        return this.setTransform(this.matrix);  // self
416                }
417        });
418        vml.Ellipse.nodeType = "oval";
419
420        declare("dojox.gfx.vml.Circle", [vml.Shape, gs.Circle], {
421                // summary: a circle shape (VML)
422                setShape: function(newShape){
423                        // summary: sets a circle shape object (VML)
424                        // newShape: Object: a circle shape object
425                        var shape = this.shape = g.makeParameters(this.shape, newShape);
426                        this.bbox = null;
427                        var style = this.rawNode.style;
428                        style.left   = (shape.cx - shape.r).toFixed();
429                        style.top    = (shape.cy - shape.r).toFixed();
430                        style.width  = (shape.r * 2).toFixed();
431                        style.height = (shape.r * 2).toFixed();
432                        return this;    // self
433                }
434        });
435        vml.Circle.nodeType = "oval";
436
437        declare("dojox.gfx.vml.Line", [vml.Shape, gs.Line], {
438                // summary: a line shape (VML)
439                constructor: function(rawNode){
440                        if(rawNode) rawNode.setAttribute("dojoGfxType", "line");
441                },
442                setShape: function(newShape){
443                        // summary: sets a line shape object (VML)
444                        // newShape: Object: a line shape object
445                        var shape = this.shape = g.makeParameters(this.shape, newShape);
446                        this.bbox = null;
447                        this.rawNode.path.v = "m" + shape.x1.toFixed() + " " + shape.y1.toFixed() +
448                                "l" + shape.x2.toFixed() + " " + shape.y2.toFixed() + "e";
449                        return this.setTransform(this.matrix);  // self
450                }
451        });
452        vml.Line.nodeType = "shape";
453
454        declare("dojox.gfx.vml.Polyline", [vml.Shape, gs.Polyline], {
455                // summary: a polyline/polygon shape (VML)
456                constructor: function(rawNode){
457                        if(rawNode) rawNode.setAttribute("dojoGfxType", "polyline");
458                },
459                setShape: function(points, closed){
460                        // summary: sets a polyline/polygon shape object (VML)
461                        // points: Object: a polyline/polygon shape object
462                        // closed: Boolean?: if true, close the polyline explicitely
463                        if(points && points instanceof Array){
464                                // branch
465                                // points: Array: an array of points
466                                this.shape = g.makeParameters(this.shape, { points: points });
467                                if(closed && this.shape.points.length) this.shape.points.push(this.shape.points[0]);
468                        }else{
469                                this.shape = g.makeParameters(this.shape, points);
470                        }
471                        this.bbox = null;
472                        this._normalizePoints();
473                        var attr = [], p = this.shape.points;
474                        if(p.length > 0){
475                                attr.push("m");
476                                attr.push(p[0].x.toFixed(), p[0].y.toFixed());
477                                if(p.length > 1){
478                                        attr.push("l");
479                                        for(var i = 1; i < p.length; ++i){
480                                                attr.push(p[i].x.toFixed(), p[i].y.toFixed());
481                                        }
482                                }
483                        }
484                        attr.push("e");
485                        this.rawNode.path.v = attr.join(" ");
486                        return this.setTransform(this.matrix);  // self
487                }
488        });
489        vml.Polyline.nodeType = "shape";
490
491        declare("dojox.gfx.vml.Image", [vml.Shape, gs.Image], {
492                // summary: an image (VML)
493                setShape: function(newShape){
494                        // summary: sets an image shape object (VML)
495                        // newShape: Object: an image shape object
496                        var shape = this.shape = g.makeParameters(this.shape, newShape);
497                        this.bbox = null;
498                        this.rawNode.firstChild.src = shape.src;
499                        return this.setTransform(this.matrix);  // self
500                },
501                _applyTransform: function() {
502                        var matrix = this._getRealMatrix(),
503                                rawNode = this.rawNode,
504                                s = rawNode.style,
505                                shape = this.shape;
506                        if(matrix){
507                                matrix = m.multiply(matrix, {dx: shape.x, dy: shape.y});
508                        }else{
509                                matrix = m.normalize({dx: shape.x, dy: shape.y});
510                        }
511                        if(matrix.xy == 0 && matrix.yx == 0 && matrix.xx > 0 && matrix.yy > 0){
512                                // special case to avoid filters
513                                s.filter = "";
514                                s.width  = Math.floor(matrix.xx * shape.width);
515                                s.height = Math.floor(matrix.yy * shape.height);
516                                s.left   = Math.floor(matrix.dx);
517                                s.top    = Math.floor(matrix.dy);
518                        }else{
519                                var ps = rawNode.parentNode.style;
520                                s.left   = "0px";
521                                s.top    = "0px";
522                                s.width  = ps.width;
523                                s.height = ps.height;
524                                matrix = m.multiply(matrix,
525                                        {xx: shape.width / parseInt(s.width), yy: shape.height / parseInt(s.height)});
526                                var f = rawNode.filters["DXImageTransform.Microsoft.Matrix"];
527                                if(f){
528                                        f.M11 = matrix.xx;
529                                        f.M12 = matrix.xy;
530                                        f.M21 = matrix.yx;
531                                        f.M22 = matrix.yy;
532                                        f.Dx = matrix.dx;
533                                        f.Dy = matrix.dy;
534                                }else{
535                                        s.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=" + matrix.xx +
536                                                ", M12=" + matrix.xy + ", M21=" + matrix.yx + ", M22=" + matrix.yy +
537                                                ", Dx=" + matrix.dx + ", Dy=" + matrix.dy + ")";
538                                }
539                        }
540                        return this; // self
541                },
542                _setDimensions: function(width, height){
543                        // summary: sets the width and height of the rawNode,
544                        //      if the surface sixe has been changed
545                        // width: String: width in pixels
546                        // height: String: height in pixels
547
548                        var r = this.rawNode, f = r.filters["DXImageTransform.Microsoft.Matrix"];
549                        if(f){
550                                var s = r.style;
551                                s.width  = width;
552                                s.height = height;
553                                return this._applyTransform(); // self
554                        }
555                        return this;    // self
556                }
557        });
558        vml.Image.nodeType = "rect";
559
560        declare("dojox.gfx.vml.Text", [vml.Shape, gs.Text], {
561                // summary: an anchored text (VML)
562                constructor: function(rawNode){
563                        if(rawNode){rawNode.setAttribute("dojoGfxType", "text");}
564                        this.fontStyle = null;
565                },
566                _alignment: {start: "left", middle: "center", end: "right"},
567                setShape: function(newShape){
568                        // summary: sets a text shape object (VML)
569                        // newShape: Object: a text shape object
570                        this.shape = g.makeParameters(this.shape, newShape);
571                        this.bbox = null;
572                        var r = this.rawNode, s = this.shape, x = s.x, y = s.y.toFixed(), path;
573                        switch(s.align){
574                                case "middle":
575                                        x -= 5;
576                                        break;
577                                case "end":
578                                        x -= 10;
579                                        break;
580                        }
581                        path = "m" + x.toFixed() + "," + y + "l" + (x + 10).toFixed() + "," + y + "e";
582                        // find path and text path
583                        var p = null, t = null, c = r.childNodes;
584                        for(var i = 0; i < c.length; ++i){
585                                var tag = c[i].tagName;
586                                if(tag == "path"){
587                                        p = c[i];
588                                        if(t) break;
589                                }else if(tag == "textpath"){
590                                        t = c[i];
591                                        if(p) break;
592                                }
593                        }
594                        if(!p){
595                                p = r.ownerDocument.createElement("v:path");
596                                r.appendChild(p);
597                        }
598                        if(!t){
599                                t = r.ownerDocument.createElement("v:textpath");
600                                r.appendChild(t);
601                        }
602                        p.v = path;
603                        p.textPathOk = true;
604                        t.on = true;
605                        var a = vml.text_alignment[s.align];
606                        t.style["v-text-align"] = a ? a : "left";
607                        t.style["text-decoration"] = s.decoration;
608                        t.style["v-rotate-letters"] = s.rotated;
609                        t.style["v-text-kern"] = s.kerning;
610                        t.string = s.text;
611                        return this.setTransform(this.matrix);  // self
612                },
613                _setFont: function(){
614                        // summary: sets a font object (VML)
615                        var f = this.fontStyle, c = this.rawNode.childNodes;
616                        for(var i = 0; i < c.length; ++i){
617                                if(c[i].tagName == "textpath"){
618                                        c[i].style.font = g.makeFontString(f);
619                                        break;
620                                }
621                        }
622                        this.setTransform(this.matrix);
623                },
624                _getRealMatrix: function(){
625                        // summary: returns the cumulative ("real") transformation matrix
626                        //      by combining the shape's matrix with its parent's matrix;
627                        //      it makes a correction for a font size
628                        var matrix = this.inherited(arguments);
629                        // It appears that text is always aligned vertically at a middle of x-height (???).
630                        // It is impossible to obtain these metrics from VML => I try to approximate it with
631                        // more-or-less util value of 0.7 * FontSize, which is typical for European fonts.
632                        if(matrix){
633                                matrix = m.multiply(matrix,
634                                        {dy: -g.normalizedLength(this.fontStyle ? this.fontStyle.size : "10pt") * 0.35});
635                        }
636                        return matrix;  // dojox.gfx.Matrix2D
637                },
638                getTextWidth: function(){
639                        // summary: get the text width, in px
640                        var rawNode = this.rawNode, _display = rawNode.style.display;
641                        rawNode.style.display = "inline";
642                        var _width = g.pt2px(parseFloat(rawNode.currentStyle.width));
643                        rawNode.style.display = _display;
644                        return _width;
645                }
646        });
647        vml.Text.nodeType = "shape";
648
649        declare("dojox.gfx.vml.Path", [vml.Shape, pathLib.Path], {
650                // summary: a path shape (VML)
651                constructor: function(rawNode){
652                        if(rawNode && !rawNode.getAttribute("dojoGfxType")){
653                                rawNode.setAttribute("dojoGfxType", "path");
654                        }
655                        this.vmlPath = "";
656                        this.lastControl = {};
657                },
658                _updateWithSegment: function(segment){
659                        // summary: updates the bounding box of path with new segment
660                        // segment: Object: a segment
661                        var last = lang.clone(this.last);
662                        this.inherited(arguments);
663                        if(arguments.length > 1){ return; } // skip transfomed bbox calculations
664                        // add a VML path segment
665                        var path = this[this.renderers[segment.action]](segment, last);
666                        if(typeof this.vmlPath == "string"){
667                                this.vmlPath += path.join("");
668                                this.rawNode.path.v = this.vmlPath + " r0,0 e";
669                        }else{
670                                Array.prototype.push.apply(this.vmlPath, path); //FIXME: why not push()?
671                        }
672                },
673                setShape: function(newShape){
674                        // summary: forms a path using a shape (VML)
675                        // newShape: Object: an VML path string or a path object (see dojox.gfx.defaultPath)
676                        this.vmlPath = [];
677                        this.lastControl.type = "";     // no prior control point
678                        this.inherited(arguments);
679                        this.vmlPath = this.vmlPath.join("");
680                        this.rawNode.path.v = this.vmlPath + " r0,0 e";
681                        return this;
682                },
683                _pathVmlToSvgMap: {m: "M", l: "L", t: "m", r: "l", c: "C", v: "c", qb: "Q", x: "z", e: ""},
684                // VML-specific segment renderers
685                renderers: {
686                        M: "_moveToA", m: "_moveToR",
687                        L: "_lineToA", l: "_lineToR",
688                        H: "_hLineToA", h: "_hLineToR",
689                        V: "_vLineToA", v: "_vLineToR",
690                        C: "_curveToA", c: "_curveToR",
691                        S: "_smoothCurveToA", s: "_smoothCurveToR",
692                        Q: "_qCurveToA", q: "_qCurveToR",
693                        T: "_qSmoothCurveToA", t: "_qSmoothCurveToR",
694                        A: "_arcTo", a: "_arcTo",
695                        Z: "_closePath", z: "_closePath"
696                },
697                _addArgs: function(path, segment, from, upto){
698                        var n = segment instanceof Array ? segment : segment.args;
699                        for(var i = from; i < upto; ++i){
700                                path.push(" ", n[i].toFixed());
701                        }
702                },
703                _adjustRelCrd: function(last, segment, step){
704                        var n = segment instanceof Array ? segment : segment.args, l = n.length,
705                                result = new Array(l), i = 0, x = last.x, y = last.y;
706                        if(typeof x != "number"){
707                                // there is no last coordinate =>
708                                // treat the first pair as an absolute coordinate
709                                result[0] = x = n[0];
710                                result[1] = y = n[1];
711                                i = 2;
712                        }
713                        if(typeof step == "number" && step != 2){
714                                var j = step;
715                                while(j <= l){
716                                        for(; i < j; i += 2){
717                                                result[i] = x + n[i];
718                                                result[i + 1] = y + n[i + 1];
719                                        }
720                                        x = result[j - 2];
721                                        y = result[j - 1];
722                                        j += step;
723                                }
724                        }else{
725                                for(; i < l; i += 2){
726                                        result[i] = (x += n[i]);
727                                        result[i + 1] = (y += n[i + 1]);
728                                }
729                        }
730                        return result;
731                },
732                _adjustRelPos: function(last, segment){
733                        var n = segment instanceof Array ? segment : segment.args, l = n.length,
734                                result = new Array(l);
735                        for(var i = 0; i < l; ++i){
736                                result[i] = (last += n[i]);
737                        }
738                        return result;
739                },
740                _moveToA: function(segment){
741                        var p = [" m"], n = segment instanceof Array ? segment : segment.args, l = n.length;
742                        this._addArgs(p, n, 0, 2);
743                        if(l > 2){
744                                p.push(" l");
745                                this._addArgs(p, n, 2, l);
746                        }
747                        this.lastControl.type = "";     // no control point after this primitive
748                        return p;
749                },
750                _moveToR: function(segment, last){
751                        return this._moveToA(this._adjustRelCrd(last, segment));
752                },
753                _lineToA: function(segment){
754                        var p = [" l"], n = segment instanceof Array ? segment : segment.args;
755                        this._addArgs(p, n, 0, n.length);
756                        this.lastControl.type = "";     // no control point after this primitive
757                        return p;
758                },
759                _lineToR: function(segment, last){
760                        return this._lineToA(this._adjustRelCrd(last, segment));
761                },
762                _hLineToA: function(segment, last){
763                        var p = [" l"], y = " " + last.y.toFixed(),
764                                n = segment instanceof Array ? segment : segment.args, l = n.length;
765                        for(var i = 0; i < l; ++i){
766                                p.push(" ", n[i].toFixed(), y);
767                        }
768                        this.lastControl.type = "";     // no control point after this primitive
769                        return p;
770                },
771                _hLineToR: function(segment, last){
772                        return this._hLineToA(this._adjustRelPos(last.x, segment), last);
773                },
774                _vLineToA: function(segment, last){
775                        var p = [" l"], x = " " + last.x.toFixed(),
776                                n = segment instanceof Array ? segment : segment.args, l = n.length;
777                        for(var i = 0; i < l; ++i){
778                                p.push(x, " ", n[i].toFixed());
779                        }
780                        this.lastControl.type = "";     // no control point after this primitive
781                        return p;
782                },
783                _vLineToR: function(segment, last){
784                        return this._vLineToA(this._adjustRelPos(last.y, segment), last);
785                },
786                _curveToA: function(segment){
787                        var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
788                                lc = this.lastControl;
789                        for(var i = 0; i < l; i += 6){
790                                p.push(" c");
791                                this._addArgs(p, n, i, i + 6);
792                        }
793                        lc.x = n[l - 4];
794                        lc.y = n[l - 3];
795                        lc.type = "C";
796                        return p;
797                },
798                _curveToR: function(segment, last){
799                        return this._curveToA(this._adjustRelCrd(last, segment, 6));
800                },
801                _smoothCurveToA: function(segment, last){
802                        var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
803                                lc = this.lastControl, i = 0;
804                        if(lc.type != "C"){
805                                p.push(" c");
806                                this._addArgs(p, [last.x, last.y], 0, 2);
807                                this._addArgs(p, n, 0, 4);
808                                lc.x = n[0];
809                                lc.y = n[1];
810                                lc.type = "C";
811                                i = 4;
812                        }
813                        for(; i < l; i += 4){
814                                p.push(" c");
815                                this._addArgs(p, [
816                                        2 * last.x - lc.x,
817                                        2 * last.y - lc.y
818                                ], 0, 2);
819                                this._addArgs(p, n, i, i + 4);
820                                lc.x = n[i];
821                                lc.y = n[i + 1];
822                        }
823                        return p;
824                },
825                _smoothCurveToR: function(segment, last){
826                        return this._smoothCurveToA(this._adjustRelCrd(last, segment, 4), last);
827                },
828                _qCurveToA: function(segment){
829                        var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
830                                lc = this.lastControl;
831                        for(var i = 0; i < l; i += 4){
832                                p.push(" qb");
833                                this._addArgs(p, n, i, i + 4);
834                        }
835                        lc.x = n[l - 4];
836                        lc.y = n[l - 3];
837                        lc.type = "Q";
838                        return p;
839                },
840                _qCurveToR: function(segment, last){
841                        return this._qCurveToA(this._adjustRelCrd(last, segment, 4));
842                },
843                _qSmoothCurveToA: function(segment, last){
844                        var p = [], n = segment instanceof Array ? segment : segment.args, l = n.length,
845                                lc = this.lastControl, i = 0;
846                        if(lc.type != "Q"){
847                                p.push(" qb");
848                                this._addArgs(p, [
849                                        lc.x = last.x,
850                                        lc.y = last.y
851                                ], 0, 2);
852                                lc.type = "Q";
853                                this._addArgs(p, n, 0, 2);
854                                i = 2;
855                        }
856                        for(; i < l; i += 2){
857                                p.push(" qb");
858                                this._addArgs(p, [
859                                        lc.x = 2 * last.x - lc.x,
860                                        lc.y = 2 * last.y - lc.y
861                                ], 0, 2);
862                                this._addArgs(p, n, i, i + 2);
863                        }
864                        return p;
865                },
866                _qSmoothCurveToR: function(segment, last){
867                        return this._qSmoothCurveToA(this._adjustRelCrd(last, segment, 2), last);
868                },
869                _arcTo: function(segment, last){
870                        var p = [], n = segment.args, l = n.length, relative = segment.action == "a";
871                        for(var i = 0; i < l; i += 7){
872                                var x1 = n[i + 5], y1 = n[i + 6];
873                                if(relative){
874                                        x1 += last.x;
875                                        y1 += last.y;
876                                }
877                                var result = arcLib.arcAsBezier(
878                                        last, n[i], n[i + 1], n[i + 2],
879                                        n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0,
880                                        x1, y1
881                                );
882                                for(var j = 0; j < result.length; ++j){
883                                        p.push(" c");
884                                        var t = result[j];
885                                        this._addArgs(p, t, 0, t.length);
886                                        this._updateBBox(t[0], t[1]);
887                                        this._updateBBox(t[2], t[3]);
888                                        this._updateBBox(t[4], t[5]);
889                                }
890                                last.x = x1;
891                                last.y = y1;
892                        }
893                        this.lastControl.type = "";     // no control point after this primitive
894                        return p;
895                },
896                _closePath: function(){
897                        this.lastControl.type = "";     // no control point after this primitive
898                        return ["x"];
899                }
900        });
901        vml.Path.nodeType = "shape";
902
903        declare("dojox.gfx.vml.TextPath", [vml.Path, pathLib.TextPath], {
904                // summary: a textpath shape (VML)
905                constructor: function(rawNode){
906                        if(rawNode){rawNode.setAttribute("dojoGfxType", "textpath");}
907                        this.fontStyle = null;
908                        if(!("text" in this)){
909                                this.text = lang.clone(g.defaultTextPath);
910                        }
911                        if(!("fontStyle" in this)){
912                                this.fontStyle = lang.clone(g.defaultFont);
913                        }
914                },
915                setText: function(newText){
916                        // summary: sets a text to be drawn along the path
917                        this.text = g.makeParameters(this.text,
918                                typeof newText == "string" ? {text: newText} : newText);
919                        this._setText();
920                        return this;    // self
921                },
922                setFont: function(newFont){
923                        // summary: sets a font for text
924                        this.fontStyle = typeof newFont == "string" ?
925                                g.splitFontString(newFont) :
926                                g.makeParameters(g.defaultFont, newFont);
927                        this._setFont();
928                        return this;    // self
929                },
930
931                _setText: function(){
932                        // summary: sets a text shape object (VML)
933                        this.bbox = null;
934                        var r = this.rawNode, s = this.text,
935                                // find path and text path
936                                p = null, t = null, c = r.childNodes;
937                        for(var i = 0; i < c.length; ++i){
938                                var tag = c[i].tagName;
939                                if(tag == "path"){
940                                        p = c[i];
941                                        if(t) break;
942                                }else if(tag == "textpath"){
943                                        t = c[i];
944                                        if(p) break;
945                                }
946                        }
947                        if(!p){
948                                p = this.rawNode.ownerDocument.createElement("v:path");
949                                r.appendChild(p);
950                        }
951                        if(!t){
952                                t = this.rawNode.ownerDocument.createElement("v:textpath");
953                                r.appendChild(t);
954                        }
955                        p.textPathOk = true;
956                        t.on = true;
957                        var a = vml.text_alignment[s.align];
958                        t.style["v-text-align"] = a ? a : "left";
959                        t.style["text-decoration"] = s.decoration;
960                        t.style["v-rotate-letters"] = s.rotated;
961                        t.style["v-text-kern"] = s.kerning;
962                        t.string = s.text;
963                },
964                _setFont: function(){
965                        // summary: sets a font object (VML)
966                        var f = this.fontStyle, c = this.rawNode.childNodes;
967                        for(var i = 0; i < c.length; ++i){
968                                if(c[i].tagName == "textpath"){
969                                        c[i].style.font = g.makeFontString(f);
970                                        break;
971                                }
972                        }
973                }
974        });
975        vml.TextPath.nodeType = "shape";
976
977        declare("dojox.gfx.vml.Surface", gs.Surface, {
978                // summary: a surface object to be used for drawings (VML)
979                constructor: function(){
980                        gs.Container._init.call(this);
981                },
982                setDimensions: function(width, height){
983                        // summary: sets the width and height of the rawNode
984                        // width: String: width of surface, e.g., "100px"
985                        // height: String: height of surface, e.g., "100px"
986                        this.width  = g.normalizedLength(width);        // in pixels
987                        this.height = g.normalizedLength(height);       // in pixels
988                        if(!this.rawNode) return this;
989                        var cs = this.clipNode.style,
990                                r = this.rawNode, rs = r.style,
991                                bs = this.bgNode.style,
992                                ps = this._parent.style, i;
993                        ps.width = width;
994                        ps.height = height;
995                        cs.width  = width;
996                        cs.height = height;
997                        cs.clip = "rect(0px " + width + "px " + height + "px 0px)";
998                        rs.width = width;
999                        rs.height = height;
1000                        r.coordsize = width + " " + height;
1001                        bs.width = width;
1002                        bs.height = height;
1003                        for(i = 0; i < this.children.length; ++i){
1004                                this.children[i]._setDimensions(width, height);
1005                        }
1006                        return this;    // self
1007                },
1008                getDimensions: function(){
1009                        // summary: returns an object with properties "width" and "height"
1010                        var t = this.rawNode ? {
1011                                width:  g.normalizedLength(this.rawNode.style.width),
1012                                height: g.normalizedLength(this.rawNode.style.height)} : null;
1013                        if(t.width  <= 0){ t.width  = this.width; }
1014                        if(t.height <= 0){ t.height = this.height; }
1015                        return t;       // Object
1016                }
1017        });
1018
1019        vml.createSurface = function(parentNode, width, height){
1020                // summary: creates a surface (VML)
1021                // parentNode: Node: a parent node
1022                // width: String: width of surface, e.g., "100px"
1023                // height: String: height of surface, e.g., "100px"
1024
1025                if(!width && !height){
1026                        var pos = domGeom.position(parentNode);
1027                        width  = width  || pos.w;
1028                        height = height || pos.h;
1029                }
1030                if(typeof width == "number"){
1031                        width = width + "px";
1032                }
1033                if(typeof height == "number"){
1034                        height = height + "px";
1035                }
1036
1037                var s = new vml.Surface(), p = dom.byId(parentNode),
1038                        c = s.clipNode = p.ownerDocument.createElement("div"),
1039                        r = s.rawNode = p.ownerDocument.createElement("v:group"),
1040                        cs = c.style, rs = r.style;
1041
1042                if(has("ie") > 7){
1043                        rs.display = "inline-block";
1044                }
1045
1046                s._parent = p;
1047                s._nodes.push(c);       // other elements will be deleted as parts of "c"
1048
1049                p.style.width  = width;
1050                p.style.height = height;
1051
1052                cs.position = "absolute";
1053                cs.width  = width;
1054                cs.height = height;
1055                cs.clip = "rect(0px " + width + " " + height + " 0px)";
1056                rs.position = "absolute";
1057                rs.width  = width;
1058                rs.height = height;
1059                r.coordsize = (width === "100%" ? width : parseFloat(width)) + " " +
1060                        (height === "100%" ? height : parseFloat(height));
1061                r.coordorigin = "0 0";
1062
1063                // create a background rectangle, which is required to show all other shapes
1064                var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style;
1065                bs.left = bs.top = 0;
1066                bs.width  = rs.width;
1067                bs.height = rs.height;
1068                b.filled = b.stroked = "f";
1069
1070                r.appendChild(b);
1071                c.appendChild(r);
1072                p.appendChild(c);
1073
1074                s.width  = g.normalizedLength(width);   // in pixels
1075                s.height = g.normalizedLength(height);  // in pixels
1076
1077                return s;       // dojox.gfx.Surface
1078        };
1079
1080        // Extenders
1081       
1082        // copied from dojox.gfx.utils
1083        function forEach(object, f, o){
1084                o = o || win.global;
1085                f.call(o, object);
1086                if(object instanceof g.Surface || object instanceof g.Group){
1087                        arr.forEach(object.children, function(shape){
1088                                forEach(shape, f, o);
1089                        });
1090                }
1091        }
1092
1093        var addPatch9624 = function(shape){
1094                if(this != shape.getParent()){
1095                        // cleanup from old parent
1096                        var oldParent = shape.getParent();
1097                        if(oldParent) { oldParent.remove(shape); }
1098                        // then move the raw node
1099                        this.rawNode.appendChild(shape.rawNode);
1100                        C.add.apply(this, arguments);
1101                        // reapply visual attributes (slow..)
1102                        forEach(this, function(s){
1103                                if (typeof(s.getFont) == 'function'){ // text shapes need to be completely refreshed
1104                                        s.setShape(s.getShape());
1105                                        s.setFont(s.getFont());
1106                                }
1107                                if (typeof(s.setFill) == 'function'){ // if setFill is available a setStroke should be safe to assume also
1108                                        s.setFill(s.getFill());
1109                                        s.setStroke(s.getStroke());
1110                                }
1111                        });
1112                }
1113                return this;    // self
1114        };
1115       
1116        var add15 = function(shape){
1117                if(this != shape.getParent()){
1118                        this.rawNode.appendChild(shape.rawNode);
1119                        if(!shape.getParent()){
1120                                // reapply visual attributes
1121                                shape.setFill(shape.getFill());
1122                                shape.setStroke(shape.getStroke());
1123                        }
1124                        C.add.apply(this, arguments);
1125                }
1126                return this;    // self
1127        };
1128
1129        var C = gs.Container, Container = {
1130                add: config.fixVmlAdd === true ? addPatch9624 : add15,
1131                remove: function(shape, silently){
1132                        // summary: remove a shape from a group/surface
1133                        // shape: dojox.gfx.Shape: an VML shape object
1134                        // silently: Boolean?: if true, regenerate a picture
1135                        if(this == shape.getParent()){
1136                                if(this.rawNode == shape.rawNode.parentNode){
1137                                        this.rawNode.removeChild(shape.rawNode);
1138                                }
1139                                C.remove.apply(this, arguments);
1140                        }
1141                        return this;    // self
1142                },
1143                clear: function(){
1144                        // summary: removes all shapes from a group/surface
1145                        var r = this.rawNode;
1146                        while(r.firstChild != r.lastChild){
1147                                if(r.firstChild != this.bgNode){
1148                                        r.removeChild(r.firstChild);
1149                                }
1150                                if(r.lastChild != this.bgNode){
1151                                        r.removeChild(r.lastChild);
1152                                }
1153                        }
1154                        return C.clear.apply(this, arguments);
1155                },
1156                _moveChildToFront: C._moveChildToFront,
1157                _moveChildToBack:  C._moveChildToBack
1158        };
1159
1160        var Creator = {
1161                // summary: VML shape creators
1162                createGroup: function(){
1163                        // summary: creates a VML group shape
1164                        var node = this.createObject(vml.Group, null);  // dojox.gfx.Group
1165                        // create a background rectangle, which is required to show all other shapes
1166                        var r = node.rawNode.ownerDocument.createElement("v:rect");
1167                        r.style.left = r.style.top = 0;
1168                        r.style.width  = node.rawNode.style.width;
1169                        r.style.height = node.rawNode.style.height;
1170                        r.filled = r.stroked = "f";
1171                        node.rawNode.appendChild(r);
1172                        node.bgNode = r;
1173                        return node;    // dojox.gfx.Group
1174                },
1175                createImage: function(image){
1176                        // summary: creates a VML image shape
1177                        // image: Object: an image object (see dojox.gfx.defaultImage)
1178                        if(!this.rawNode) return null;
1179                        var shape = new vml.Image(),
1180                                doc = this.rawNode.ownerDocument,
1181                                node = doc.createElement('v:rect');
1182                        node.stroked = "f";
1183                        node.style.width  = this.rawNode.style.width;
1184                        node.style.height = this.rawNode.style.height;
1185                        var img  = doc.createElement('v:imagedata');
1186                        node.appendChild(img);
1187                        shape.setRawNode(node);
1188                        this.rawNode.appendChild(node);
1189                        shape.setShape(image);
1190                        this.add(shape);
1191                        return shape;   // dojox.gfx.Image
1192                },
1193                createRect: function(rect){
1194                        // summary: creates a rectangle shape
1195                        // rect: Object: a path object (see dojox.gfx.defaultRect)
1196                        if(!this.rawNode) return null;
1197                        var shape = new vml.Rect,
1198                                node = this.rawNode.ownerDocument.createElement("v:roundrect");
1199                        if(has("ie") > 7){
1200                                node.style.display = "inline-block";
1201                        }
1202                        shape.setRawNode(node);
1203                        this.rawNode.appendChild(node);
1204                        shape.setShape(rect);
1205                        this.add(shape);
1206                        return shape;   // dojox.gfx.Rect
1207                },
1208                createObject: function(shapeType, rawShape) {
1209                        // summary: creates an instance of the passed shapeType class
1210                        // shapeType: Function: a class constructor to create an instance of
1211                        // rawShape: Object: properties to be passed in to the classes "setShape" method
1212                        // overrideSize: Boolean: set the size explicitly, if true
1213                        if(!this.rawNode) return null;
1214                        var shape = new shapeType(),
1215                                node = this.rawNode.ownerDocument.createElement('v:' + shapeType.nodeType);
1216                        shape.setRawNode(node);
1217                        this.rawNode.appendChild(node);
1218                        switch(shapeType){
1219                                case vml.Group:
1220                                case vml.Line:
1221                                case vml.Polyline:
1222                                case vml.Image:
1223                                case vml.Text:
1224                                case vml.Path:
1225                                case vml.TextPath:
1226                                        this._overrideSize(node);
1227                        }
1228                        shape.setShape(rawShape);
1229                        this.add(shape);
1230                        return shape;   // dojox.gfx.Shape
1231                },
1232                _overrideSize: function(node){
1233                        var s = this.rawNode.style, w = s.width, h = s.height;
1234                        node.style.width  = w;
1235                        node.style.height = h;
1236                        node.coordsize = parseInt(w) + " " + parseInt(h);
1237                }
1238        };
1239
1240        lang.extend(vml.Group, Container);
1241        lang.extend(vml.Group, gs.Creator);
1242        lang.extend(vml.Group, Creator);
1243
1244        lang.extend(vml.Surface, Container);
1245        lang.extend(vml.Surface, gs.Creator);
1246        lang.extend(vml.Surface, Creator);
1247
1248        // Mouse/Touch event
1249        vml.fixTarget = function(event, gfxElement){
1250                // summary:
1251                //     Adds the gfxElement to event.gfxTarget if none exists. This new
1252                //     property will carry the GFX element associated with this event.
1253                // event: Object
1254                //     The current input event (MouseEvent or TouchEvent)
1255                // gfxElement: Object
1256                //     The GFX target element
1257                if (!event.gfxTarget) {
1258                        event.gfxTarget = gs.byId(event.target.__gfxObject__);
1259                }
1260                return true;
1261        };
1262       
1263        return vml;
1264});
Note: See TracBrowser for help on using the repository browser.