/*
	Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
	Available via Academic Free License >= 2.1 OR the modified BSD license.
	see: http://dojotoolkit.org/license for details
*/


if(!dojo._hasResource["dojox.gfx.VectorText"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.gfx.VectorText"] = true;
dojo.provide("dojox.gfx.VectorText");
dojo.require("dojox.gfx");
dojo.require("dojox.xml.DomParser");
dojo.require("dojox.html.metrics");

(function(){
	/*
		dojox.gfx.VectorText
		An implementation of the SVG Font 1.1 spec, using dojox.gfx.

		Basic interface:
		var f = new dojox.gfx.Font(url|string);
		surface||group.createVectorText(text)
			.setFill(fill)
			.setStroke(stroke)
			.setFont(fontStyleObject);

		The arguments passed to createVectorText are the same as you would
		pass to surface||group.createText; the difference is that this
		is entirely renderer-agnostic, and the return value is a subclass
		of dojox.gfx.Group.

		Note also that the "defaultText" object is slightly different:
		{ type:"vectortext", x:0, y:0, width:null, height: null,
			text: "", align: "start", decoration: "none" }

		...as well as the "defaultVectorFont" object:
		{ type:"vectorfont", size:"10pt" }

		The reason for this should be obvious: most of the style for the font is defined
		by the font object itself.

		Note that this will only render IF and WHEN you set the font.
	 */
	dojo.mixin(dojox.gfx, {
		vectorFontFitting: {
			NONE: 0,	//	render text according to passed size.
			FLOW: 1,		//	render text based on the passed width and size
			FIT: 2			//	render text based on a passed viewbox.
		},
		defaultVectorText: {
			type:"vectortext", x:0, y:0, width: null, height: null,
			text: "", align: "start", decoration: "none", fitting: 0,	//	vectorFontFitting.NONE
			leading: 1.5	//	in ems.
		},
		defaultVectorFont: {
			type:"vectorfont", size: "10pt", family: null
		},
		_vectorFontCache: {},
		_svgFontCache: {},
		getVectorFont: function(/* String */url){
			if(dojox.gfx._vectorFontCache[url]){
				return dojox.gfx._vectorFontCache[url];
			}
			return new dojox.gfx.VectorFont(url);
		}
	});

	dojo.declare("dojox.gfx.VectorFont", null, {
		_entityRe: /&(quot|apos|lt|gt|amp|#x[^;]+|#\d+);/g,
		_decodeEntitySequence: function(str){
			//	unescape the unicode sequences

			//	nothing to decode
			if(!str.match(this._entityRe)){ return; }  // undefined
			var xmlEntityMap = {
				amp:"&", apos:"'", quot:'"', lt:"<", gt:">"
			};

			//	we have at least one encoded entity.
			var r, tmp="";
			while((r=this._entityRe.exec(str))!==null){
				if(r[1].charAt(1)=="x"){
					tmp += String.fromCharCode(parseInt(r[1].slice(2), 16));
				}
				else if(!isNaN(parseInt(r[1].slice(1),10))){
					tmp += String.fromCharCode(parseInt(r[1].slice(1), 10));
				}
				else {
					tmp += xmlEntityMap[r[1]] || "";
				}
			}
			return tmp;	//	String
		},
		_parse: function(/* String */svg, /* String */url){
			//	summary:
			//		Take the loaded SVG Font definition file and convert the info
			//		into things we can use. The SVG Font definition must follow
			//		the SVG 1.1 Font specification.
			var doc = dojox.gfx._svgFontCache[url]||dojox.xml.DomParser.parse(svg);

			//	font information
			var f = doc.documentElement.byName("font")[0], face = doc.documentElement.byName("font-face")[0];
			var unitsPerEm = parseFloat(face.getAttribute("units-per-em")||1000, 10);
			var advance = {
				x: parseFloat(f.getAttribute("horiz-adv-x"), 10),
				y: parseFloat(f.getAttribute("vert-adv-y")||0, 10)
			};
			if(!advance.y){
				advance.y = unitsPerEm;
			}

			var origin = {
				horiz: {
					x: parseFloat(f.getAttribute("horiz-origin-x")||0, 10),
					y: parseFloat(f.getAttribute("horiz-origin-y")||0, 10)
				},
				vert: {
					x: parseFloat(f.getAttribute("vert-origin-x")||0, 10),
					y: parseFloat(f.getAttribute("vert-origin-y")||0, 10)
				}
			};

			//	face information
			var family = face.getAttribute("font-family"),
				style = face.getAttribute("font-style")||"all",
				variant = face.getAttribute("font-variant")||"normal",
				weight = face.getAttribute("font-weight")||"all",
				stretch = face.getAttribute("font-stretch")||"normal",

				//	additional info, may not be needed
				range = face.getAttribute("unicode-range")||"U+0-10FFFF",
				panose = face.getAttribute("panose-1") || "0 0 0 0 0 0 0 0 0 0",
				capHeight = face.getAttribute("cap-height"),
				ascent = parseFloat(face.getAttribute("ascent")||(unitsPerEm-origin.vert.y), 10),
				descent = parseFloat(face.getAttribute("descent")||origin.vert.y, 10),
				baseline = {};

			//	check for font-face-src/font-face-name
			var name = family;
			if(face.byName("font-face-name")[0]){
				name = face.byName("font-face-name")[0].getAttribute("name");
			}

			//	see if this is cached already, and if so, forget the rest of the parsing.
			if(dojox.gfx._vectorFontCache[name]){ return; }

			//	get any provided baseline alignment offsets.
			dojo.forEach(["alphabetic", "ideographic", "mathematical", "hanging" ], function(attr){
				var a = face.getAttribute(attr);
				if(a !== null /* be explicit, might be 0 */){
					baseline[attr] = parseFloat(a, 10);
				}
			});

		/*
			//	TODO: decoration hinting.
			var decoration = { };
			dojo.forEach(["underline", "strikethrough", "overline"], function(type){
				if(face.getAttribute(type+"-position")!=null){
					decoration[type]={ };
				}
			});
		*/

			//	missing glyph info
			var missing = parseFloat(doc.documentElement.byName("missing-glyph")[0].getAttribute("horiz-adv-x")||advance.x, 10);

			//	glyph information
			var glyphs = {}, glyphsByName={}, g=doc.documentElement.byName("glyph");
			dojo.forEach(g, function(node){
				//	we are going to assume the following:
				//		1) we have the unicode attribute
				//		2) we have the name attribute
				//		3) we have the horiz-adv-x and d attributes.
				var code = node.getAttribute("unicode"),
					name = node.getAttribute("glyph-name"),
					xAdv = parseFloat(node.getAttribute("horiz-adv-x")||advance.x, 10),
					path = node.getAttribute("d");

				//	unescape the unicode sequences
				if(code.match(this._entityRe)){
					code = this._decodeEntitySequence(code);
				}

				// build our glyph objects
				var o = { code: code, name: name, xAdvance: xAdv, path: path };
				glyphs[code]=o;
				glyphsByName[name]=o;
			}, this);

			//	now the fun part: look for kerning pairs.
			var hkern=doc.documentElement.byName("hkern");
			dojo.forEach(hkern, function(node, i){
				var k = -parseInt(node.getAttribute("k"),10);
				//	look for either a code or a name
				var u1=node.getAttribute("u1"),
					g1=node.getAttribute("g1"),
					u2=node.getAttribute("u2"),
					g2=node.getAttribute("g2"),
					gl;

				if(u1){
					//	the first of the pair is a sequence of unicode characters.
					//	TODO: deal with unicode ranges and mulitple characters.
					u1 = this._decodeEntitySequence(u1);
					if(glyphs[u1]){
						gl = glyphs[u1];
					}
				} else {
					//	we are referring to a name.
					//	TODO: deal with multiple names
					if(glyphsByName[g1]){
						gl = glyphsByName[g1];
					}
				}

				if(gl){
					if(!gl.kern){ gl.kern = {}; }
					if(u2){
						//	see the notes above.
						u2 = this._decodeEntitySequence(u2);
						gl.kern[u2] = { x: k };
					} else {
						if(glyphsByName[g2]){
							gl.kern[glyphsByName[g2].code] = { x: k };
						}
					}
				}
			}, this);

			//	pop the final definition in the font cache.
			dojo.mixin(this, {
				family: family,
				name: name,
				style: style,
				variant: variant,
				weight: weight,
				stretch: stretch,
				range: range,
				viewbox: { width: unitsPerEm, height: unitsPerEm },
				origin: origin,
				advance: dojo.mixin(advance, {
					missing:{ x: missing, y: missing }
				}),
				ascent: ascent,
				descent: descent,
				baseline: baseline,
				glyphs: glyphs
			});

			//	cache the parsed font
			dojox.gfx._vectorFontCache[name] = this;
			dojox.gfx._vectorFontCache[url] = this;
			if(name!=family && !dojox.gfx._vectorFontCache[family]){
				dojox.gfx._vectorFontCache[family] = this;
			}

			//	cache the doc
			if(!dojox.gfx._svgFontCache[url]){
				dojox.gfx._svgFontCache[url]=doc;
			}
		},
		_clean: function(){
			//	summary:
			//		Clean off all of the given mixin parameters.
			var name = this.name, family = this.family;
			dojo.forEach(["family","name","style","variant",
				"weight","stretch","range","viewbox",
				"origin","advance","ascent","descent",
				"baseline","glyphs"], function(prop){
					try{ delete this[prop]; } catch(e) { }
			}, this);

			//	try to pull out of the font cache.
			if(dojox.gfx._vectorFontCache[name]){
				delete dojox.gfx._vectorFontCache[name];
			}
			if(dojox.gfx._vectorFontCache[family]){
				delete dojox.gfx._vectorFontCache[family];
			}
			return this;
		},

		constructor: function(/* String|dojo._Url */url){
			//	summary::
			//		Create this font object based on the SVG Font definition at url.
			this._defaultLeading = 1.5;
			if(url!==undefined){
				this.load(url);
			}
		},
		load: function(/* String|dojo._Url */url){
			//	summary::
			//		Load the passed SVG and send it to the parser for parsing.
			this.onLoadBegin(url.toString());
			this._parse(
				dojox.gfx._svgFontCache[url.toString()]||dojo._getText(url.toString()),
				url.toString()
			);
			this.onLoad(this);
			return this;	//	dojox.gfx.VectorFont
		},
		initialized: function(){
			//	summary::
			//		Return if we've loaded a font def, and the parsing was successful.
			return (this.glyphs!==null);	//	Boolean
		},

		//	preset round to 3 places.
		_round: function(n){ return Math.round(1000*n)/1000; },
		_leading: function(unit){ return this.viewbox.height * (unit||this._defaultLeading); },
		_normalize: function(str){
			return str.replace(/\s+/g, String.fromCharCode(0x20));
		},

		_getWidth: function(glyphs){
			var w=0, last=0, lastGlyph=null;
			dojo.forEach(glyphs, function(glyph, i){
				last=glyph.xAdvance;
				if(glyphs[i] && glyph.kern && glyph.kern[glyphs[i].code]){
					last += glyph.kern[glyphs[i].code].x;
				}
				w += last;
				lastGlyph = glyph;
			});

			//	if the last glyph was a space, pull it off.
			if(lastGlyph && lastGlyph.code == " "){
				w -= lastGlyph.xAdvance;
			}

			return this._round(w/*-last*/);
		},

		_getLongestLine: function(lines){
			var maxw=0, idx=0;
			dojo.forEach(lines, function(line, i){
				var max = Math.max(maxw, this._getWidth(line));
				if(max > maxw){
					maxw = max;
					idx=i;
				}
			}, this);
			return { width: maxw, index: idx, line: lines[idx] };
		},

		_trim: function(lines){
			var fn = function(arr){
				//	check if the first or last character is a space and if so, remove it.
				if(!arr.length){ return; }
				if(arr[arr.length-1].code == " "){ arr.splice(arr.length-1, 1); }
				if(!arr.length){ return; }
				if(arr[0].code == " "){ arr.splice(0, 1); }
			};

			if(dojo.isArray(lines[0])){
				//	more than one line.
				dojo.forEach(lines, fn);
			} else {
				fn(lines);
			}
			return lines;
		},

		_split: function(chars, nLines){
			//	summary:
			//		split passed chars into nLines by finding the closest whitespace.
			var w = this._getWidth(chars),
				limit = Math.floor(w/nLines),
				lines = [],
				cw = 0,
				c = [],
				found = false;

			for(var i=0, l=chars.length; i<l; i++){
				if(chars[i].code == " "){ found = true; }
				cw += chars[i].xAdvance;
				if(i+1<l && chars[i].kern && chars[i].kern[chars[i+1].code]){
					cw += chars[i].kern[chars[i+1].code].x;
				}

				if(cw>=limit){
					var chr=chars[i];
					while(found && chr.code != " " && i>=0){
						chr = c.pop(); i--;
					}
					lines.push(c);
					c=[];
					cw=0;
					found=false;
				}
				c.push(chars[i]);
			}
			if(c.length){ lines.push(c); }
			//	"trim" it
			return this._trim(lines);
		},

		_getSizeFactor: function(size){
			//	given the size, return a scaling factor based on the height of the
			//	font as defined in the font definition file.
			size += "";	//	force the string cast.
			var metrics = dojox.html.metrics.getCachedFontMeasurements(),
				height=this.viewbox.height,
				f=metrics["1em"],
				unit=parseFloat(size, 10);	//	the default.
			if(size.indexOf("em")>-1){
				return this._round((metrics["1em"]*unit)/height);
			}
			else if(size.indexOf("ex")>-1){
				return this._round((metrics["1ex"]*unit)/height);
			}
			else if(size.indexOf("pt")>-1){
				return this._round(((metrics["12pt"] / 12)*unit) / height);
			}
			else if(size.indexOf("px")>-1){
				return this._round(((metrics["16px"] / 16)*unit) / height);
			}
			else if(size.indexOf("%")>-1){
				return this._round((metrics["1em"]*(unit / 100)) / height);
			}
			else {
				f=metrics[size]||metrics.medium;
				return this._round(f/height);
			}
		},

		_getFitFactor: function(lines, w, h, l){
			//	summary:
			//		Find the scaling factor for the given phrase set.
			if(!h){
				//	if no height was passed, we assume an array of glyphs instead of lines.
				return this._round(w/this._getWidth(lines));
			} else {
				var maxw = this._getLongestLine(lines).width,
					maxh = (lines.length*(this.viewbox.height*l))-((this.viewbox.height*l)-this.viewbox.height);
				return this._round(Math.min(w/maxw, h/maxh));
			}
		},
		_getBestFit: function(chars, w, h, ldng){
			//	summary:
			//		Get the best number of lines to return given w and h.
			var limit=32,
				factor=0,
				lines=limit;
			while(limit>0){
				var f=this._getFitFactor(this._split(chars, limit), w, h, ldng);
				if(f>factor){
					factor = f;
					lines=limit;
				}
				limit--;
			}
			return { scale: factor, lines: this._split(chars, lines) };
		},

		_getBestFlow: function(chars, w, scale){
			//	summary:
			//		Based on the given scale, do the best line splitting possible.
			var lines = [],
				cw = 0,
				c = [],
				found = false;
			for(var i=0, l=chars.length; i<l; i++){
				if(chars[i].code == " "){ found = true; }
				var tw = chars[i].xAdvance;
				if(i+1<l && chars[i].kern && chars[i].kern[chars[i+1].code]){
					tw += chars[i].kern[chars[i+1].code].x;
				}
				cw += scale*tw;

				if(cw>=w){
					var chr=chars[i];
					while(found && chr.code != " " && i>=0){
						chr = c.pop(); i--;
					}
					lines.push(c);
					c=[];
					cw=0;
					found=false;
				}
				c.push(chars[i]);
			}
			if(c.length){ lines.push(c); }
			return this._trim(lines);
		},

		//	public functions
		getWidth: function(/* String */text, /* Float? */scale){
			//	summary:
			//		Get the width of the rendered text without actually rendering it.
			return this._getWidth(dojo.map(this._normalize(text).split(""), function(chr){
				return this.glyphs[chr] || { xAdvance: this.advance.missing.x };
			}, this)) * (scale || 1);	//	Float
		},
		getLineHeight: function(/* Float? */scale){
			//	summary:
			//		return the height of a single line, sans leading, based on scale.
			return this.viewbox.height * (scale || 1);	//	Float
		},

		//	A note:
		//		Many SVG exports do not include information such as x-height, caps-height
		//		and other coords that may help alignment.  We can calc the baseline and
		//		we can get a mean line (i.e. center alignment) but that's about all, reliably.
		getCenterline: function(/* Float? */scale){
			//	summary:
			//		return the y coordinate that is the center of the viewbox.
			return (scale||1) * (this.viewbox.height/2);
		},
		getBaseline: function(/* Float? */scale){
			//	summary:
			//		Find the baseline coord for alignment; adjust for scale if passed.
			return (scale||1) * (this.viewbox.height+this.descent);	//	Float
		},

		draw: function(/* dojox.gfx.Container */group, /* dojox.gfx.__TextArgs */textArgs, /* dojox.gfx.__FontArgs */fontArgs, /* dojox.gfx.__FillArgs */fillArgs, /* dojox.gfx.__StrokeArgs? */strokeArgs){
			//	summary:
			//		based on the passed parameters, draw the given text using paths
			//		defined by this font.
			//
			//	description:
			//		The main method of a VectorFont, draw() will take a text fragment
			//		and render it in a set of groups and paths based on the parameters
			//		passed.
			//
			//		The basics of drawing text are simple enough: pass it your text as
			//		part of the textArgs object, pass size and family info as part of
			//		the fontArgs object, pass at least a color as the fillArgs object,
			//		and if you are looking to create an outline, pass the strokeArgs
			//		object as well. fillArgs and strokeArgs are the same as any other
			//		gfx fill and stroke arguments; they are simply applied to any path
			//		object generated by this method.
			//
			//		Resulting GFX structure
			//		-----------------------
			//
			//		The result of this function is a set of gfx objects in the following
			//		structure:
			//
			//	|	dojox.gfx.Group 			//	the parent group generated by this function
			//	|	+	dojox.gfx.Group[]		//	a group generated for each line of text
			//	|		+	dojox.gfx.Path[]	//	each glyph/character in the text
			//
			//		Scaling transformations (i.e. making the generated text the correct size)
			//		are always applied to the parent Group that is generated (i.e. the top
			//		node in the above example).  In theory, if you are looking to do any kind
			//		of other transformations (such as a translation), you should apply it to
			//		the group reference you pass to this method.  If you find that you need
			//		to apply transformations to the group that is returned by this method,
			//		you will need to reapply the scaling transformation as the *last* transform,
			//		like so:
			//
			//	|	textGroup.setTransform(new dojox.gfx.Matrix2D([
			//	|		dojox.gfx.matrix.translate({ dx: dx, dy: dy }),
			//	|		textGroup.getTransform()
			//	|	]));
			//
			//		In general, this should never be necessary unless you are doing advanced
			//		placement of your text.
			//
			//		Advanced Layout Functionality
			//		-----------------------------
			//
			//		In addition to straight text fragments, draw() supports a few advanced
			//		operations not normally available with vector graphics:
			//
			//		* Flow operations (i.e. wrap to a given width)
			//		* Fitting operations (i.e. find a best fit to a given rectangle)
			//
			//		To enable either, pass a `fitting` property along with the textArgs object.
			//		The possible values are contained in the dojox.gfx.vectorFontFitting enum
			//		(NONE, FLOW, FIT).
			//
			//		`Flow fitting`
			//		Flow fitting requires both a passed size (in the fontArgs object) and a
			//		width (passed with the textArgs object).  draw() will attempt to split the
			//		passed text up into lines, at the closest whitespace according to the
			//		passed width.  If a width is missing, it will revert to NONE.
			//
			//		`Best fit fitting`
			//		Doing a "best fit" means taking the passed text, and finding the largest
			//		size and line breaks so that it is the closest fit possible.  With best
			//		fit, any size arguments are ignored; if a height is missing, it will revert
			//		to NONE.
			//
			//		Other notes
			//		-----------
			//
			//		`a11y`
			//		Since the results of this method are rendering using pure paths (think
			//		"convert to outlines" in Adobe Illustrator), any text rendered by this
			//		code is NOT considered a11y-friendly.  If a11y is a requirement, we
			//		suggest using other, more a11y-friendly methods.
			//
			//		`Font sources`
			//		Always make sure that you are legally allowed to use any fonts that you
			//		convert to SVG format; we claim no responsibility for any licensing
			//		infractions that may be caused by the use of this code.
			if(!this.initialized()){
				throw new Error("dojox.gfx.VectorFont.draw(): we have not been initialized yet.");
			}
			//	TODO: BIDI handling.  Deal with layout/alignments based on font parameters.

			//	start by creating the overall group.  This is the INNER group (the caller
			//	should be the outer).
			var g = group.createGroup();

			//	do the x/y translation on the parent group
			//	FIXME: this is probably not the best way of doing this.
			if(textArgs.x || textArgs.y){
				group.applyTransform({ dx: textArgs.x||0, dy: textArgs.y||0 });
			}

			//	go get the glyph array.
			var text = dojo.map(this._normalize(textArgs.text).split(""), function(chr){
				return this.glyphs[chr] || { path:null, xAdvance: this.advance.missing.x };
			}, this);

			//	determine the font style info, ignore decoration.
			var size = fontArgs.size,
				fitting = textArgs.fitting,
				width = textArgs.width,
				height = textArgs.height,
				align = textArgs.align,
				leading = textArgs.leading||this._defaultLeading;

			//	figure out if we have to do fitting at all.
			if(fitting){
				//	more than zero.
				if((fitting==dojox.gfx.vectorFontFitting.FLOW && !width) || (fitting==dojox.gfx.vectorFontFitting.FIT && (!width || !height))){
					//	reset the fitting if we don't have everything we need.
					fitting = dojox.gfx.vectorFontFitting.NONE;
				}
			}

			//	set up the lines array and the scaling factor.
			var lines, scale;
			switch(fitting){
				case dojox.gfx.vectorFontFitting.FIT:
					var o=this._getBestFit(text, width, height, leading);
					scale = o.scale;
					lines = o.lines;
					break;

				case dojox.gfx.vectorFontFitting.FLOW:
					scale = this._getSizeFactor(size);
					lines = this._getBestFlow(text, width, scale);
					break;

				default:
					scale = this._getSizeFactor(size);
					lines = [ text ];

			}

			//	make sure lines doesn't have any empty lines.
			lines = dojo.filter(lines, function(item){
				return item.length>0;
			});

			//	let's start drawing.
			var cy = 0,
				maxw = this._getLongestLine(lines).width;

			for(var i=0, l=lines.length; i<l; i++){
				var cx = 0,
					line=lines[i],
					linew = this._getWidth(line),
					lg=g.createGroup();

				//	loop through the glyphs and add them to the line group (lg)
				for (var j=0; j<line.length; j++){
					var glyph=line[j];
					if(glyph.path!==null){
						var p = lg.createPath(glyph.path).setFill(fillArgs);
						if(strokeArgs){ p.setStroke(strokeArgs); }
						p.setTransform([
							dojox.gfx.matrix.flipY,
							dojox.gfx.matrix.translate(cx, -this.viewbox.height-this.descent)
						]);
					}
					cx += glyph.xAdvance;
					if(j+1<line.length && glyph.kern && glyph.kern[line[j+1].code]){
						cx += glyph.kern[line[j+1].code].x;
					}
				}

				//	transform the line group.
				var dx = 0;
				if(align=="middle"){ dx = maxw/2 - linew/2; }
				else if(align=="end"){ dx = maxw - linew; }
				lg.setTransform({ dx: dx, dy: cy });
				cy += this.viewbox.height * leading;
			}

			//	scale the group
			g.setTransform(dojox.gfx.matrix.scale(scale));

			//	return the overall group
			return g;	//	dojox.gfx.Group
		},

		//	events
		onLoadBegin: function(/* String */url){ },
		onLoad: function(/* dojox.gfx.VectorFont */font){ }
	});

	//	TODO: dojox.gfx integration
/*

	//	Inherit from Group but attach Text properties to it.
	dojo.declare("dojox.gfx.VectorText", dojox.gfx.Group, {
		constructor: function(rawNode){
			dojox.gfx.Group._init.call(this);
			this.fontStyle = null;
		},

		//	private methods.
		_setFont: function(){
			//	render this using the font code.
			var f = this.fontStyle;
			var font = dojox.gfx._vectorFontCache[f.family];
			if(!font){
				throw new Error("dojox.gfx.VectorText._setFont: the passed font family '" + f.family + "' was not found.");
			}

			//	the actual rendering belongs to the font itself.
			font.draw(this, this.shape, this.fontStyle, this.fillStyle, this.strokeStyle);
		},

		getFont: function(){ return this.fontStyle; },

		//	overridden public methods.
		setShape: function(newShape){
			dojox.gfx.Group.setShape.call(this);
			this.shape = dojox.gfx.makeParameters(this.shape, newShape);
			this.bbox = null;
			this._setFont();
			return this;
		},

		//	if we've been drawing, we should have exactly one child, and that
		//		child will contain the real children.
		setFill: function(fill){
			this.fillStyle = fill;
			if(this.children[0]){
				dojo.forEach(this.children[0].children, function(group){
					dojo.forEach(group.children, function(path){
						path.setFill(fill);
					});
				}, this);
			}
			return this;
		},
		setStroke: function(stroke){
			this.strokeStyle = stroke;
			if(this.children[0]){
				dojo.forEach(this.children[0].children, function(group){
					dojo.forEach(group.children, function(path){
						path.setStroke(stroke);
					});
				}, this);
			}
			return this;
		},

		setFont: function(newFont){
			//	this will do the real rendering.
			this.fontStyle = typeof newFont == "string" ? dojox.gfx.splitFontString(newFont)
				: dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
			this._setFont();
			return this;
		},

		getBoundingBox: function(){
			return this.bbox;
		}
	});

	//	TODO: figure out how to add this to container objects!
	dojox.gfx.shape.Creator.createVectorText = function(text){
		return this.createObject(dojox.gfx.VectorText, text);
	}
*/
})();

}
