http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/transitionbase.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/transitionbase.js 
b/externs/GCL/externs/goog/fx/transitionbase.js
new file mode 100644
index 0000000..0a2c184
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/transitionbase.js
@@ -0,0 +1,236 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview An abstract base class for transitions. This is a simple
+ * interface that allows for playing, pausing and stopping an animation. It 
adds
+ * a simple event model, and animation status.
+ */
+goog.provide('goog.fx.TransitionBase');
+goog.provide('goog.fx.TransitionBase.State');
+
+goog.require('goog.events.EventTarget');
+goog.require('goog.fx.Transition');  // Unreferenced: interface
+
+
+
+/**
+ * Constructor for a transition object.
+ *
+ * @constructor
+ * @implements {goog.fx.Transition}
+ * @extends {goog.events.EventTarget}
+ */
+goog.fx.TransitionBase = function() {
+  goog.fx.TransitionBase.base(this, 'constructor');
+
+  /**
+   * The internal state of the animation.
+   * @type {goog.fx.TransitionBase.State}
+   * @private
+   */
+  this.state_ = goog.fx.TransitionBase.State.STOPPED;
+
+  /**
+   * Timestamp for when the animation was started.
+   * @type {?number}
+   * @protected
+   */
+  this.startTime = null;
+
+  /**
+   * Timestamp for when the animation finished or was stopped.
+   * @type {?number}
+   * @protected
+   */
+  this.endTime = null;
+};
+goog.inherits(goog.fx.TransitionBase, goog.events.EventTarget);
+
+
+/**
+ * Enum for the possible states of an animation.
+ * @enum {number}
+ */
+goog.fx.TransitionBase.State = {
+  STOPPED: 0,
+  PAUSED: -1,
+  PLAYING: 1
+};
+
+
+/**
+ * Plays the animation.
+ *
+ * @param {boolean=} opt_restart Optional parameter to restart the animation.
+ * @return {boolean} True iff the animation was started.
+ * @override
+ */
+goog.fx.TransitionBase.prototype.play = goog.abstractMethod;
+
+
+/**
+ * Stops the animation.
+ *
+ * @param {boolean=} opt_gotoEnd Optional boolean parameter to go the the end 
of
+ *     the animation.
+ * @override
+ */
+goog.fx.TransitionBase.prototype.stop = goog.abstractMethod;
+
+
+/**
+ * Pauses the animation.
+ */
+goog.fx.TransitionBase.prototype.pause = goog.abstractMethod;
+
+
+/**
+ * Returns the current state of the animation.
+ * @return {goog.fx.TransitionBase.State} State of the animation.
+ */
+goog.fx.TransitionBase.prototype.getStateInternal = function() {
+  return this.state_;
+};
+
+
+/**
+ * Sets the current state of the animation to playing.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStatePlaying = function() {
+  this.state_ = goog.fx.TransitionBase.State.PLAYING;
+};
+
+
+/**
+ * Sets the current state of the animation to paused.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStatePaused = function() {
+  this.state_ = goog.fx.TransitionBase.State.PAUSED;
+};
+
+
+/**
+ * Sets the current state of the animation to stopped.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStateStopped = function() {
+  this.state_ = goog.fx.TransitionBase.State.STOPPED;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is playing.
+ */
+goog.fx.TransitionBase.prototype.isPlaying = function() {
+  return this.state_ == goog.fx.TransitionBase.State.PLAYING;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is paused.
+ */
+goog.fx.TransitionBase.prototype.isPaused = function() {
+  return this.state_ == goog.fx.TransitionBase.State.PAUSED;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is stopped.
+ */
+goog.fx.TransitionBase.prototype.isStopped = function() {
+  return this.state_ == goog.fx.TransitionBase.State.STOPPED;
+};
+
+
+/**
+ * Dispatches the BEGIN event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onBegin = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.BEGIN);
+};
+
+
+/**
+ * Dispatches the END event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onEnd = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.END);
+};
+
+
+/**
+ * Dispatches the FINISH event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onFinish = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.FINISH);
+};
+
+
+/**
+ * Dispatches the PAUSE event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onPause = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.PAUSE);
+};
+
+
+/**
+ * Dispatches the PLAY event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onPlay = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.PLAY);
+};
+
+
+/**
+ * Dispatches the RESUME event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onResume = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.RESUME);
+};
+
+
+/**
+ * Dispatches the STOP event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onStop = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.STOP);
+};
+
+
+/**
+ * Dispatches an event object for the current animation.
+ * @param {string} type Event type that will be dispatched.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.dispatchAnimationEvent = function(type) {
+  this.dispatchEvent(type);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/abstractgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/abstractgraphics.js 
b/externs/GCL/externs/goog/graphics/abstractgraphics.js
new file mode 100644
index 0000000..0ae1776
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/abstractgraphics.js
@@ -0,0 +1,454 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+
+/**
+ * @fileoverview Graphics utility functions and factory methods.
+ * @author [email protected] (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.AbstractGraphics');
+
+goog.require('goog.dom');
+goog.require('goog.graphics.Path');
+goog.require('goog.math.Coordinate');
+goog.require('goog.math.Size');
+goog.require('goog.style');
+goog.require('goog.ui.Component');
+
+
+
+/**
+ * Base class for the different graphics. You should never construct objects
+ * of this class. Instead us goog.graphics.createGraphics
+ * @param {number|string} width The width in pixels or percent.
+ * @param {number|string} height The height in pixels or percent.
+ * @param {?number=} opt_coordWidth Optional coordinate system width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight Optional coordinate system height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.ui.Component}
+ */
+goog.graphics.AbstractGraphics = function(width, height,
+                                          opt_coordWidth, opt_coordHeight,
+                                          opt_domHelper) {
+  goog.ui.Component.call(this, opt_domHelper);
+
+  /**
+   * Width of graphics in pixels or percentage points.
+   * @type {number|string}
+   * @protected
+   */
+  this.width = width;
+
+  /**
+   * Height of graphics in pixels or precentage points.
+   * @type {number|string}
+   * @protected
+   */
+  this.height = height;
+
+  /**
+   * Width of coordinate system in units.
+   * @type {?number}
+   * @protected
+   */
+  this.coordWidth = opt_coordWidth || null;
+
+  /**
+   * Height of coordinate system in units.
+   * @type {?number}
+   * @protected
+   */
+  this.coordHeight = opt_coordHeight || null;
+};
+goog.inherits(goog.graphics.AbstractGraphics, goog.ui.Component);
+
+
+/**
+ * The root level group element.
+ * @type {goog.graphics.GroupElement?}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.canvasElement = null;
+
+
+/**
+ * Left coordinate of the view box
+ * @type {number}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.coordLeft = 0;
+
+
+/**
+ * Top coordinate of the view box
+ * @type {number}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.coordTop = 0;
+
+
+/**
+ * @return {goog.graphics.GroupElement} The root level canvas element.
+ */
+goog.graphics.AbstractGraphics.prototype.getCanvasElement = function() {
+  return this.canvasElement;
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth  The coordinate width.
+ * @param {number} coordHeight  The coordinate height.
+ */
+goog.graphics.AbstractGraphics.prototype.setCoordSize = function(coordWidth,
+                                                                 coordHeight) {
+  this.coordWidth = coordWidth;
+  this.coordHeight = coordHeight;
+};
+
+
+/**
+ * @return {goog.math.Size} The coordinate size.
+ */
+goog.graphics.AbstractGraphics.prototype.getCoordSize = function() {
+  if (this.coordWidth) {
+    return new goog.math.Size(this.coordWidth,
+        /** @type {number} */ (this.coordHeight));
+  } else {
+    return this.getPixelSize();
+  }
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left  The coordinate system left bound.
+ * @param {number} top  The coordinate system top bound.
+ */
+goog.graphics.AbstractGraphics.prototype.setCoordOrigin = goog.abstractMethod;
+
+
+/**
+ * @return {!goog.math.Coordinate} The coordinate system position.
+ */
+goog.graphics.AbstractGraphics.prototype.getCoordOrigin = function() {
+  return new goog.math.Coordinate(this.coordLeft, this.coordTop);
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth  The width in pixels.
+ * @param {number} pixelHeight  The height in pixels.
+ */
+goog.graphics.AbstractGraphics.prototype.setSize = goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Size} The size of canvas.
+ * @deprecated Use getPixelSize.
+ */
+goog.graphics.AbstractGraphics.prototype.getSize = function() {
+  return this.getPixelSize();
+};
+
+
+/**
+ * @return {goog.math.Size?} Returns the number of pixels spanned by the
+ *     surface, or null if the size could not be computed due to the size being
+ *     specified in percentage points and the component not being in the
+ *     document.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelSize = function() {
+  if (this.isInDocument()) {
+    return goog.style.getSize(this.getElement());
+  }
+  if (goog.isNumber(this.width) && goog.isNumber(this.height)) {
+    return new goog.math.Size(this.width, this.height);
+  }
+  return null;
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the x direction.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelScaleX = function() {
+  var pixelSize = this.getPixelSize();
+  return pixelSize ? pixelSize.width / this.getCoordSize().width : 0;
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the y direction.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelScaleY = function() {
+  var pixelSize = this.getPixelSize();
+  return pixelSize ? pixelSize.height / this.getCoordSize().height : 0;
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ */
+goog.graphics.AbstractGraphics.prototype.clear = goog.abstractMethod;
+
+
+/**
+ * Remove a single drawing element from the surface.  The default 
implementation
+ * assumes a DOM based drawing surface.
+ * @param {goog.graphics.Element} element The element to remove.
+ */
+goog.graphics.AbstractGraphics.prototype.removeElement = function(element) {
+  goog.dom.removeNode(element.getElement());
+};
+
+
+/**
+ * Sets the fill for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementFill = goog.abstractMethod;
+
+
+/**
+ * Sets the stroke for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementStroke = 
goog.abstractMethod;
+
+
+/**
+ * Set the transformation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementTransform =
+    goog.abstractMethod;
+
+
+/**
+ * Set the affine transform of an element.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementAffineTransform =
+    goog.abstractMethod;
+
+
+/**
+ * Draw a circle
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} r Radius length.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.EllipseElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawCircle = function(
+    cx, cy, r, stroke, fill, opt_group) {
+  return this.drawEllipse(cx, cy, r, r, stroke, fill, opt_group);
+};
+
+
+/**
+ * Draw an ellipse
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.EllipseElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawEllipse = goog.abstractMethod;
+
+
+/**
+ * Draw a rectangle
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.RectElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawRect = goog.abstractMethod;
+
+
+/**
+ * Draw a text string within a rectangle (drawing is horizontal)
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {string} align Horizontal alignment: left (default), center, right.
+ * @param {string} vAlign Vertical alignment: top (default), center, bottom.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill  Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.TextElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawText = function(
+    text, x, y, width, height, align, vAlign, font, stroke, fill, opt_group) {
+  var baseline = font.size / 2; // Baseline is middle of line
+  var textY;
+  if (vAlign == 'bottom') {
+    textY = y + height - baseline;
+  } else if (vAlign == 'center') {
+    textY = y + height / 2;
+  } else {
+    textY = y + baseline;
+  }
+
+  return this.drawTextOnLine(text, x, textY, x + width, textY, align,
+      font, stroke, fill, opt_group);
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text  The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {string} align Horizontal alingnment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.TextElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawTextOnLine = goog.abstractMethod;
+
+
+/**
+ * Draw a path.
+ *
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.PathElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawPath = goog.abstractMethod;
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.GroupElement} The newly created group.
+ */
+goog.graphics.AbstractGraphics.prototype.createGroup = goog.abstractMethod;
+
+
+/**
+ * Create an empty path.
+ *
+ * @return {!goog.graphics.Path} The path.
+ * @deprecated Use {@code new goog.graphics.Path()}.
+ */
+goog.graphics.AbstractGraphics.prototype.createPath = function() {
+  return new goog.graphics.Path();
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated
+ * area. The way text length is measured is by writing it into a div that is
+ * after the visible area, measure the div width, and immediatly erase the
+ * written value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ *
+ * @return {number} The width in pixels of the text strings.
+ */
+goog.graphics.AbstractGraphics.prototype.getTextWidth = goog.abstractMethod;
+
+
+/**
+ * @return {boolean} Whether the underlying element can be cloned resulting in
+ *     an accurate reproduction of the graphics contents.
+ */
+goog.graphics.AbstractGraphics.prototype.isDomClonable = function() {
+  return false;
+};
+
+
+/**
+ * Start preventing redraws - useful for chaining large numbers of changes
+ * together.  Not guaranteed to do anything - i.e. only use this for
+ * optimization of a single code path.
+ */
+goog.graphics.AbstractGraphics.prototype.suspend = function() {
+};
+
+
+/**
+ * Stop preventing redraws.  If any redraws had been prevented, a redraw will
+ * be done now.
+ */
+goog.graphics.AbstractGraphics.prototype.resume = function() {
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/affinetransform.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/affinetransform.js 
b/externs/GCL/externs/goog/graphics/affinetransform.js
new file mode 100644
index 0000000..ec328f2
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/affinetransform.js
@@ -0,0 +1,588 @@
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+
+/**
+ * @fileoverview Provides an object representation of an AffineTransform and
+ * methods for working with it.
+ */
+
+
+goog.provide('goog.graphics.AffineTransform');
+
+goog.require('goog.math');
+
+
+
+/**
+ * Creates a 2D affine transform. An affine transform performs a linear
+ * mapping from 2D coordinates to other 2D coordinates that preserves the
+ * "straightness" and "parallelness" of lines.
+ *
+ * Such a coordinate transformation can be represented by a 3 row by 3 column
+ * matrix with an implied last row of [ 0 0 1 ]. This matrix transforms source
+ * coordinates (x,y) into destination coordinates (x',y') by considering them
+ * to be a column vector and multiplying the coordinate vector by the matrix
+ * according to the following process:
+ * <pre>
+ *      [ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
+ *      [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
+ *      [ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
+ * </pre>
+ *
+ * This class is optimized for speed and minimizes calculations based on its
+ * knowledge of the underlying matrix (as opposed to say simply performing
+ * matrix multiplication).
+ *
+ * @param {number=} opt_m00 The m00 coordinate of the transform.
+ * @param {number=} opt_m10 The m10 coordinate of the transform.
+ * @param {number=} opt_m01 The m01 coordinate of the transform.
+ * @param {number=} opt_m11 The m11 coordinate of the transform.
+ * @param {number=} opt_m02 The m02 coordinate of the transform.
+ * @param {number=} opt_m12 The m12 coordinate of the transform.
+ * @constructor
+ * @final
+ */
+goog.graphics.AffineTransform = function(opt_m00, opt_m10, opt_m01,
+    opt_m11, opt_m02, opt_m12) {
+  if (arguments.length == 6) {
+    this.setTransform(/** @type {number} */ (opt_m00),
+                      /** @type {number} */ (opt_m10),
+                      /** @type {number} */ (opt_m01),
+                      /** @type {number} */ (opt_m11),
+                      /** @type {number} */ (opt_m02),
+                      /** @type {number} */ (opt_m12));
+  } else if (arguments.length != 0) {
+    throw Error('Insufficient matrix parameters');
+  } else {
+    this.m00_ = this.m11_ = 1;
+    this.m10_ = this.m01_ = this.m02_ = this.m12_ = 0;
+  }
+};
+
+
+/**
+ * @return {boolean} Whether this transform is the identity transform.
+ */
+goog.graphics.AffineTransform.prototype.isIdentity = function() {
+  return this.m00_ == 1 && this.m10_ == 0 && this.m01_ == 0 &&
+      this.m11_ == 1 && this.m02_ == 0 && this.m12_ == 0;
+};
+
+
+/**
+ * @return {!goog.graphics.AffineTransform} A copy of this transform.
+ */
+goog.graphics.AffineTransform.prototype.clone = function() {
+  return new goog.graphics.AffineTransform(this.m00_, this.m10_, this.m01_,
+      this.m11_, this.m02_, this.m12_);
+};
+
+
+/**
+ * Sets this transform to the matrix specified by the 6 values.
+ *
+ * @param {number} m00 The m00 coordinate of the transform.
+ * @param {number} m10 The m10 coordinate of the transform.
+ * @param {number} m01 The m01 coordinate of the transform.
+ * @param {number} m11 The m11 coordinate of the transform.
+ * @param {number} m02 The m02 coordinate of the transform.
+ * @param {number} m12 The m12 coordinate of the transform.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setTransform = function(m00, m10, m01,
+    m11, m02, m12) {
+  if (!goog.isNumber(m00) || !goog.isNumber(m10) || !goog.isNumber(m01) ||
+      !goog.isNumber(m11) || !goog.isNumber(m02) || !goog.isNumber(m12)) {
+    throw Error('Invalid transform parameters');
+  }
+  this.m00_ = m00;
+  this.m10_ = m10;
+  this.m01_ = m01;
+  this.m11_ = m11;
+  this.m02_ = m02;
+  this.m12_ = m12;
+  return this;
+};
+
+
+/**
+ * Sets this transform to be identical to the given transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to copy.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.copyFrom = function(tx) {
+  this.m00_ = tx.m00_;
+  this.m10_ = tx.m10_;
+  this.m01_ = tx.m01_;
+  this.m11_ = tx.m11_;
+  this.m02_ = tx.m02_;
+  this.m12_ = tx.m12_;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.scale = function(sx, sy) {
+  this.m00_ *= sx;
+  this.m10_ *= sx;
+  this.m01_ *= sy;
+  this.m11_ *= sy;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a scaling transformation,
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [sx  0 0] [m00 m01 m02]
+ * [ 0 sy 0] [m10 m11 m12]
+ * [ 0  0 1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preScale = function(sx, sy) {
+  this.m00_ *= sx;
+  this.m01_ *= sx;
+  this.m02_ *= sx;
+  this.m10_ *= sy;
+  this.m11_ *= sy;
+  this.m12_ *= sy;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a translate transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.translate = function(dx, dy) {
+  this.m02_ += dx * this.m00_ + dy * this.m01_;
+  this.m12_ += dx * this.m10_ + dy * this.m11_;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a translate transformation,
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [1 0 dx] [m00 m01 m02]
+ * [0 1 dy] [m10 m11 m12]
+ * [0 0  1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preTranslate = function(dx, dy) {
+  this.m02_ += dx;
+  this.m12_ += dy;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a rotation transformation around an anchor
+ * point.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.rotate = function(theta, x, y) {
+  return this.concatenate(
+      goog.graphics.AffineTransform.getRotateInstance(theta, x, y));
+};
+
+
+/**
+ * Pre-concatenates this transform with a rotation transformation around an
+ * anchor point.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preRotate = function(theta, x, y) {
+  return this.preConcatenate(
+      goog.graphics.AffineTransform.getRotateInstance(theta, x, y));
+};
+
+
+/**
+ * Concatenates this transform with a shear transformation.
+ *
+ * @param {number} shx The x shear factor.
+ * @param {number} shy The y shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.shear = function(shx, shy) {
+  var m00 = this.m00_;
+  var m10 = this.m10_;
+  this.m00_ += shy * this.m01_;
+  this.m10_ += shy * this.m11_;
+  this.m01_ += shx * m00;
+  this.m11_ += shx * m10;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a shear transformation.
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [  1 shx 0] [m00 m01 m02]
+ * [shy   1 0] [m10 m11 m12]
+ * [  0   0 1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} shx The x shear factor.
+ * @param {number} shy The y shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preShear = function(shx, shy) {
+  var m00 = this.m00_;
+  var m01 = this.m01_;
+  var m02 = this.m02_;
+  this.m00_ += shx * this.m10_;
+  this.m01_ += shx * this.m11_;
+  this.m02_ += shx * this.m12_;
+  this.m10_ += shy * m00;
+  this.m11_ += shy * m01;
+  this.m12_ += shy * m02;
+  return this;
+};
+
+
+/**
+ * @return {string} A string representation of this transform. The format of
+ *     of the string is compatible with SVG matrix notation, i.e.
+ *     "matrix(a,b,c,d,e,f)".
+ * @override
+ */
+goog.graphics.AffineTransform.prototype.toString = function() {
+  return 'matrix(' +
+      [this.m00_, this.m10_, this.m01_, this.m11_, this.m02_, this.m12_].join(
+          ',') +
+      ')';
+};
+
+
+/**
+ * @return {number} The scaling factor in the x-direction (m00).
+ */
+goog.graphics.AffineTransform.prototype.getScaleX = function() {
+  return this.m00_;
+};
+
+
+/**
+ * @return {number} The scaling factor in the y-direction (m11).
+ */
+goog.graphics.AffineTransform.prototype.getScaleY = function() {
+  return this.m11_;
+};
+
+
+/**
+ * @return {number} The translation in the x-direction (m02).
+ */
+goog.graphics.AffineTransform.prototype.getTranslateX = function() {
+  return this.m02_;
+};
+
+
+/**
+ * @return {number} The translation in the y-direction (m12).
+ */
+goog.graphics.AffineTransform.prototype.getTranslateY = function() {
+  return this.m12_;
+};
+
+
+/**
+ * @return {number} The shear factor in the x-direction (m01).
+ */
+goog.graphics.AffineTransform.prototype.getShearX = function() {
+  return this.m01_;
+};
+
+
+/**
+ * @return {number} The shear factor in the y-direction (m10).
+ */
+goog.graphics.AffineTransform.prototype.getShearY = function() {
+  return this.m10_;
+};
+
+
+/**
+ * Concatenates an affine transform to this transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to concatenate.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.concatenate = function(tx) {
+  var m0 = this.m00_;
+  var m1 = this.m01_;
+  this.m00_ = tx.m00_ * m0 + tx.m10_ * m1;
+  this.m01_ = tx.m01_ * m0 + tx.m11_ * m1;
+  this.m02_ += tx.m02_ * m0 + tx.m12_ * m1;
+
+  m0 = this.m10_;
+  m1 = this.m11_;
+  this.m10_ = tx.m00_ * m0 + tx.m10_ * m1;
+  this.m11_ = tx.m01_ * m0 + tx.m11_ * m1;
+  this.m12_ += tx.m02_ * m0 + tx.m12_ * m1;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates an affine transform to this transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to preconcatenate.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preConcatenate = function(tx) {
+  var m0 = this.m00_;
+  var m1 = this.m10_;
+  this.m00_ = tx.m00_ * m0 + tx.m01_ * m1;
+  this.m10_ = tx.m10_ * m0 + tx.m11_ * m1;
+
+  m0 = this.m01_;
+  m1 = this.m11_;
+  this.m01_ = tx.m00_ * m0 + tx.m01_ * m1;
+  this.m11_ = tx.m10_ * m0 + tx.m11_ * m1;
+
+  m0 = this.m02_;
+  m1 = this.m12_;
+  this.m02_ = tx.m00_ * m0 + tx.m01_ * m1 + tx.m02_;
+  this.m12_ = tx.m10_ * m0 + tx.m11_ * m1 + tx.m12_;
+  return this;
+};
+
+
+/**
+ * Transforms an array of coordinates by this transform and stores the result
+ * into a destination array.
+ *
+ * @param {!Array<number>} src The array containing the source points
+ *     as x, y value pairs.
+ * @param {number} srcOff The offset to the first point to be transformed.
+ * @param {!Array<number>} dst The array into which to store the transformed
+ *     point pairs.
+ * @param {number} dstOff The offset of the location of the first transformed
+ *     point in the destination array.
+ * @param {number} numPts The number of points to tranform.
+ */
+goog.graphics.AffineTransform.prototype.transform = function(src, srcOff, dst,
+    dstOff, numPts) {
+  var i = srcOff;
+  var j = dstOff;
+  var srcEnd = srcOff + 2 * numPts;
+  while (i < srcEnd) {
+    var x = src[i++];
+    var y = src[i++];
+    dst[j++] = x * this.m00_ + y * this.m01_ + this.m02_;
+    dst[j++] = x * this.m10_ + y * this.m11_ + this.m12_;
+  }
+};
+
+
+/**
+ * @return {number} The determinant of this transform.
+ */
+goog.graphics.AffineTransform.prototype.getDeterminant = function() {
+  return this.m00_ * this.m11_ - this.m01_ * this.m10_;
+};
+
+
+/**
+ * Returns whether the transform is invertible. A transform is not invertible
+ * if the determinant is 0 or any value is non-finite or NaN.
+ *
+ * @return {boolean} Whether the transform is invertible.
+ */
+goog.graphics.AffineTransform.prototype.isInvertible = function() {
+  var det = this.getDeterminant();
+  return goog.math.isFiniteNumber(det) &&
+      goog.math.isFiniteNumber(this.m02_) &&
+      goog.math.isFiniteNumber(this.m12_) &&
+      det != 0;
+};
+
+
+/**
+ * @return {!goog.graphics.AffineTransform} An AffineTransform object
+ *     representing the inverse transformation.
+ */
+goog.graphics.AffineTransform.prototype.createInverse = function() {
+  var det = this.getDeterminant();
+  return new goog.graphics.AffineTransform(
+      this.m11_ / det,
+      -this.m10_ / det,
+      -this.m01_ / det,
+      this.m00_ / det,
+      (this.m01_ * this.m12_ - this.m11_ * this.m02_) / det,
+      (this.m10_ * this.m02_ - this.m00_ * this.m12_) / det);
+};
+
+
+/**
+ * Creates a transform representing a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} A transform representing a scaling
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getScaleInstance = function(sx, sy) {
+  return new goog.graphics.AffineTransform().setToScale(sx, sy);
+};
+
+
+/**
+ * Creates a transform representing a translation transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} A transform representing a
+ *     translation transformation.
+ */
+goog.graphics.AffineTransform.getTranslateInstance = function(dx, dy) {
+  return new goog.graphics.AffineTransform().setToTranslation(dx, dy);
+};
+
+
+/**
+ * Creates a transform representing a shearing transformation.
+ *
+ * @param {number} shx The x-axis shear factor.
+ * @param {number} shy The y-axis shear factor.
+ * @return {!goog.graphics.AffineTransform} A transform representing a shearing
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getShearInstance = function(shx, shy) {
+  return new goog.graphics.AffineTransform().setToShear(shx, shy);
+};
+
+
+/**
+ * Creates a transform representing a rotation transformation.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} A transform representing a rotation
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getRotateInstance = function(theta, x, y) {
+  return new goog.graphics.AffineTransform().setToRotation(theta, x, y);
+};
+
+
+/**
+ * Sets this transform to a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToScale = function(sx, sy) {
+  return this.setTransform(sx, 0, 0, sy, 0, 0);
+};
+
+
+/**
+ * Sets this transform to a translation transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToTranslation = function(dx, dy) {
+  return this.setTransform(1, 0, 0, 1, dx, dy);
+};
+
+
+/**
+ * Sets this transform to a shearing transformation.
+ *
+ * @param {number} shx The x-axis shear factor.
+ * @param {number} shy The y-axis shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToShear = function(shx, shy) {
+  return this.setTransform(1, shy, shx, 1, 0, 0);
+};
+
+
+/**
+ * Sets this transform to a rotation transformation.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToRotation = function(theta, x, y) {
+  var cos = Math.cos(theta);
+  var sin = Math.sin(theta);
+  return this.setTransform(cos, sin, -sin, cos,
+      x - x * cos + y * sin, y - x * sin - y * cos);
+};
+
+
+/**
+ * Compares two affine transforms for equality.
+ *
+ * @param {goog.graphics.AffineTransform} tx The other affine transform.
+ * @return {boolean} whether the two transforms are equal.
+ */
+goog.graphics.AffineTransform.prototype.equals = function(tx) {
+  if (this == tx) {
+    return true;
+  }
+  if (!tx) {
+    return false;
+  }
+  return this.m00_ == tx.m00_ &&
+      this.m01_ == tx.m01_ &&
+      this.m02_ == tx.m02_ &&
+      this.m10_ == tx.m10_ &&
+      this.m11_ == tx.m11_ &&
+      this.m12_ == tx.m12_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/canvaselement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/canvaselement.js 
b/externs/GCL/externs/goog/graphics/canvaselement.js
new file mode 100644
index 0000000..6c400db
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/canvaselement.js
@@ -0,0 +1,812 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+
+/**
+ * @fileoverview Objects representing shapes drawn on a canvas.
+ * @author [email protected] (Robby Walker)
+ */
+
+goog.provide('goog.graphics.CanvasEllipseElement');
+goog.provide('goog.graphics.CanvasGroupElement');
+goog.provide('goog.graphics.CanvasImageElement');
+goog.provide('goog.graphics.CanvasPathElement');
+goog.provide('goog.graphics.CanvasRectElement');
+goog.provide('goog.graphics.CanvasTextElement');
+
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.graphics.EllipseElement');
+goog.require('goog.graphics.GroupElement');
+goog.require('goog.graphics.ImageElement');
+goog.require('goog.graphics.Path');
+goog.require('goog.graphics.PathElement');
+goog.require('goog.graphics.RectElement');
+goog.require('goog.graphics.TextElement');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.math');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+
+
+
+/**
+ * Object representing a group of objects in a canvas.
+ * This is an implementation of the goog.graphics.GroupElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.GroupElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.CanvasGroupElement = function(graphics) {
+  goog.graphics.GroupElement.call(this, null, graphics);
+
+
+  /**
+   * Children contained by this group.
+   * @type {Array<goog.graphics.Element>}
+   * @private
+   */
+  this.children_ = [];
+};
+goog.inherits(goog.graphics.CanvasGroupElement, goog.graphics.GroupElement);
+
+
+/**
+ * Remove all drawing elements from the group.
+ * @override
+ */
+goog.graphics.CanvasGroupElement.prototype.clear = function() {
+  if (this.children_.length) {
+    this.children_.length = 0;
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Set the size of the group element.
+ * @param {number|string} width The width of the group element.
+ * @param {number|string} height The height of the group element.
+ * @override
+ */
+goog.graphics.CanvasGroupElement.prototype.setSize = function(width, height) {
+  // Do nothing.
+};
+
+
+/**
+ * Append a child to the group.  Does not draw it
+ * @param {goog.graphics.Element} element The child to append.
+ */
+goog.graphics.CanvasGroupElement.prototype.appendChild = function(element) {
+  this.children_.push(element);
+};
+
+
+/**
+ * Draw the group.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasGroupElement.prototype.draw = function(ctx) {
+  for (var i = 0, len = this.children_.length; i < len; i++) {
+    this.getGraphics().drawElement(this.children_[i]);
+  }
+};
+
+
+
+/**
+ * Thin wrapper for canvas ellipse elements.
+ * This is an implementation of the goog.graphics.EllipseElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics  The graphics creating
+ *     this element.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.EllipseElement}
+ * @final
+ */
+goog.graphics.CanvasEllipseElement = function(element, graphics,
+    cx, cy, rx, ry, stroke, fill) {
+  goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * X coordinate of the ellipse center.
+   * @type {number}
+   * @private
+   */
+  this.cx_ = cx;
+
+
+  /**
+   * Y coordinate of the ellipse center.
+   * @type {number}
+   * @private
+   */
+  this.cy_ = cy;
+
+
+  /**
+   * Radius length for the x-axis.
+   * @type {number}
+   * @private
+   */
+  this.rx_ = rx;
+
+
+  /**
+   * Radius length for the y-axis.
+   * @type {number}
+   * @private
+   */
+  this.ry_ = ry;
+
+
+  /**
+   * Internal path approximating an ellipse.
+   * @type {goog.graphics.Path}
+   * @private
+   */
+  this.path_ = new goog.graphics.Path();
+  this.setUpPath_();
+
+  /**
+   * Internal path element that actually does the drawing.
+   * @type {goog.graphics.CanvasPathElement}
+   * @private
+   */
+  this.pathElement_ = new goog.graphics.CanvasPathElement(null, graphics,
+      this.path_, stroke, fill);
+};
+goog.inherits(goog.graphics.CanvasEllipseElement, 
goog.graphics.EllipseElement);
+
+
+/**
+ * Sets up the path.
+ * @private
+ */
+goog.graphics.CanvasEllipseElement.prototype.setUpPath_ = function() {
+  this.path_.clear();
+  this.path_.moveTo(this.cx_ + goog.math.angleDx(0, this.rx_),
+                    this.cy_ + goog.math.angleDy(0, this.ry_));
+  this.path_.arcTo(this.rx_, this.ry_, 0, 360);
+  this.path_.close();
+};
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @override
+ */
+goog.graphics.CanvasEllipseElement.prototype.setCenter = function(cx, cy) {
+  this.cx_ = cx;
+  this.cy_ = cy;
+  this.setUpPath_();
+  this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_));
+};
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx Center X coordinate.
+ * @param {number} ry Center Y coordinate.
+ * @override
+ */
+goog.graphics.CanvasEllipseElement.prototype.setRadius = function(rx, ry) {
+  this.rx_ = rx;
+  this.ry_ = ry;
+  this.setUpPath_();
+  this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_));
+};
+
+
+/**
+ * Draw the ellipse.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasEllipseElement.prototype.draw = function(ctx) {
+  this.pathElement_.draw(ctx);
+};
+
+
+
+/**
+ * Thin wrapper for canvas rectangle elements.
+ * This is an implementation of the goog.graphics.RectElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} w Width of rectangle.
+ * @param {number} h Height of rectangle.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.RectElement}
+ * @final
+ */
+goog.graphics.CanvasRectElement = function(element, graphics, x, y, w, h,
+    stroke, fill) {
+  goog.graphics.RectElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * X coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.x_ = x;
+
+
+  /**
+   * Y coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.y_ = y;
+
+
+  /**
+   * Width of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.w_ = w;
+
+
+  /**
+   * Height of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.h_ = h;
+};
+goog.inherits(goog.graphics.CanvasRectElement, goog.graphics.RectElement);
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.CanvasRectElement.prototype.setPosition = function(x, y) {
+  this.x_ = x;
+  this.y_ = y;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Whether the rectangle has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasRectElement.prototype.drawn_ = false;
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.CanvasRectElement.prototype.setSize = function(width, height) {
+  this.w_ = width;
+  this.h_ = height;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the rectangle.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasRectElement.prototype.draw = function(ctx) {
+  this.drawn_ = true;
+  ctx.beginPath();
+  ctx.moveTo(this.x_, this.y_);
+  ctx.lineTo(this.x_, this.y_ + this.h_);
+  ctx.lineTo(this.x_ + this.w_, this.y_ + this.h_);
+  ctx.lineTo(this.x_ + this.w_, this.y_);
+  ctx.closePath();
+};
+
+
+
+/**
+ * Thin wrapper for canvas path elements.
+ * This is an implementation of the goog.graphics.PathElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.PathElement}
+ * @final
+ */
+goog.graphics.CanvasPathElement = function(element, graphics, path, stroke,
+    fill) {
+  goog.graphics.PathElement.call(this, element, graphics, stroke, fill);
+
+  this.setPath(path);
+};
+goog.inherits(goog.graphics.CanvasPathElement, goog.graphics.PathElement);
+
+
+/**
+ * Whether the shape has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasPathElement.prototype.drawn_ = false;
+
+
+/**
+ * The path to draw.
+ * @type {goog.graphics.Path}
+ * @private
+ */
+goog.graphics.CanvasPathElement.prototype.path_;
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @override
+ */
+goog.graphics.CanvasPathElement.prototype.setPath = function(path) {
+  this.path_ = path.isSimple() ? path :
+      goog.graphics.Path.createSimplifiedPath(path);
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the path.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.CanvasPathElement.prototype.draw = function(ctx) {
+  this.drawn_ = true;
+
+  ctx.beginPath();
+  this.path_.forEachSegment(function(segment, args) {
+    switch (segment) {
+      case goog.graphics.Path.Segment.MOVETO:
+        ctx.moveTo(args[0], args[1]);
+        break;
+      case goog.graphics.Path.Segment.LINETO:
+        for (var i = 0; i < args.length; i += 2) {
+          ctx.lineTo(args[i], args[i + 1]);
+        }
+        break;
+      case goog.graphics.Path.Segment.CURVETO:
+        for (var i = 0; i < args.length; i += 6) {
+          ctx.bezierCurveTo(args[i], args[i + 1], args[i + 2],
+              args[i + 3], args[i + 4], args[i + 5]);
+        }
+        break;
+      case goog.graphics.Path.Segment.ARCTO:
+        throw Error('Canvas paths cannot contain arcs');
+      case goog.graphics.Path.Segment.CLOSE:
+        ctx.closePath();
+        break;
+    }
+  });
+};
+
+
+
+/**
+ * Thin wrapper for canvas text elements.
+ * This is an implementation of the goog.graphics.TextElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {!goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {?string} align Horizontal alignment: left (default), center, right.
+ * @param {!goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.TextElement}
+ * @final
+ */
+goog.graphics.CanvasTextElement = function(graphics, text, x1, y1, x2, y2,
+    align, font, stroke, fill) {
+  var element = goog.dom.createDom(goog.dom.TagName.DIV, {
+    'style': 'display:table;position:absolute;padding:0;margin:0;border:0'
+  });
+  goog.graphics.TextElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * The text to draw.
+   * @type {string}
+   * @private
+   */
+  this.text_ = text;
+
+  /**
+   * X coordinate of the start of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.x1_ = x1;
+
+  /**
+   * Y coordinate of the start of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.y1_ = y1;
+
+  /**
+   * X coordinate of the end of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.x2_ = x2;
+
+  /**
+   * Y coordinate of the end of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.y2_ = y2;
+
+  /**
+   * Horizontal alignment: left (default), center, right.
+   * @type {string}
+   * @private
+   */
+  this.align_ = align || 'left';
+
+  /**
+   * Font object describing the font properties.
+   * @type {goog.graphics.Font}
+   * @private
+   */
+  this.font_ = font;
+
+  /**
+   * The inner element that contains the text.
+   * @type {Element}
+   * @private
+   */
+  this.innerElement_ = goog.dom.createDom(goog.dom.TagName.DIV, {
+    'style': 'display:table-cell;padding: 0;margin: 0;border: 0'
+  });
+
+  this.updateStyle_();
+  this.updateText_();
+
+  // Append to the DOM.
+  graphics.getElement().appendChild(element);
+  element.appendChild(this.innerElement_);
+};
+goog.inherits(goog.graphics.CanvasTextElement, goog.graphics.TextElement);
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setText = function(text) {
+  this.text_ = text;
+  this.updateText_();
+};
+
+
+/**
+ * Sets the fill for this element.
+ * @param {goog.graphics.Fill} fill The fill object.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setFill = function(fill) {
+  this.fill = fill;
+  var element = this.getElement();
+  if (element) {
+    element.style.color = fill.getColor() || fill.getColor1();
+  }
+};
+
+
+/**
+ * Sets the stroke for this element.
+ * @param {goog.graphics.Stroke} stroke The stroke object.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setStroke = function(stroke) {
+  // Ignore stroke
+};
+
+
+/**
+ * Draw the text.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasTextElement.prototype.draw = function(ctx) {
+  // Do nothing - the text is already drawn.
+};
+
+
+/**
+ * Update the styles of the DIVs.
+ * @private
+ */
+goog.graphics.CanvasTextElement.prototype.updateStyle_ = function() {
+  var x1 = this.x1_;
+  var x2 = this.x2_;
+  var y1 = this.y1_;
+  var y2 = this.y2_;
+  var align = this.align_;
+  var font = this.font_;
+  var style = this.getElement().style;
+  var scaleX = this.getGraphics().getPixelScaleX();
+  var scaleY = this.getGraphics().getPixelScaleY();
+
+  if (x1 == x2) {
+    // Special case vertical text
+    style.lineHeight = '90%';
+
+    this.innerElement_.style.verticalAlign = align == 'center' ? 'middle' :
+        align == 'left' ? (y1 < y2 ? 'top' : 'bottom') :
+        y1 < y2 ? 'bottom' : 'top';
+    style.textAlign = 'center';
+
+    var w = font.size * scaleX;
+    style.top = Math.round(Math.min(y1, y2) * scaleY) + 'px';
+    style.left = Math.round((x1 - w / 2) * scaleX) + 'px';
+    style.width = Math.round(w) + 'px';
+    style.height = Math.abs(y1 - y2) * scaleY + 'px';
+
+    style.fontSize = font.size * 0.6 * scaleY + 'pt';
+  } else {
+    style.lineHeight = '100%';
+    this.innerElement_.style.verticalAlign = 'top';
+    style.textAlign = align;
+
+    style.top = Math.round(((y1 + y2) / 2 - font.size * 2 / 3) * scaleY) + 
'px';
+    style.left = Math.round(x1 * scaleX) + 'px';
+    style.width = Math.round(Math.abs(x2 - x1) * scaleX) + 'px';
+    style.height = 'auto';
+
+    style.fontSize = font.size * scaleY + 'pt';
+  }
+
+  style.fontWeight = font.bold ? 'bold' : 'normal';
+  style.fontStyle = font.italic ? 'italic' : 'normal';
+  style.fontFamily = font.family;
+
+  var fill = this.getFill();
+  style.color = fill.getColor() || fill.getColor1();
+};
+
+
+/**
+ * Update the text content.
+ * @private
+ */
+goog.graphics.CanvasTextElement.prototype.updateText_ = function() {
+  if (this.x1_ == this.x2_) {
+    // Special case vertical text
+    var html =
+        goog.array.map(
+            this.text_.split(''),
+            function(entry) { return goog.string.htmlEscape(entry); })
+        .join('<br>');
+    // Creating a SafeHtml for each character would be quite expensive, and 
it's
+    // obvious that this is safe, so an unchecked conversion is appropriate.
+    var safeHtml = goog.html.uncheckedconversions
+        .safeHtmlFromStringKnownToSatisfyTypeContract(
+            goog.string.Const.from('Concatenate escaped chars and <br>'),
+            html);
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.innerElement_), safeHtml);
+  } else {
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.innerElement_),
+        goog.html.SafeHtml.htmlEscape(this.text_));
+  }
+};
+
+
+
+/**
+ * Thin wrapper for canvas image elements.
+ * This is an implementation of the goog.graphics.ImageElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} w Width of rectangle.
+ * @param {number} h Height of rectangle.
+ * @param {string} src Source of the image.
+ * @constructor
+ * @extends {goog.graphics.ImageElement}
+ * @final
+ */
+goog.graphics.CanvasImageElement = function(element, graphics, x, y, w, h,
+    src) {
+  goog.graphics.ImageElement.call(this, element, graphics);
+
+  /**
+   * X coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.x_ = x;
+
+
+  /**
+   * Y coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.y_ = y;
+
+
+  /**
+   * Width of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.w_ = w;
+
+
+  /**
+   * Height of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.h_ = h;
+
+
+  /**
+   * URL of the image source.
+   * @type {string}
+   * @private
+   */
+  this.src_ = src;
+};
+goog.inherits(goog.graphics.CanvasImageElement, goog.graphics.ImageElement);
+
+
+/**
+ * Whether the image has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasImageElement.prototype.drawn_ = false;
+
+
+/**
+ * Update the position of the image.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setPosition = function(x, y) {
+  this.x_ = x;
+  this.y_ = y;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Update the size of the image.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setSize = function(width, height) {
+  this.w_ = width;
+  this.h_ = height;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setSource = function(src) {
+  this.src_ = src;
+  if (this.drawn_) {
+    // TODO(robbyw): Probably need to reload the image here.
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the image.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasImageElement.prototype.draw = function(ctx) {
+  if (this.img_) {
+    if (this.w_ && this.h_) {
+      // If the image is already loaded, draw it.
+      ctx.drawImage(this.img_, this.x_, this.y_, this.w_, this.h_);
+    }
+    this.drawn_ = true;
+
+  } else {
+    // Otherwise, load it.
+    var img = new Image();
+    img.onload = goog.bind(this.handleImageLoad_, this, img);
+    // TODO(robbyw): Handle image load errors.
+    img.src = this.src_;
+  }
+};
+
+
+/**
+ * Handle an image load.
+ * @param {Element} img The image element that finished loading.
+ * @private
+ */
+goog.graphics.CanvasImageElement.prototype.handleImageLoad_ = function(img) {
+  this.img_ = img;
+
+  // TODO(robbyw): Add a small delay to catch batched images
+  this.getGraphics().redraw();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/canvasgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/canvasgraphics.js 
b/externs/GCL/externs/goog/graphics/canvasgraphics.js
new file mode 100644
index 0000000..2c55938
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/canvasgraphics.js
@@ -0,0 +1,670 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+
+/**
+ * @fileoverview CanvasGraphics sub class that uses the canvas tag for drawing.
+ * @author [email protected] (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.CanvasGraphics');
+
+
+goog.require('goog.dom.TagName');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics.AbstractGraphics');
+goog.require('goog.graphics.CanvasEllipseElement');
+goog.require('goog.graphics.CanvasGroupElement');
+goog.require('goog.graphics.CanvasImageElement');
+goog.require('goog.graphics.CanvasPathElement');
+goog.require('goog.graphics.CanvasRectElement');
+goog.require('goog.graphics.CanvasTextElement');
+goog.require('goog.graphics.SolidFill');
+goog.require('goog.math.Size');
+goog.require('goog.style');
+
+
+
+/**
+ * A Graphics implementation for drawing using canvas.
+ * @param {string|number} width The (non-zero) width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The (non-zero) height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The coordinate height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.graphics.AbstractGraphics}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.CanvasGraphics = function(width, height,
+                                        opt_coordWidth, opt_coordHeight,
+                                        opt_domHelper) {
+  goog.graphics.AbstractGraphics.call(this, width, height,
+                                      opt_coordWidth, opt_coordHeight,
+                                      opt_domHelper);
+};
+goog.inherits(goog.graphics.CanvasGraphics, goog.graphics.AbstractGraphics);
+
+
+/**
+ * Sets the fill for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element
+ *     wrapper.
+ * @param {goog.graphics.Fill} fill The fill object.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementFill = function(element,
+    fill) {
+  this.redraw();
+};
+
+
+/**
+ * Sets the stroke for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element
+ *     wrapper.
+ * @param {goog.graphics.Stroke} stroke The stroke object.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementStroke = function(
+    element, stroke) {
+  this.redraw();
+};
+
+
+/**
+ * Set the translation and rotation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementTransform = function(element,
+    x, y, angle, centerX, centerY) {
+  this.redraw();
+};
+
+
+/**
+ * Set the transformation of an element.
+ *
+ * Note that in this implementation this method just calls this.redraw()
+ * and the affineTransform param is unused.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementAffineTransform =
+    function(element, affineTransform) {
+  this.redraw();
+};
+
+
+/**
+ * Push an element transform on to the transform stack.
+ * @param {goog.graphics.Element} element The transformed element.
+ */
+goog.graphics.CanvasGraphics.prototype.pushElementTransform = function(
+    element) {
+  var ctx = this.getContext();
+  ctx.save();
+
+  var transform = element.getTransform();
+
+  // TODO(robbyw): Test for unsupported transforms i.e. skews.
+  var tx = transform.getTranslateX();
+  var ty = transform.getTranslateY();
+  if (tx || ty) {
+    ctx.translate(tx, ty);
+  }
+
+  var sinTheta = transform.getShearY();
+  if (sinTheta) {
+    ctx.rotate(Math.asin(sinTheta));
+  }
+};
+
+
+/**
+ * Pop an element transform off of the transform stack.
+ */
+goog.graphics.CanvasGraphics.prototype.popElementTransform = function() {
+  this.getContext().restore();
+};
+
+
+/**
+ * Creates the DOM representation of the graphics area.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.createDom = function() {
+  var element = this.dom_.createDom(goog.dom.TagName.DIV,
+      {'style': 'position:relative;overflow:hidden'});
+  this.setElementInternal(element);
+
+  this.canvas_ = this.dom_.createDom(goog.dom.TagName.CANVAS);
+  element.appendChild(this.canvas_);
+
+  /**
+   * The main canvas element.
+   * @type {goog.graphics.CanvasGroupElement}
+   */
+  this.canvasElement = new goog.graphics.CanvasGroupElement(this);
+
+  this.lastGroup_ = this.canvasElement;
+  this.redrawTimeout_ = 0;
+
+  this.updateSize();
+};
+
+
+/**
+ * Clears the drawing context object in response to actions that make the old
+ * context invalid - namely resize of the canvas element.
+ * @private
+ */
+goog.graphics.CanvasGraphics.prototype.clearContext_ = function() {
+  this.context_ = null;
+};
+
+
+/**
+ * Returns the drawing context.
+ * @return {Object} The canvas element rendering context.
+ */
+goog.graphics.CanvasGraphics.prototype.getContext = function() {
+  if (!this.getElement()) {
+    this.createDom();
+  }
+  if (!this.context_) {
+    this.context_ = this.canvas_.getContext('2d');
+    this.context_.save();
+  }
+  return this.context_;
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setCoordOrigin = function(left, top) {
+  this.coordLeft = left;
+  this.coordTop = top;
+  this.redraw();
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setCoordSize = function(coordWidth,
+                                                               coordHeight) {
+  goog.graphics.CanvasGraphics.superClass_.setCoordSize.apply(this, arguments);
+  this.redraw();
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setSize = function(pixelWidth,
+    pixelHeight) {
+  this.width = pixelWidth;
+  this.height = pixelHeight;
+
+  this.updateSize();
+  this.redraw();
+};
+
+
+/** @override */
+goog.graphics.CanvasGraphics.prototype.getPixelSize = function() {
+  // goog.style.getSize does not work for Canvas elements.  We
+  // have to compute the size manually if it is percentage based.
+  var width = this.width;
+  var height = this.height;
+  var computeWidth = goog.isString(width) && width.indexOf('%') != -1;
+  var computeHeight = goog.isString(height) && height.indexOf('%') != -1;
+
+  if (!this.isInDocument() && (computeWidth || computeHeight)) {
+    return null;
+  }
+
+  var parent;
+  var parentSize;
+
+  if (computeWidth) {
+    parent = /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = goog.style.getSize(parent);
+    width = parseFloat(/** @type {string} */ (width)) * parentSize.width / 100;
+  }
+
+  if (computeHeight) {
+    parent = parent || /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = parentSize || goog.style.getSize(parent);
+    height = parseFloat(/** @type {string} */ (height)) * parentSize.height /
+        100;
+  }
+
+  return new goog.math.Size(/** @type {number} */ (width),
+      /** @type {number} */ (height));
+};
+
+
+/**
+ * Update the size of the canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.updateSize = function() {
+  goog.style.setSize(this.getElement(), this.width, this.height);
+
+  var pixels = this.getPixelSize();
+  if (pixels) {
+    goog.style.setSize(this.canvas_,
+        /** @type {number} */ (pixels.width),
+        /** @type {number} */ (pixels.height));
+    this.canvas_.width = pixels.width;
+    this.canvas_.height = pixels.height;
+    this.clearContext_();
+  }
+};
+
+
+/**
+ * Reset the canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.reset = function() {
+  var ctx = this.getContext();
+  ctx.restore();
+  var size = this.getPixelSize();
+  if (size.width && size.height) {
+    ctx.clearRect(0, 0, size.width, size.height);
+  }
+  ctx.save();
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.clear = function() {
+  this.reset();
+  this.canvasElement.clear();
+  var el = this.getElement();
+
+  // Remove all children (text nodes) except the canvas (which is at index 0)
+  while (el.childNodes.length > 1) {
+    el.removeChild(el.lastChild);
+  }
+};
+
+
+/**
+ * Redraw the entire canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.redraw = function() {
+  if (this.preventRedraw_) {
+    this.needsRedraw_ = true;
+    return;
+  }
+
+  if (this.isInDocument()) {
+    this.reset();
+
+    if (this.coordWidth) {
+      var pixels = this.getPixelSize();
+      this.getContext().scale(pixels.width / this.coordWidth,
+          pixels.height / this.coordHeight);
+    }
+    if (this.coordLeft || this.coordTop) {
+      this.getContext().translate(-this.coordLeft, -this.coordTop);
+    }
+    this.pushElementTransform(this.canvasElement);
+    this.canvasElement.draw(this.context_);
+    this.popElementTransform();
+  }
+};
+
+
+/**
+ * Draw an element, including any stroke or fill.
+ * @param {goog.graphics.Element} element The element to draw.
+ */
+goog.graphics.CanvasGraphics.prototype.drawElement = function(element) {
+  if (element instanceof goog.graphics.CanvasTextElement) {
+    // Don't draw text since that is not implemented using canvas.
+    return;
+  }
+
+  var ctx = this.getContext();
+  this.pushElementTransform(element);
+
+  if (!element.getFill || !element.getStroke) {
+    // Draw without stroke or fill (e.g. the element is an image or group).
+    element.draw(ctx);
+    this.popElementTransform();
+    return;
+  }
+
+  var fill = element.getFill();
+  if (fill) {
+    if (fill instanceof goog.graphics.SolidFill) {
+      if (fill.getOpacity() != 0) {
+        ctx.globalAlpha = fill.getOpacity();
+        ctx.fillStyle = fill.getColor();
+        element.draw(ctx);
+        ctx.fill();
+        ctx.globalAlpha = 1;
+      }
+    } else { // (fill instanceof goog.graphics.LinearGradient)
+      var linearGradient = ctx.createLinearGradient(fill.getX1(), fill.getY1(),
+          fill.getX2(), fill.getY2());
+      linearGradient.addColorStop(0.0, fill.getColor1());
+      linearGradient.addColorStop(1.0, fill.getColor2());
+
+      ctx.fillStyle = linearGradient;
+      element.draw(ctx);
+      ctx.fill();
+    }
+  }
+
+  var stroke = element.getStroke();
+  if (stroke) {
+    element.draw(ctx);
+    ctx.strokeStyle = stroke.getColor();
+
+    var width = stroke.getWidth();
+    if (goog.isString(width) && width.indexOf('px') != -1) {
+      width = parseFloat(width) / this.getPixelScaleX();
+    }
+    ctx.lineWidth = width;
+
+    ctx.stroke();
+  }
+
+  this.popElementTransform();
+};
+
+
+/**
+ * Append an element.
+ *
+ * @param {goog.graphics.Element} element The element to draw.
+ * @param {goog.graphics.GroupElement|undefined} group The group to draw
+ *     it in. If null or undefined, defaults to the root group.
+ * @protected
+ */
+goog.graphics.CanvasGraphics.prototype.append = function(element, group) {
+  group = group || this.canvasElement;
+  group.appendChild(element);
+
+  if (this.isDrawable(group)) {
+    this.drawElement(element);
+  }
+};
+
+
+/**
+ * Draw an ellipse.
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to.  If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.EllipseElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawEllipse = function(cx, cy, rx, ry,
+    stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasEllipseElement(null, this,
+      cx, cy, rx, ry, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a rectangle.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.RectElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawRect = function(x, y, width, height,
+    stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasRectElement(null, this,
+      x, y, width, height, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw an image.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of image.
+ * @param {number} height Height of image.
+ * @param {string} src Source of the image.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.ImageElement} The newly created element.
+ */
+goog.graphics.CanvasGraphics.prototype.drawImage = function(x, y, width, 
height,
+    src, opt_group) {
+  var element = new goog.graphics.CanvasImageElement(null, this, x, y, width,
+      height, src);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {?string} align Horizontal alignment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.TextElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawTextOnLine = function(
+    text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasTextElement(this,
+      text, x1, y1, x2, y2, align, /** @type {!goog.graphics.Font} */ (font),
+      stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.PathElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawPath = function(path, stroke, fill,
+    opt_group) {
+  var element = new goog.graphics.CanvasPathElement(null, this,
+      path, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * @param {goog.graphics.GroupElement} group The group to possibly
+ *     draw to.
+ * @return {boolean} Whether drawing can occur now.
+ */
+goog.graphics.CanvasGraphics.prototype.isDrawable = function(group) {
+  return this.isInDocument() && !this.redrawTimeout_ &&
+      !this.isRedrawRequired(group);
+};
+
+
+/**
+ * Returns true if drawing to the given group means a redraw is required.
+ * @param {goog.graphics.GroupElement} group The group to draw to.
+ * @return {boolean} Whether drawing to this group should force a redraw.
+ */
+goog.graphics.CanvasGraphics.prototype.isRedrawRequired = function(group) {
+  // TODO(robbyw): Moving up to any parent of lastGroup should not force 
redraw.
+  return group != this.canvasElement && group != this.lastGroup_;
+};
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.CanvasGroupElement} The newly created group.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.createGroup = function(opt_group) {
+  var group = new goog.graphics.CanvasGroupElement(this);
+
+  opt_group = opt_group || this.canvasElement;
+
+  // TODO(robbyw): Moving up to any parent group should not force redraw.
+  if (opt_group == this.canvasElement || opt_group == this.lastGroup_) {
+    this.lastGroup_ = group;
+  }
+
+  this.append(group, opt_group);
+
+  return group;
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated
+ * area. The way text length is measured is by writing it into a div that is
+ * after the visible area, measure the div width, and immediatly erase the
+ * written value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.getTextWidth = goog.abstractMethod;
+
+
+/**
+ * Disposes of the component by removing event handlers, detacing DOM nodes 
from
+ * the document body, and removing references to them.
+ * @override
+ * @protected
+ */
+goog.graphics.CanvasGraphics.prototype.disposeInternal = function() {
+  this.context_ = null;
+  goog.graphics.CanvasGraphics.superClass_.disposeInternal.call(this);
+};
+
+
+/** @override */
+goog.graphics.CanvasGraphics.prototype.enterDocument = function() {
+  var oldPixelSize = this.getPixelSize();
+  goog.graphics.CanvasGraphics.superClass_.enterDocument.call(this);
+  if (!oldPixelSize) {
+    this.updateSize();
+    this.dispatchEvent(goog.events.EventType.RESIZE);
+  }
+  this.redraw();
+};
+
+
+/**
+ * Start preventing redraws - useful for chaining large numbers of changes
+ * together.  Not guaranteed to do anything - i.e. only use this for
+ * optimization of a single code path.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.suspend = function() {
+  this.preventRedraw_ = true;
+};
+
+
+/**
+ * Stop preventing redraws.  If any redraws had been prevented, a redraw will
+ * be done now.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.resume = function() {
+  this.preventRedraw_ = false;
+
+  if (this.needsRedraw_) {
+    this.redraw();
+    this.needsRedraw_ = false;
+  }
+};

Reply via email to