/lib/svgweb/tests/non-licensed/perf/test7/src/org/svgweb/core/SVGNode.as
ActionScript | 1123 lines | 628 code | 84 blank | 411 comment | 164 complexity | 97744adbbd4360b91bd5b929d3769533 MD5 | raw file
- /*
- Copyright (c) 2009 by contributors:
- * James Hight (http://labs.zavoo.com/)
- * Richard R. Masters
- * Google Inc. (Brad Neuberg -- http://codinginparadise.org)
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package org.svgweb.core
- {
- import org.svgweb.core.SVGViewer;
- import org.svgweb.SVGViewerWeb;
- import org.svgweb.nodes.*;
- import org.svgweb.utils.SVGColors;
- import org.svgweb.utils.SVGUnits;
-
- import flash.display.CapsStyle;
- import flash.display.DisplayObject;
- import flash.display.JointStyle;
- import flash.display.LineScaleMode;
- import flash.display.Shape;
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.MouseEvent;
- import flash.geom.Matrix;
- import flash.utils.getDefinitionByName;
- import flash.utils.getQualifiedClassName;
- /** Base node extended by all other SVG Nodes **/
- public class SVGNode extends EventDispatcher
- {
- public static const ATTRIBUTES_NOT_INHERITED:Array = ['id', 'x', 'y', 'width', 'height', 'rotate', 'transform',
- 'gradientTransform', 'opacity', 'mask', 'clip-path', 'href', 'target',
- 'viewBox', 'preserveAspectRatio'];
-
- public namespace xlink = 'http://www.w3.org/1999/xlink';
- public namespace svg = 'http://www.w3.org/2000/svg';
- public namespace aaa = 'http://www.w3.org/XML/1998/namespace';
-
- public var svgRoot:SVGSVGNode = null;
- public var svgParent:SVGNode = null;
- public var svgChildren:Array = new Array();
- public var isMask:Boolean = false;
- //Used for gradients
- public var xMin:Number;
- public var xMax:Number;
- public var yMin:Number;
- public var yMax:Number;
- protected var _parsedChildren:Boolean = false;
- public var _initialRenderDone:Boolean = false;
- protected var _firstX:Boolean = true;
- protected var _firstY:Boolean = true;
- protected var _xml:XML;
- protected var _invalidDisplay:Boolean = false;
- protected var _id:String = null;
- protected var _graphicsCommands:Array;
- protected var _styles:Object;
- protected var original:SVGNode;
- protected var _isClone:Boolean = false;
- protected var _clones:Array = new Array();
-
- protected var animations:Array = new Array();
-
- // cache the matrix to aid any zooming and panning operations
- // later
- protected var _lastVBMatrix:Matrix;
-
- /**
- *
- * To handle certain flash quirks, and to support certain SVG features,
- * the implementation of one SVG node is split into one to four
- * Sprites which perform the functions of transforming, clipping, and drawing.
- * Here are the specific functions performed by each sprite:
- *
- * topSprite:
- * * top sprite, used display list handling (parent/child relationships)
- * * handles the transform attribute
- * * mouse, stage, frame events
- * * handles visibility
- * * is the parent of the clip-path mask
- * * has mask set to 'default' mask (top level bounding box)
- *
- * clipSprite:
- * * has mask set to 'clip-path' mask
- *
- * drawSprite:
- * * handles all graphics access
- * * handles x,y,rotate,opacity attributes
- * * filters added here
- *
- * viewBoxSprite:
- * * handles viewBox transform
- * * parent of SVG children
- *
- */
- public var topSprite:SVGSprite;
- public var clipSprite:SVGSprite;
- public var drawSprite:SVGSprite;
- public var viewBoxSprite:SVGSprite;
- /**
- * Constructor
- *
- * @param xml XML object containing the SVG document. @default null
- *
- * @return void.
- */
- public function SVGNode(svgRoot:SVGSVGNode, xml:XML = null, original:SVGNode = null):void {
- this.svgRoot = svgRoot;
- this.xml = xml;
- if (original) {
- this.original = original;
- this._isClone = true;
- }
- if (topSprite) {
- topSprite.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
- topSprite.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
- }
- //increment('SVGNode_Constructor', new Date().getTime() - t);
- }
- public function createSVGSprites():void {
- //dbg("createSVGSprites, this="+this.xml.localName());
- topSprite = new SVGSprite(this);
- // This handle strange gradient bugs with negative transforms
- // by separating the transform from the drawing object
- /*if ( (xml.@['transform']).toString() != ""
- || (xml.@['clip-path']).toString() != "" ) {
- clipSprite = new SVGSprite(this);
- topSprite.addChild(clipSprite);
- }
- else {
- clipSprite = topSprite;
- }*/
- // ADDED!!!
- clipSprite = topSprite;
- // If the object has a gaussian filter, flash will blur the object mask,
- // even if the mask is not drawn with a blur. This is not correct rendering.
- // So, we use a stub parent object to hold the mask, in order to isolate the
- // mask from the filter. A child is created for drawing and the
- // filter is applied to the child.
- // FIXME: Currently x and y are on the drawSprite. Try to move
- // to transform sprite.
- /*if ( (xml.@['clip-path']).toString() != ""
- || (xml.@['x']).toString() != ""
- || (xml.@['y']).toString() != "" ) {
- drawSprite = new SVGSprite(this);
- clipSprite.addChild(drawSprite);
- }
- else {
- drawSprite = clipSprite;
- }*/
- // ADDED!!!
- drawSprite = topSprite;
- // If the object has a viewBox, the resulting transform should only apply to the
- // children of the object, so create a child sprite to hold the transform.
- // If the object is a text node, we put the TextField on the drawSprite instead of
- // the viewBoxSprite because it is simpler all children of viewBoxSprite are SVGSprites.
- /*if ( (xml.@['viewBox']).toString() != ""
- || (this is SVGSVGNode) || (this is SVGTextNode) ) {
- viewBoxSprite = new SVGSprite(this);
- drawSprite.addChild(viewBoxSprite);
- }
- else {
- viewBoxSprite = drawSprite;
- }*/
- // ADDED!!!
- viewBoxSprite = drawSprite;
- }
- /**
- * Parse the SVG XML.
- * This handles creation of child nodes.
- **/
- protected function parseChildren():void {
- this.dbg("parseChildren, this="+this.xml.localName());
- var text:String = '';
- for each (var childXML:XML in this._xml.children()) {
- if (childXML.nodeKind() == 'element') {
- // If we support text values then set them
- /*if (this.hasText()) {
- if (childXML.localName() == '__text'
- && childXML.children().length() > 0) {
- // for the SVGViewerWeb we use a nested
- // SVGDOMTextNode to store the actual value; this
- // class is necessary so that we can do text
- // node detection in the browser and have a unique
- // GUID per DOM text node
- text += childXML.children().toString();
- }
- }*/
- this.dbg("trying to parse node");
- var newChildNode:SVGNode = this.parseNode(childXML);
- this.dbg("node parsed");
- if (!newChildNode) {
- continue;
- }
- this.dbg("adding SVG child");
- this.addSVGChild(newChildNode);
- this.dbg("svg child added");
- }/* else if (childXML.nodeKind() == 'text'
- && this.hasText()) {
- text = this._xml.text().toString();
- } */
- }
-
- /*if (this.hasText()) {
- this.setText(text);
- }*/
- }
- public function parseNode(childXML:XML):SVGNode {
- var childNode:SVGNode = null;
- var nodeName:String = childXML.localName();
- nodeName = nodeName.toLowerCase();
- switch(nodeName) {
- /*case "a":
- childNode = new SVGANode(this.svgRoot, childXML);
- break;
- case "animate":
- childNode = new SVGAnimateNode(this.svgRoot, childXML);
- break;
- case "animatemotion":
- childNode = new SVGAnimateMotionNode(this.svgRoot, childXML);
- break;
- case "animatecolor":
- childNode = new SVGAnimateColorNode(this.svgRoot, childXML);
- break;
- case "animatetransform":
- childNode = new SVGAnimateTransformNode(this.svgRoot, childXML);
- break;
- case "audio":
- childNode = new SVGAudioNode(this.svgRoot, childXML);
- break;
- case "circle":
- childNode = new SVGCircleNode(this.svgRoot, childXML);
- break;
- case "clippath":
- childNode = new SVGClipPathNode(this.svgRoot, childXML);
- break;
- case "desc":
- childNode = new SVGDescNode(this.svgRoot, childXML);
- break;
- case "defs":
- childNode = new SVGDefsNode(this.svgRoot, childXML);
- break;
- case "ellipse":
- childNode = new SVGEllipseNode(this.svgRoot, childXML);
- break;
- case "filter":
- childNode = new SVGFilterNode(this.svgRoot, childXML);
- break;
- case "font":
- childNode = new SVGFontNode(this.svgRoot, childXML);
- break;
- case "font-face":
- childNode = new SVGFontFaceNode(this.svgRoot, childXML);
- break;*/
- case "g":
- childNode = new SVGGroupNode(this.svgRoot, childXML);
- break;
- /*case "glyph":
- childNode = new SVGGlyphNode(this.svgRoot, childXML);
- break;
- case "image":
- childNode = new SVGImageNode(this.svgRoot, childXML);
- break;
- case "line":
- childNode = new SVGLineNode(this.svgRoot, childXML);
- break;
- case "lineargradient":
- childNode = new SVGLinearGradient(this.svgRoot, childXML);
- break;
- case "mask":
- childNode = new SVGMaskNode(this.svgRoot, childXML);
- break;
- case "metadata":
- childNode = new SVGMetadataNode(this.svgRoot, childXML);
- break;
- case "missing-glyph":
- childNode = new SVGMissingGlyphNode(this.svgRoot, childXML);
- break;
- case "pattern":
- childNode = new SVGPatternNode(this.svgRoot, childXML);
- break;
- case "polygon":
- childNode = new SVGPolygonNode(this.svgRoot, childXML);
- break;
- case "polyline":
- childNode = new SVGPolylineNode(this.svgRoot, childXML);
- break;*/
- case "path":
- childNode = new SVGPathNode(this.svgRoot, childXML);
- break;
- /*case "radialgradient":
- childNode = new SVGRadialGradient(this.svgRoot, childXML);
- break;
- case "rect":
- childNode = new SVGRectNode(this.svgRoot, childXML);
- break;
- case "script":
- childNode = new SVGScriptNode(this.svgRoot, childXML);
- break;
- case "set":
- childNode = new SVGSetNode(this.svgRoot, childXML);
- break;
- case "stop":
- childNode = new SVGStopNode(this.svgRoot, childXML);
- break;*/
- case "svg":
- childNode = new SVGSVGNode(this.svgRoot, childXML, null, this.svgRoot.viewer);
- break;
- /*case "symbol":
- childNode = new SVGSymbolNode(this.svgRoot, childXML);
- break;
- case "text":
- childNode = new SVGTextNode(this.svgRoot, childXML);
- break;
- case "title":
- childNode = new SVGTitleNode(this.svgRoot, childXML);
- break;
- case "tspan":
- childNode = new SVGTspanNode(this.svgRoot, childXML);
- break;
- case "use":
- childNode = new SVGUseNode(this.svgRoot, childXML);
- break;
- case "video":
- childNode = new SVGVideoNode(this.svgRoot, childXML);
- break;*/
- //case "__text":
- /** These are fake text nodes necessary for integration
- with the browser through JavaScript. */
- /* childNode = new SVGDOMTextNode(this.svgRoot, childXML);
- break;
- case "null":
- break;*/
-
- default:
- trace("Unknown Element: " + nodeName);
- childNode = new SVGUnknownNode(this.svgRoot, childXML);
- break;
- }
- return childNode;
- }
-
- /**
- * Called when a node is created after page load with XML content
- * added as a child. Forces a parse.
- */
- public function forceParse():void {
- if (this._xml != null && !this._parsedChildren) {
- this.parseChildren();
- for (var i:uint = 0; i < this.svgChildren.length; i++) {
- var child:SVGNode = this.svgChildren[i];
- child.forceParse();
- }
-
- this._parsedChildren = true;
- }
- }
- /**
- * Triggers on ENTER_FRAME event
- * Redraws node graphics if _invalidDisplay == true
- **/
- protected function drawNode(event:Event = null):void {
- if ( this.topSprite.parent != null && this._invalidDisplay) {
- this.dbg("drawNode, this="+this.xml.localName());
- // are we in the middle of a suspendRedraw operation?
- if (this.svgRoot.viewer && this.svgRoot.viewer.isSuspended) {
- return;
- }
- //var t:int;
- //var pieceTime:int;
- this._invalidDisplay = false;
- if (this._xml != null) {
- this.dbg("1");
- //t = new Date().getTime();
- //pieceTime = new Date().getTime();
- //drawSprite.graphics.clear();
- //increment('drawNode_graphics.clear', new Date().getTime() - pieceTime);
- this.dbg("2");
- //pieceTime = new Date().getTime();
- if (!this._parsedChildren) {
- this.parseChildren();
- this._parsedChildren = true;
- }
- //increment('drawNode_parseChildren', new Date().getTime() - pieceTime);
- this.dbg("3");
- // sets x, y, rotate, and opacity
- //pieceTime = new Date().getTime();
- //this.setAttributes();
- //increment('drawNode_setAttributes', new Date().getTime() - pieceTime);
- this.dbg("4");
- //pieceTime = new Date().getTime();
- /*if (this.getStyleOrAttr('visibility') == 'hidden') {
- // SVG spec says visibility='hidden' should fully draw
- // the shape with full stroke widths, etc.,
- // just make it invisible. It also states that
- // all children should be invisible _unless_ they
- // explicitly have a visibility set to 'visible'.
- this.setVisibility('hidden');
- } else {
- //increment('drawNode_getStyleOrAttr(visibility)', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- this.setVisibility('visible');
- //increment('drawNode_setVisibility', new Date().getTime() - pieceTime);
- }*/
- this.dbg("5");
- //pieceTime = new Date().getTime();
- /*if (this.getStyleOrAttr('display') == 'none') {
- this.topSprite.visible = false;
- }
- else {*/
- this.dbg("6");
- //increment('drawNode_getStyleOrAttr(display)', new Date().getTime() - pieceTime);
- //this.topSprite.visible = true;
- this.dbg("6.1");
- //pieceTime = new Date().getTime();
- // <svg> nodes get an implicit mask of their height and width
- /*if (this is SVGSVGNode) {
- this.dbg("6.2");
- this.applyDefaultMask();
- this.dbg("6.3");
- }*/
- //increment('drawNode_applyDefaultMask', new Date().getTime() - pieceTime);
- this.dbg("7");
- //pieceTime = new Date().getTime();
- this.generateGraphicsCommands();
- this.dbg("8");
- //increment('drawNode_generateGraphicsCommands', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- //this.transformNode();
- this.dbg("9");
- //increment('drawNode_transformNode', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- this.draw();
- //increment('drawNode_draw', new Date().getTime() - pieceTime);
- this.dbg("10");
- //pieceTime = new Date().getTime();
- //this.applyClipPathMask();
- this.dbg("11");
- //increment('drawNode_applyClipPathMask', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- this.applyViewBox();
- this.dbg("12");
- //increment('drawNode_applyViewBox', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- //this.setupFilters();
- this.dbg("13");
- //increment('drawNode_setupFilters', new Date().getTime() - pieceTime);
- //}
- }
-
- //pieceTime = new Date().getTime();
- topSprite.removeEventListener(Event.ENTER_FRAME, drawNode);
- //increment('drawNode_removeEventListener', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- if (this.xml.@id) {
- //increment('drawNode_xml.@id', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- this.svgRoot.invalidateReferers(this.xml.@id);
- //increment('drawNode_invalidateReferers', new Date().getTime() - pieceTime);
- }
- //pieceTime = new Date().getTime();
- if (getPatternAncestor() != null) {
- //increment('drawNode_getPatternAncestor', new Date().getTime() - pieceTime);
- //pieceTime = new Date().getTime();
- this.svgRoot.invalidateReferers(getPatternAncestor().id);
- //increment('drawNode_invalidateReferers', new Date().getTime() - pieceTime);
- }
- //increment('drawNodeTOTAL', new Date().getTime() - t);
- }
-
- if (!this._initialRenderDone && this.topSprite.parent) {
- this.attachEventListeners();
- this._initialRenderDone = true;
- this.svgRoot.renderFinished();
- }
- }
- protected function setAttributes():void {
- this.loadAttribute('x');
- this.loadAttribute('y');
- this.loadAttribute('rotate','rotation');
- this.loadAttribute('opacity', 'alpha', true);
- if (this.getStyleOrAttr('pointer-events') == 'none') {
- topSprite.mouseEnabled = false;
- topSprite.mouseChildren = false;
- }
- else {
- topSprite.mouseEnabled = true;
- topSprite.mouseChildren = true;
- }
- }
- /**
- * Load an XML attribute into the current node
- *
- * @param name Name of the XML attribute to load
- * @param field Name of the node field to set. If null, the name attribute will be used as the field attribute.
- * @param applyStyle Boolean Optional parameter that controls whether we
- * will look in this node's style value if the given name is not in
- * the node's attribute list. Defaults to false.
- **/
- protected function loadAttribute(name:String, field:String = null,
- applyStyle:Boolean = false):void {
- if (field == null) {
- field = name;
- }
- var tmp:String = this.getStyleOrAttr(name);
- if (tmp != null) {
- switch (name) {
- case 'x':
- drawSprite[field] = SVGColors.cleanNumber2(tmp, this.getWidth());
- break;
- case 'y':
- drawSprite[field] = SVGColors.cleanNumber2(tmp, this.getHeight());
- break;
- case 'rotate':
- drawSprite[field] = SVGColors.cleanNumber(tmp);
- break;
- case 'opacity':
- drawSprite[field] = SVGColors.cleanNumber(tmp);
- break;
- }
- }
- }
- /** Sets this node and all its children to the given visibility value.
- If a child has an explicit visibility setting then that is retained
- independent of what we set here.
-
- @param visible - If 'visible', sets this node to be visible.
- The value 'hidden' will hide it.
- @param recursive - Internal variable. Should not set. */
- protected function setVisibility(visible:String,
- recursive:Boolean = false):void {
- // FIXME: Turn this into an iterative rather than a recursive
- // method
- //this.dbg('setVisibility, this='+this.xml.localName()+', visible='+visible+', recursive='+recursive);
- // ignore if we have our own visibility value and we are a recursive
- // call
- if (drawSprite && (this.getStyleOrAttr('visibility', null, false) == null
- || recursive == false) ) {
- if (visible == 'visible') {
- drawSprite.alpha = SVGColors.cleanNumber(this.getStyleOrAttr('opacity'));
- } else {
- drawSprite.alpha = 0;
- }
- }
-
- // set on all our children
- var child:SVGNode;
- for (var i:uint = 0; i < this.svgChildren.length; i++) {
- child = this.svgChildren[i];
- child.setVisibility(visible, true);
- }
- }
- // <svg> and <image> nodes get an implicit mask of their height and width
- public function applyDefaultMask():void {
- if ( (this is SVGImageNode &&
- this.getAttribute('width') != null &&
- this.getAttribute('height') != null )
- || this is SVGSVGNode ) {
- if (topSprite.mask == null) {
- var myMask:Shape = new Shape();
- topSprite.parent.addChild(myMask);
- topSprite.mask = myMask;
- }
- if (topSprite.mask is Shape) {
- Shape(topSprite.mask).graphics.clear();
- Shape(topSprite.mask).graphics.beginFill(0x000000);
- Shape(topSprite.mask).transform.matrix=topSprite.transform.matrix.clone();
- drawSprite.graphics.clear();
- drawSprite.graphics.beginFill(0x000000, 0);
- var canvasWidth:Number;
- var canvasHeight:Number;
- if (this.topSprite.parent is SVGViewerWeb) {
- var clipMode:String= SVGViewerWeb(this.topSprite.parent).getClipMode();
- //this.dbg("<svg> clip mode: "+ clipMode);
- switch (clipMode) {
- case 'height':
- canvasWidth = SVGViewer(this.topSprite.parent).getWidth();
- canvasHeight = this.getHeight();
- break;
- case 'neither':
- canvasWidth = SVGViewer(this.topSprite.parent).getWidth();
- canvasHeight = SVGViewer(this.topSprite.parent).getHeight();
- break;
- case 'width':
- canvasWidth = this.getWidth();
- canvasHeight = SVGViewer(this.topSprite.parent).getHeight();
- break;
- default:
- this.dbg("invalid <svg> clip mode: "+ clipMode);
- case 'both':
- canvasWidth = this.getWidth();
- canvasHeight = this.getHeight();
- break;
- }
- }
- else {
- canvasWidth = this.getWidth();
- canvasHeight = this.getHeight();
- }
- Shape(topSprite.mask).graphics.drawRect(drawSprite.x, drawSprite.y,
- canvasWidth, canvasHeight);
- Shape(topSprite.mask).graphics.endFill();
- // Draw an invisible rect to receive mouse events.
- drawSprite.graphics.drawRect(drawSprite.x, drawSprite.y,
- canvasWidth, canvasHeight);
- drawSprite.graphics.endFill();
- }
- }
- }
- /**
- * Called to generate AS3 graphics commands from the SVG instructions
- **/
- protected function generateGraphicsCommands():void {
- this._graphicsCommands = new Array();
- }
- /**
- * Perform transformations defined by the transform attribute
- **/
- public function transformNode():void {
- topSprite.transform.matrix = new Matrix();
- this.loadAttribute('x');
- this.loadAttribute('y');
- // Tspan x,y replaces the parent text x,y instead of
- // offsetting the parent like every other node.
- // However, if the x or y is not specified, then use the parent.
- if (this is SVGTspanNode) {
- if (this.getAttribute('x',null) != null) {
- drawSprite.x = drawSprite.x - this.svgParent.getAttribute('x',0);
- }
- if (this.getAttribute('y',null) != null) {
- drawSprite.y = drawSprite.y - this.svgParent.getAttribute('y',0);
- }
- }
-
- this.loadAttribute('rotate', 'rotation');
- // Apply transform attribute
- var trans:String = this.getAttribute('transform');
- if (trans) {
- topSprite.transform.matrix = this.parseTransform(trans,
- topSprite.transform.matrix.clone());
- }
-
- var animResult:Array = this.getAllAnimsTransform();
- var animMatrix:Matrix = animResult[0];
- var isAdditive:Boolean = animResult[1];
- if (animMatrix != null) {
- // See Issue 311: Tranforms must be applied in correct order
- // and must account for additive attribute.
- if (isAdditive) {
- var newMatrix:Matrix = topSprite.transform.matrix.clone();
- animMatrix.concat(newMatrix);
- }
- topSprite.transform.matrix = animMatrix;
- }
- }
- public function parseTransform(trans:String, baseMatrix:Matrix = null):Matrix {
- if (!baseMatrix) {
- baseMatrix = new Matrix();
- }
-
- if (trans != null) {
- var transArray:Array = trans.match(/\S+\(.*?\)/sg);
- transArray.reverse();
- for each(var tran:String in transArray) {
- var tranArray:Array = tran.split('(',2);
- if (tranArray.length == 2)
- {
- var command:String = String(tranArray[0]);
- var args:String = String(tranArray[1]);
- args = args.replace(')','');
- args = args.replace(/\s+/sg,","); //Replace spaces with a comma
- args = args.replace(/,{2,}/sg,","); // Remove any extra commas
- args = args.replace(/^,/, ''); //Remove leading comma
- args = args.replace(/,$/, ''); //Remove trailing comma
- var argsArray:Array = args.split(',');
- var nodeMatrix:Matrix = new Matrix();
- switch (command) {
- case "matrix":
- if (argsArray.length == 6) {
- nodeMatrix.a = argsArray[0];
- nodeMatrix.b = argsArray[1];
- nodeMatrix.c = argsArray[2];
- nodeMatrix.d = argsArray[3];
- nodeMatrix.tx = argsArray[4];
- nodeMatrix.ty = argsArray[5];
- }
- break;
- case "translate":
- if (argsArray.length == 1) {
- nodeMatrix.tx = argsArray[0];
- }
- else if (argsArray.length == 2) {
- nodeMatrix.tx = argsArray[0];
- nodeMatrix.ty = argsArray[1];
- }
- break;
- case "scale":
- if (argsArray.length == 1) {
- nodeMatrix.a = argsArray[0];
- nodeMatrix.d = argsArray[0];
- }
- else if (argsArray.length == 2) {
- nodeMatrix.a = argsArray[0];
- nodeMatrix.d = argsArray[1];
- }
- break;
-
- case "skewX":
- nodeMatrix.c = Math.tan(argsArray[0] * Math.PI / 180.0);
- break;
-
- case "skewY":
- nodeMatrix.b = Math.tan(argsArray[0] * Math.PI / 180.0);
- break;
-
- case "rotate":
- if (argsArray.length == 3) {
- nodeMatrix.translate(-argsArray[1], -argsArray[2]);
- nodeMatrix.rotate(Number(argsArray[0])* Math.PI / 180.0);
- nodeMatrix.translate(argsArray[1], argsArray[2]);
- }
- else {
- nodeMatrix.rotate(Number(argsArray[0])* Math.PI / 180.0);
- }
- break;
-
- default:
- //this.dbg('Unknown Transformation: ' + command);
- }
- baseMatrix.concat(nodeMatrix);
- }
- }
- }
-
- return baseMatrix;
- }
- protected function draw():void {
- var firstX:Number = 0;
- var firstY:Number = 0;
- for each (var command:Array in this._graphicsCommands) {
- switch(command[0]) {
- case "SF":
- this.nodeBeginFill();
- //drawSprite.graphics.lineStyle(0, 0, 0, false, LineScaleMode.NORMAL, "none");
- //line_width=0, line_color=0, line_alpha=0, linescalemode=NORMAL,, capsStyle=none, jointStyle=miter, miterLimit=4
- //drawSprite.graphics.lineStyle(1, 0x000000);
- //drawSprite.graphics.beginFill(0x000000);
- break;
- case "EF":
- //drawSprite.graphics.lineStyle(0, 0, 0);
- //drawSprite.graphics.endFill();
- this.nodeEndFill();
- break;
- /*case "SF":
- this.nodeBeginFill();
- break;*/
- /*case "EF":
- drawSprite.graphics.lineStyle(0, 0, 0);
- this.nodeEndFill();
- break;*/
- case "M":
- drawSprite.graphics.lineStyle(0, 0, 0);
- drawSprite.graphics.moveTo(command[1], command[2]);
- firstX = command[1];
- firstY = command[2];
- this.nodeBeginStroke();
- break;
- case "L":
- drawSprite.graphics.lineTo(command[1], command[2]);
- break;
- case "C":
- //dbg("curveTo: " + command[1] + ", " + command[2] + ", " + command[3] + ", " + command[4]);
- /*if (isNaN(command[1]) || isNaN(command[2])
- || isNaN(command[3]) || isNaN(command[4])) {
- dbg("Invalid curve path data: " + command[1]
- + ", " + command[2] + ", " + command[3]
- + ", " + command[4]);
- continue;
- }*/
- drawSprite.graphics.curveTo(command[1], command[2],command[3], command[4]);
- // DELETE ME!!!
- //drawSprite.graphics.lineTo(command[3], command[4]);
- break;
- case "Z":
- drawSprite.graphics.lineTo(firstX, firstY);
- break;
- case "LINE":
- this.nodeBeginFill();
- drawSprite.graphics.moveTo(command[1], command[2]);
- drawSprite.graphics.lineTo(command[3], command[4]);
- this.nodeEndFill();
- break;
- case "RECT":
- this.nodeBeginFill();
- if (command.length == 5) {
- drawSprite.graphics.drawRect(command[1], command[2],command[3], command[4]);
- }
- else {
- drawSprite.graphics.drawRoundRect(command[1], command[2],command[3], command[4], command[5], command[6]);
- }
- this.nodeEndFill();
- break;
- case "CIRCLE":
- this.nodeBeginFill();
- drawSprite.graphics.drawCircle(command[1], command[2], command[3]);
- this.nodeEndFill();
- break;
- case "ELLIPSE":
- this.nodeBeginFill();
- drawSprite.graphics.drawEllipse(command[1], command[2],command[3], command[4]);
- this.nodeEndFill();
- break;
- }
- }
- }
- /**
- * Called at the start of drawing an SVG element.
- * Sets fill and stroke styles
- **/
- protected function nodeBeginFill():void {
- //Fill
- var color_and_alpha:Array = [0, 0];
- var color_core:Number = 0;
- var color_alpha:Number = 0;
- var fill_alpha:Number = 0;
- var fill:String = this.getStyleOrAttr('fill');
- if ( (fill != 'none') && (fill != null) && (this.getStyleOrAttr('visibility') != 'hidden') ) {
- var matches:Array = fill.match(/url\(#([^\)]+)\)/si);
- if (matches != null && matches.length > 0) {
- var fillName:String = matches[1];
- this.svgRoot.addReference(this, fillName);
- var fillNode:SVGNode = this.svgRoot.getNode(fillName);
- if (!fillNode) {
- // this happens normally
- //this.dbg("Gradient " + fillName + " not (yet?) available for " + this.xml.@id);
- }
- if (fillNode is SVGGradient) {
- SVGGradient(fillNode).beginGradientFill(this);
- }
- else if (fillNode is SVGPatternNode) {
- SVGPatternNode(fillNode).beginPatternFill(this);
- }
- }
- else {
- if (fill == 'currentColor') {
- fill = this.getStyleOrAttr('color');
- }
- color_and_alpha = SVGColors.getColorAndAlpha(fill);
- color_core = color_and_alpha[0];
- color_alpha = color_and_alpha[1];
- fill_alpha = SVGColors.cleanNumber( this.getStyleOrAttr('fill-opacity') ) * color_alpha;
- drawSprite.graphics.beginFill(color_core, fill_alpha);
- }
- }
- this.dbg("calling nodeBeginStroke, the one that matters");
- nodeBeginStroke();
- }
- protected function nodeBeginStroke():void {
- //Stroke
- var line_color:Number;
- var line_alpha:Number;
- var line_width:Number;
- var stroke:String = this.getStyleOrAttr('stroke');
- if ( (stroke == 'none') || (stroke == '') || (this.getStyleOrAttr('visibility') == 'hidden') ) {
- line_alpha = 0;
- line_color = 0;
- line_width = 0;
- }
- else {
- if (stroke == 'currentColor') {
- stroke = this.getStyleOrAttr('color');
- }
- line_color = SVGColors.cleanNumber(SVGColors.getColor(stroke));
- line_alpha = SVGColors.cleanNumber(this.getStyleOrAttr('stroke-opacity'));
- line_width = SVGColors.cleanNumber(this.getStyleOrAttr('stroke-width'));
- }
- var capsStyle:String = this.getStyleOrAttr('stroke-linecap');
- if (capsStyle == 'round'){
- capsStyle = CapsStyle.ROUND;
- }
- else if (capsStyle == 'square'){
- capsStyle = CapsStyle.SQUARE;
- }
- else {
- capsStyle = CapsStyle.NONE;
- }
-
- var jointStyle:String = this.getStyleOrAttr('stroke-linejoin');
- if (jointStyle == 'round'){
- jointStyle = JointStyle.ROUND;
- }
- else if (jointStyle == 'bevel'){
- jointStyle = JointStyle.BEVEL;
- }
- else {
- jointStyle = JointStyle.MITER;
- }
-
- var miterLimit:String = this.getStyleOrAttr('stroke-miterlimit');
- if (miterLimit == null) {
- miterLimit = '4';
- }
-
- //this.dbg("line_width="+line_width+", line_color="+line_color+", line_alpha="+line_alpha+", linescalemode=NORMAL,"
- // + ", capsStyle="+capsStyle+", jointStyle="+jointStyle+", miterLimit="+miterLimit);
- // jointStyle="miter" is VERY slow!!! HANDLE!!!
- drawSprite.graphics.lineStyle(line_width, line_color, line_alpha, false, LineScaleMode.NORMAL,
- capsStyle); /*,*jointStyle, SVGColors.cleanNumber(miterLimit));*/
- if ( (stroke != 'none') && (stroke != '') && (this.getStyleOrAttr('visibility') != 'hidden') ) {
- var strokeMatches:Array = stroke.match(/url\(#([^\)]+)\)/si);
- if (strokeMatches != null && strokeMatches.length > 0) {
- var strokeName:String = strokeMatches[1];
- this.svgRoot.addReference(this, strokeName);
- var strokeNode:SVGNode = this.svgRoot.getNode(strokeName);
- if (!strokeNode) {
- // this happens normally
- //this.dbg("stroke gradient " + strokeName + " not (yet?) available for " + this.xml.@id);
- }
- if (strokeNode is SVGGradient) {
- SVGGradient(strokeNode).lineGradientStyle(this, line_alpha);
- }
- }
- }
- }
-
- /**
- * Called at the end of drawing an SVG element
- **/
- protected function nodeEndFill():void {
- drawSprite.graphics.endFill();
- }
- /**
- * Check value of x against _minX and _maxX,
- * Update values when appropriate
- **/
- protected function setXMinMax(value:Number):void {
- if (_firstX) {
- _firstX = false;
- this.xMax = value;
- this.xMin = value;
- return;
- }
-
- if (value < this.xMin) {
- this.xMin = value;
- }
- if (value > this.xMax) {
- this.xMax = value;
- }
- }
-
- /**
- * Check value of y against _minY and _maxY,
- * Update values when appropriate
- **/
- protected function setYMinMax(value:Number):void {
- if (_firstY) {
- _firstY = false;
- this.yMax = value;
- this.yMin = value;
- return;
- }
-
- if (value < this.yMin) {
- this.yMin = value;
- }
- if (value > this.yMax) {
- this.yMax = value;
- }
- }
- public function applyViewBox():void {
- // Apply viewbox transform
- var viewBox:String = this.getAttribute('viewBox');
- var preserveAspectRatio:String = this.getAttribute('preserveAspectRatio');
- if ( (viewBox != null) || (preserveAspectRatio != null) ) {
- var newMatrix:Matrix = new Matrix();
- if (preserveAspectRatio == null) {
- preserveAspectRatio = 'xMidYMid meet';
- }
- /**
- * Canvas, the viewport
- **/
- var canvasWidth:Number;
- var canvasHeight:Number;
- if (topSprite.parent is SVGViewerWeb) {
- canvasWidth = SVGViewerWeb(topSprite.parent).getWidth();
- canvasHeight = SVGViewerWeb(topSprite.parent).getHeight();
- }
- else {
- canvasWidth = this.getWidth();
- canvasHeight = this.getHeight();
- }
- /**
- * Viewbox
- **/
- var viewX:Number;
- var viewY:Number;
- var viewWidth:Number;
- var viewHeight:Number;
- if (viewBox != null) {
- viewBox = viewBox.replace(/,/sg," "); //Replace commas with spaces
- var points:Array = viewBox.split(/\s+/); //Split by white space
- viewX = SVGColors.cleanNumber(points[0]);
- viewY = SVGColors.cleanNumber(points[1]);
- viewWidth = SVGColors.cleanNumber(points[2]);
- viewHeight = SVGColors.cleanNumber(points[3]);
- }
- else {
- viewX = 0;
- viewY = 0;
- viewWidth = canvasWidth;
- viewHeight = canvasHeight;
- }
- var oldAspectRes:Number = viewWidth / viewHeight;
- var newAspectRes:Number = canvasWidth / canvasHeight;
- var cropWidth:Number;
- var cropHeight:Number;
- var alignMode:String = preserveAspectRatio.substr(0,8);
- var meetOrSlice:String = 'meet';
- if (preserveAspectRatio.indexOf('slice') != -1) {
- meetOrSlice = 'slice';
- }
- /**
- * Handle Scaling
- **/
- if (alignMode == 'none') {
- // stretch to fit viewport width and height
- cropWidth = canvasWidth;
- cropHeight = canvasHeight;
- }
- else {
- if (meetOrSlice == 'meet') {
- // shrink to fit inside viewport
- if (newAspectRes > oldAspectRes) {
- cropWidth = canvasHeight * oldAspectRes;
- cropHeight = canvasHeight;
- }
- else {
- cropWidth = canvasWidth;
- cropHeight = canvasWidth / oldAspectRes;
- }
-
- }
- else {
- // meetOrSlice == 'slice'
- // Expand to cover viewport.
- if (newAspectRes > oldAspectRes) {
- cropWidth = canvasWidth;
- cropHeight = canvasWidth / oldAspectRes;
- }
- else {
- cropWidth = canvasHeight * oldAspectRes;
- cropHeight = canvasHeight;
- }
-
- }
- }
- var scale