flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ftho...@apache.org
Subject [09/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.
Date Thu, 17 Sep 2015 15:28:24 GMT
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/vmlelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/vmlelement.js b/externs/GCL/externs/goog/graphics/vmlelement.js
new file mode 100644
index 0000000..9e72b13
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/vmlelement.js
@@ -0,0 +1,438 @@
+// 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 Thin wrappers around the DOM element returned from
+ * the different draw methods of the graphics. This is the VML implementation.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.graphics.VmlEllipseElement');
+goog.provide('goog.graphics.VmlGroupElement');
+goog.provide('goog.graphics.VmlImageElement');
+goog.provide('goog.graphics.VmlPathElement');
+goog.provide('goog.graphics.VmlRectElement');
+goog.provide('goog.graphics.VmlTextElement');
+
+
+goog.require('goog.dom');
+goog.require('goog.graphics.EllipseElement');
+goog.require('goog.graphics.GroupElement');
+goog.require('goog.graphics.ImageElement');
+goog.require('goog.graphics.PathElement');
+goog.require('goog.graphics.RectElement');
+goog.require('goog.graphics.TextElement');
+
+
+/**
+ * Returns the VML element corresponding to this object.  This method is added
+ * to several classes below.  Note that the return value of this method may
+ * change frequently in IE8, so it should not be cached externally.
+ * @return {Element} The VML element corresponding to this object.
+ * @this {goog.graphics.VmlGroupElement|goog.graphics.VmlEllipseElement|
+ *     goog.graphics.VmlRectElement|goog.graphics.VmlPathElement|
+ *     goog.graphics.VmlTextElement|goog.graphics.VmlImageElement}
+ * @private
+ */
+goog.graphics.vmlGetElement_ = function() {
+  this.element_ = this.getGraphics().getVmlElement(this.id_) || this.element_;
+  return this.element_;
+};
+
+
+
+/**
+ * Thin wrapper for VML group elements.
+ * 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 {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} 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.VmlGroupElement = function(element, graphics) {
+  this.id_ = element.id;
+  goog.graphics.GroupElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.VmlGroupElement, goog.graphics.GroupElement);
+
+
+/** @override */
+goog.graphics.VmlGroupElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Remove all drawing elements from the group.
+ * @override
+ */
+goog.graphics.VmlGroupElement.prototype.clear = function() {
+  goog.dom.removeChildren(this.getElement());
+};
+
+
+/**
+ * @return {boolean} True if this group is the root canvas element.
+ * @private
+ */
+goog.graphics.VmlGroupElement.prototype.isRootElement_ = function() {
+  return this.getGraphics().getCanvasElement() == this;
+};
+
+
+/**
+ * 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.VmlGroupElement.prototype.setSize = function(width, height) {
+  var element = this.getElement();
+
+  var style = element.style;
+  style.width = /** @suppress {missingRequire} */ (
+      goog.graphics.VmlGraphics.toSizePx(width));
+  style.height = /** @suppress {missingRequire} */ (
+      goog.graphics.VmlGraphics.toSizePx(height));
+
+  element.coordsize = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizeCoord(width) +
+      ' ' +
+      /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizeCoord(height);
+
+  // Don't overwrite the root element's origin.
+  if (!this.isRootElement_()) {
+    element.coordorigin = '0 0';
+  }
+};
+
+
+
+/**
+ * Thin wrapper for VML 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.VmlGraphics} 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}
+ * @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.VmlEllipseElement = function(element, graphics,
+    cx, cy, rx, ry, stroke, fill) {
+  this.id_ = element.id;
+
+  goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill);
+
+  // Store center and radius for future calls to setRadius or setCenter.
+
+  /**
+   * X coordinate of the ellipse center.
+   * @type {number}
+   */
+  this.cx = cx;
+
+
+  /**
+   * Y coordinate of the ellipse center.
+   * @type {number}
+   */
+  this.cy = cy;
+
+
+  /**
+   * Radius length for the x-axis.
+   * @type {number}
+   */
+  this.rx = rx;
+
+
+  /**
+   * Radius length for the y-axis.
+   * @type {number}
+   */
+  this.ry = ry;
+};
+goog.inherits(goog.graphics.VmlEllipseElement, goog.graphics.EllipseElement);
+
+
+/** @override */
+goog.graphics.VmlEllipseElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @override
+ */
+goog.graphics.VmlEllipseElement.prototype.setCenter = function(cx, cy) {
+  this.cx = cx;
+  this.cy = cy;
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setPositionAndSize(this.getElement(),
+      cx - this.rx, cy - this.ry, this.rx * 2, this.ry * 2);
+};
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx Center X coordinate.
+ * @param {number} ry Center Y coordinate.
+ * @override
+ */
+goog.graphics.VmlEllipseElement.prototype.setRadius = function(rx, ry) {
+  this.rx = rx;
+  this.ry = ry;
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setPositionAndSize(this.getElement(),
+      this.cx - rx, this.cy - ry, rx * 2, ry * 2);
+};
+
+
+
+/**
+ * Thin wrapper for VML 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.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @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}
+ * @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.VmlRectElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.RectElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlRectElement, goog.graphics.RectElement);
+
+
+/** @override */
+goog.graphics.VmlRectElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.VmlRectElement.prototype.setPosition = function(x, y) {
+  var style = this.getElement().style;
+
+  style.left = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(x);
+  style.top = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(y);
+};
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.VmlRectElement.prototype.setSize = function(width, height) {
+  var style = this.getElement().style;
+  style.width = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizePx(width);
+  style.height = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizePx(height);
+};
+
+
+
+/**
+ * Thin wrapper for VML 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.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @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}
+ * @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.VmlPathElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.PathElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlPathElement, goog.graphics.PathElement);
+
+
+/** @override */
+goog.graphics.VmlPathElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @override
+ */
+goog.graphics.VmlPathElement.prototype.setPath = function(path) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(
+      this.getElement(), 'path',
+      /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.getVmlPath(path));
+};
+
+
+
+/**
+ * Thin wrapper for VML 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 {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @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}
+ * @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.VmlTextElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.TextElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlTextElement, goog.graphics.TextElement);
+
+
+/** @override */
+goog.graphics.VmlTextElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ * @override
+ */
+goog.graphics.VmlTextElement.prototype.setText = function(text) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(this.getElement().childNodes[1],
+      'string', text);
+};
+
+
+
+/**
+ * Thin wrapper for VML 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.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.ImageElement}
+ * @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.VmlImageElement = function(element, graphics) {
+  this.id_ = element.id;
+  goog.graphics.ImageElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.VmlImageElement, goog.graphics.ImageElement);
+
+
+/** @override */
+goog.graphics.VmlImageElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the position of the image.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setPosition = function(x, y) {
+  var style = this.getElement().style;
+
+  style.left = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(x);
+  style.top = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(y);
+};
+
+
+/**
+ * Update the size of the image.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setSize = function(width, height) {
+  var style = this.getElement().style;
+  style.width = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(width);
+  style.height = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(height);
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setSource = function(src) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(this.getElement(), 'src', src);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/vmlgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/vmlgraphics.js b/externs/GCL/externs/goog/graphics/vmlgraphics.js
new file mode 100644
index 0000000..5e0cd66
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/vmlgraphics.js
@@ -0,0 +1,948 @@
+// 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 VmlGraphics sub class that uses VML to draw the graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.VmlGraphics');
+
+
+goog.require('goog.array');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics.AbstractGraphics');
+goog.require('goog.graphics.LinearGradient');
+goog.require('goog.graphics.Path');
+goog.require('goog.graphics.SolidFill');
+goog.require('goog.graphics.VmlEllipseElement');
+goog.require('goog.graphics.VmlGroupElement');
+goog.require('goog.graphics.VmlImageElement');
+goog.require('goog.graphics.VmlPathElement');
+goog.require('goog.graphics.VmlRectElement');
+goog.require('goog.graphics.VmlTextElement');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.math');
+goog.require('goog.math.Size');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.style');
+
+
+
+/**
+ * A Graphics implementation for drawing using VML.
+ * @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.
+ * @final
+ */
+goog.graphics.VmlGraphics = function(width, height,
+                                     opt_coordWidth, opt_coordHeight,
+                                     opt_domHelper) {
+  goog.graphics.AbstractGraphics.call(this, width, height,
+                                      opt_coordWidth, opt_coordHeight,
+                                      opt_domHelper);
+  this.handler_ = new goog.events.EventHandler(this);
+  this.registerDisposable(this.handler_);
+};
+goog.inherits(goog.graphics.VmlGraphics, goog.graphics.AbstractGraphics);
+
+
+/**
+ * The prefix to use for VML elements
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_PREFIX_ = 'g_vml_';
+
+
+/**
+ * The VML namespace URN
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_NS_ = 'urn:schemas-microsoft-com:vml';
+
+
+/**
+ * The VML behavior URL.
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_IMPORT_ = '#default#VML';
+
+
+/**
+ * Whether the document is using IE8 standards mode, and therefore needs hacks.
+ * @private
+ * @type {boolean}
+ */
+goog.graphics.VmlGraphics.IE8_MODE_ =
+    goog.global.document && goog.global.document.documentMode &&
+    goog.global.document.documentMode >= 8;
+
+
+/**
+ * The coordinate multiplier to allow sub-pixel rendering
+ * @type {number}
+ */
+goog.graphics.VmlGraphics.COORD_MULTIPLIER = 100;
+
+
+/**
+ * Converts the given size to a css size.  If it is a percentage, leaves it
+ * alone.  Otherwise assumes px.
+ *
+ * @param {number|string} size The size to use.
+ * @return {string} The position adjusted for COORD_MULTIPLIER.
+ */
+goog.graphics.VmlGraphics.toCssSize = function(size) {
+  return goog.isString(size) && goog.string.endsWith(size, '%') ?
+         size : parseFloat(size.toString()) + 'px';
+};
+
+
+/**
+ * Multiplies positioning coordinates by COORD_MULTIPLIER to allow sub-pixel
+ * coordinates.  Also adds a half pixel offset to match SVG.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A position in pixels.
+ * @return {number} The position adjusted for COORD_MULTIPLIER.
+ */
+goog.graphics.VmlGraphics.toPosCoord = function(number) {
+  return Math.round((parseFloat(number.toString()) - 0.5) *
+      goog.graphics.VmlGraphics.COORD_MULTIPLIER);
+};
+
+
+/**
+ * Add a "px" suffix to a number of pixels, and multiplies all coordinates by
+ * COORD_MULTIPLIER to allow sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A position in pixels.
+ * @return {string} The position with suffix 'px'.
+ */
+goog.graphics.VmlGraphics.toPosPx = function(number) {
+  return goog.graphics.VmlGraphics.toPosCoord(number) + 'px';
+};
+
+
+/**
+ * Multiplies the width or height coordinate by COORD_MULTIPLIER to allow
+ * sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {string|number} number A size in units.
+ * @return {number} The size multiplied by the correct factor.
+ */
+goog.graphics.VmlGraphics.toSizeCoord = function(number) {
+  return Math.round(parseFloat(number.toString()) *
+      goog.graphics.VmlGraphics.COORD_MULTIPLIER);
+};
+
+
+/**
+ * Add a "px" suffix to a number of pixels, and multiplies all coordinates by
+ * COORD_MULTIPLIER to allow sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A size in pixels.
+ * @return {string} The size with suffix 'px'.
+ */
+goog.graphics.VmlGraphics.toSizePx = function(number) {
+  return goog.graphics.VmlGraphics.toSizeCoord(number) + 'px';
+};
+
+
+/**
+ * Sets an attribute on the given VML element, in the way best suited to the
+ * current version of IE.  Should only be used in the goog.graphics package.
+ * @param {Element} element The element to set an attribute
+ *     on.
+ * @param {string} name The name of the attribute to set.
+ * @param {string} value The value to set it to.
+ */
+goog.graphics.VmlGraphics.setAttribute = function(element, name, value) {
+  if (goog.graphics.VmlGraphics.IE8_MODE_) {
+    element[name] = value;
+  } else {
+    element.setAttribute(name, value);
+  }
+};
+
+
+/**
+ * Event handler.
+ * @type {goog.events.EventHandler}
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handler_;
+
+
+/**
+ * Creates a VML element. Used internally and by different VML classes.
+ * @param {string} tagName The type of element to create.
+ * @return {!Element} The created element.
+ */
+goog.graphics.VmlGraphics.prototype.createVmlElement = function(tagName) {
+  var element =
+      this.dom_.createElement(goog.graphics.VmlGraphics.VML_PREFIX_ + ':' +
+                              tagName);
+  element.id = goog.string.createUniqueString();
+  return element;
+};
+
+
+/**
+ * Returns the VML element with the given id that is a child of this graphics
+ * object.
+ * Should be considered package private, and not used externally.
+ * @param {string} id The element id to find.
+ * @return {Element} The element with the given id, or null if none is found.
+ */
+goog.graphics.VmlGraphics.prototype.getVmlElement = function(id) {
+  return this.dom_.getElement(id);
+};
+
+
+/**
+ * Resets the graphics so they will display properly on IE8.  Noop in older
+ * versions.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.updateGraphics_ = function() {
+  if (goog.graphics.VmlGraphics.IE8_MODE_ && this.isInDocument()) {
+    // There's a risk of mXSS here, as the browser is not guaranteed to
+    // return the HTML that was originally written, when innerHTML is read.
+    // However, given that this a deprecated API and affects only IE, it seems
+    // an acceptable risk.
+    var html = goog.html.uncheckedconversions
+        .safeHtmlFromStringKnownToSatisfyTypeContract(
+            goog.string.Const.from('Assign innerHTML to itself'),
+            this.getElement().innerHTML);
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.getElement()), html);
+  }
+};
+
+
+/**
+ * Appends an element.
+ *
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.append_ = function(element, opt_group) {
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element.getElement());
+  this.updateGraphics_();
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.setElementFill = function(element, fill) {
+  var vmlElement = element.getElement();
+  goog.graphics.VmlGraphics.removeFill_(vmlElement);
+  if (fill instanceof goog.graphics.SolidFill) {
+    // NOTE(arv): VML does not understand 'transparent' so hard code support
+    // for it.
+    if (fill.getColor() == 'transparent') {
+      vmlElement.filled = false;
+    } else if (fill.getOpacity() != 1) {
+      vmlElement.filled = true;
+      // Set opacity (number 0-1 is translated to percent)
+      var fillNode = this.createVmlElement('fill');
+      fillNode.opacity = Math.round(fill.getOpacity() * 100) + '%';
+      fillNode.color = fill.getColor();
+      vmlElement.appendChild(fillNode);
+    } else {
+      vmlElement.filled = true;
+      vmlElement.fillcolor = fill.getColor();
+    }
+  } else if (fill instanceof goog.graphics.LinearGradient) {
+    vmlElement.filled = true;
+    // Add a 'fill' element
+    var gradient = this.createVmlElement('fill');
+    gradient.color = fill.getColor1();
+    gradient.color2 = fill.getColor2();
+    if (goog.isNumber(fill.getOpacity1())) {
+      gradient.opacity = fill.getOpacity1();
+    }
+    if (goog.isNumber(fill.getOpacity2())) {
+      gradient.opacity2 = fill.getOpacity2();
+    }
+    var angle = goog.math.angle(fill.getX1(), fill.getY1(),
+        fill.getX2(), fill.getY2());
+    // Our angles start from 0 to the right, and grow clockwise.
+    // MSIE starts from 0 to top, and grows anti-clockwise.
+    angle = Math.round(goog.math.standardAngle(270 - angle));
+    gradient.angle = angle;
+    gradient.type = 'gradient';
+    vmlElement.appendChild(gradient);
+  } else {
+    vmlElement.filled = false;
+  }
+  this.updateGraphics_();
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.setElementStroke = function(element,
+    stroke) {
+  var vmlElement = element.getElement();
+  if (stroke) {
+    vmlElement.stroked = true;
+
+    var width = stroke.getWidth();
+    if (goog.isString(width) && width.indexOf('px') == -1) {
+      width = parseFloat(width);
+    } else {
+      width = width * this.getPixelScaleX();
+    }
+
+    var strokeElement = vmlElement.getElementsByTagName('stroke')[0];
+    if (!strokeElement) {
+      strokeElement = strokeElement || this.createVmlElement('stroke');
+      vmlElement.appendChild(strokeElement);
+    }
+    strokeElement.opacity = stroke.getOpacity();
+    strokeElement.weight = width + 'px';
+    strokeElement.color = stroke.getColor();
+  } else {
+    vmlElement.stroked = false;
+  }
+  this.updateGraphics_();
+};
+
+
+/**
+ * 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 {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.VmlGraphics.prototype.setElementTransform = function(element, x,
+    y, angle, centerX, centerY) {
+  var el = element.getElement();
+
+  el.style.left = goog.graphics.VmlGraphics.toPosPx(x);
+  el.style.top = goog.graphics.VmlGraphics.toPosPx(y);
+  if (angle || el.rotation) {
+    el.rotation = angle;
+    el.coordsize = goog.graphics.VmlGraphics.toSizeCoord(centerX * 2) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(centerY * 2);
+  }
+};
+
+
+/**
+ * Set the transformation of an element.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setElementAffineTransform = function(
+    element, affineTransform) {
+  var t = affineTransform;
+  var vmlElement = element.getElement();
+  goog.graphics.VmlGraphics.removeSkew_(vmlElement);
+  var skewNode = this.createVmlElement('skew');
+  skewNode.on = 'true';
+  // Move the transform origin to 0px,0px of the graphics.
+  // In VML, 0,0 means the center of the element, -0.5,-0.5 left top conner of
+  // it.
+  skewNode.origin =
+      (-vmlElement.style.pixelLeft / vmlElement.style.pixelWidth - 0.5) + ',' +
+      (-vmlElement.style.pixelTop / vmlElement.style.pixelHeight - 0.5);
+  skewNode.offset = t.getTranslateX().toFixed(1) + 'px,' +
+                    t.getTranslateY().toFixed(1) + 'px';
+  skewNode.matrix = [t.getScaleX().toFixed(6), t.getShearX().toFixed(6),
+                     t.getShearY().toFixed(6), t.getScaleY().toFixed(6),
+                     0, 0].join(',');
+  vmlElement.appendChild(skewNode);
+  this.updateGraphics_();
+};
+
+
+/**
+ * Removes the skew information from a dom element.
+ * @param {Element} element DOM element.
+ * @private
+ */
+goog.graphics.VmlGraphics.removeSkew_ = function(element) {
+  goog.array.forEach(element.childNodes, function(child) {
+    if (child.tagName == 'skew') {
+      element.removeChild(child);
+    }
+  });
+};
+
+
+/**
+ * Removes the fill information from a dom element.
+ * @param {Element} element DOM element.
+ * @private
+ */
+goog.graphics.VmlGraphics.removeFill_ = function(element) {
+  element.fillcolor = '';
+  goog.array.forEach(element.childNodes, function(child) {
+    if (child.tagName == 'fill') {
+      element.removeChild(child);
+    }
+  });
+};
+
+
+/**
+ * Set top, left, width and height for an element.
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {Element} element DOM element.
+ * @param {number} left Left ccordinate in pixels.
+ * @param {number} top Top ccordinate in pixels.
+ * @param {number} width Width in pixels.
+ * @param {number} height Height in pixels.
+ */
+goog.graphics.VmlGraphics.setPositionAndSize = function(
+    element, left, top, width, height) {
+  var style = element.style;
+  style.position = 'absolute';
+  style.left = goog.graphics.VmlGraphics.toPosPx(left);
+  style.top = goog.graphics.VmlGraphics.toPosPx(top);
+  style.width = goog.graphics.VmlGraphics.toSizePx(width);
+  style.height = goog.graphics.VmlGraphics.toSizePx(height);
+
+  if (element.tagName == 'shape') {
+    element.coordsize = goog.graphics.VmlGraphics.toSizeCoord(width) + ' ' +
+                        goog.graphics.VmlGraphics.toSizeCoord(height);
+  }
+};
+
+
+/**
+ * Creates an element spanning the surface.
+ *
+ * @param {string} type The type of element to create.
+ * @return {!Element} The created, positioned, and sized element.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.createFullSizeElement_ = function(type) {
+  var element = this.createVmlElement(type);
+  var size = this.getCoordSize();
+  goog.graphics.VmlGraphics.setPositionAndSize(element, 0, 0, size.width,
+      size.height);
+  return element;
+};
+
+
+/**
+ * IE magic - if this "no-op" line is not here, the if statement below will
+ * fail intermittently.  The eval is used to prevent the JsCompiler from
+ * stripping this piece of code, which it quite reasonably thinks is doing
+ * nothing. Put it in try-catch block to prevent "Unspecified Error" when
+ * this statement is executed in a defer JS in IE.
+ * More info here:
+ * http://www.mail-archive.com/users@openlayers.org/msg01838.html
+ */
+try {
+  eval('document.namespaces');
+} catch (ex) {}
+
+
+/**
+ * Creates the DOM representation of the graphics area.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.createDom = function() {
+  var doc = this.dom_.getDocument();
+
+  // Add the namespace.
+  if (!doc.namespaces[goog.graphics.VmlGraphics.VML_PREFIX_]) {
+    if (goog.graphics.VmlGraphics.IE8_MODE_) {
+      doc.namespaces.add(goog.graphics.VmlGraphics.VML_PREFIX_,
+                         goog.graphics.VmlGraphics.VML_NS_,
+                         goog.graphics.VmlGraphics.VML_IMPORT_);
+    } else {
+      doc.namespaces.add(goog.graphics.VmlGraphics.VML_PREFIX_,
+                         goog.graphics.VmlGraphics.VML_NS_);
+    }
+
+    // We assume that we only need to add the CSS if the namespace was not
+    // present
+    var ss = doc.createStyleSheet();
+    ss.cssText = goog.graphics.VmlGraphics.VML_PREFIX_ + '\\:*' +
+                 '{behavior:url(#default#VML)}';
+  }
+
+  // Outer a DIV with overflow hidden for clipping.
+  // All inner elements are absolutly positioned on-top of this div.
+  var pixelWidth = this.width;
+  var pixelHeight = this.height;
+  var divElement = this.dom_.createDom(goog.dom.TagName.DIV, {
+    'style': 'overflow:hidden;position:relative;width:' +
+        goog.graphics.VmlGraphics.toCssSize(pixelWidth) + ';height:' +
+        goog.graphics.VmlGraphics.toCssSize(pixelHeight)
+  });
+
+  this.setElementInternal(divElement);
+
+  var group = this.createVmlElement('group');
+  var style = group.style;
+
+  style.position = 'absolute';
+  style.left = style.top = 0;
+  style.width = this.width;
+  style.height = this.height;
+  if (this.coordWidth) {
+    group.coordsize =
+        goog.graphics.VmlGraphics.toSizeCoord(this.coordWidth) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(
+            /** @type {number} */ (this.coordHeight));
+  } else {
+    group.coordsize = goog.graphics.VmlGraphics.toSizeCoord(pixelWidth) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(pixelHeight);
+  }
+
+  if (goog.isDef(this.coordLeft)) {
+    group.coordorigin = goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) +
+        ' ' + goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
+  } else {
+    group.coordorigin = '0 0';
+  }
+  divElement.appendChild(group);
+
+  this.canvasElement = new goog.graphics.VmlGroupElement(group, this);
+
+  goog.events.listen(divElement, goog.events.EventType.RESIZE, goog.bind(
+      this.handleContainerResize_, this));
+};
+
+
+/**
+ * Changes the canvas element size to match the container element size.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handleContainerResize_ = function() {
+  var size = goog.style.getSize(this.getElement());
+  var style = this.canvasElement.getElement().style;
+
+  if (size.width) {
+    style.width = size.width + 'px';
+    style.height = size.height + 'px';
+  } else {
+    var current = this.getElement();
+    while (current && current.currentStyle &&
+        current.currentStyle.display != 'none') {
+      current = current.parentNode;
+    }
+    if (current && current.currentStyle) {
+      this.handler_.listen(current, 'propertychange',
+          this.handleContainerResize_);
+    }
+  }
+
+  this.dispatchEvent(goog.events.EventType.RESIZE);
+};
+
+
+/**
+ * Handle property changes on hidden ancestors.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handlePropertyChange_ = function(e) {
+  var prop = e.getBrowserEvent().propertyName;
+  if (prop == 'display' || prop == 'className') {
+    this.handler_.unlisten(/** @type {Element} */(e.target),
+        'propertychange', this.handlePropertyChange_);
+    this.handleContainerResize_();
+  }
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setCoordOrigin = function(left, top) {
+  this.coordLeft = left;
+  this.coordTop = top;
+
+  this.canvasElement.getElement().coordorigin =
+      goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) + ' ' +
+      goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setCoordSize = function(coordWidth,
+                                                            coordHeight) {
+  goog.graphics.VmlGraphics.superClass_.setCoordSize.apply(this, arguments);
+
+  this.canvasElement.getElement().coordsize =
+      goog.graphics.VmlGraphics.toSizeCoord(coordWidth) + ' ' +
+      goog.graphics.VmlGraphics.toSizeCoord(coordHeight);
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setSize = function(pixelWidth,
+    pixelHeight) {
+  goog.style.setSize(this.getElement(), pixelWidth, pixelHeight);
+};
+
+
+/**
+ * @return {!goog.math.Size} Returns the number of pixels spanned by the
+ *     surface.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.getPixelSize = function() {
+  var el = this.getElement();
+  // The following relies on the fact that the size can never be 0.
+  return new goog.math.Size(el.style.pixelWidth || el.offsetWidth || 1,
+      el.style.pixelHeight || el.offsetHeight || 1);
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.clear = function() {
+  this.canvasElement.clear();
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.drawEllipse = function(cx, cy, rx, ry,
+    stroke, fill, opt_group) {
+  var element = this.createVmlElement('oval');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, cx - rx, cy - ry,
+      rx * 2, ry * 2);
+  var wrapper = new goog.graphics.VmlEllipseElement(element, this,
+      cx, cy, rx, ry, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.drawRect = function(x, y, width, height,
+    stroke, fill, opt_group) {
+  var element = this.createVmlElement('rect');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
+  var wrapper = new goog.graphics.VmlRectElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.drawImage = function(x, y, width, height,
+    src, opt_group) {
+  var element = this.createVmlElement('image');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
+  goog.graphics.VmlGraphics.setAttribute(element, 'src', src);
+  var wrapper = new goog.graphics.VmlImageElement(element, this);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.drawTextOnLine = function(
+    text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
+  var shape = this.createFullSizeElement_('shape');
+
+  var pathElement = this.createVmlElement('path');
+  var path = 'M' + goog.graphics.VmlGraphics.toPosCoord(x1) + ',' +
+             goog.graphics.VmlGraphics.toPosCoord(y1) + 'L' +
+             goog.graphics.VmlGraphics.toPosCoord(x2) + ',' +
+             goog.graphics.VmlGraphics.toPosCoord(y2) + 'E';
+  goog.graphics.VmlGraphics.setAttribute(pathElement, 'v', path);
+  goog.graphics.VmlGraphics.setAttribute(pathElement, 'textpathok', 'true');
+
+  var textPathElement = this.createVmlElement('textpath');
+  textPathElement.setAttribute('on', 'true');
+  var style = textPathElement.style;
+  style.fontSize = font.size * this.getPixelScaleX();
+  style.fontFamily = font.family;
+  if (align != null) {
+    style['v-text-align'] = align;
+  }
+  if (font.bold) {
+    style.fontWeight = 'bold';
+  }
+  if (font.italic) {
+    style.fontStyle = 'italic';
+  }
+  goog.graphics.VmlGraphics.setAttribute(textPathElement, 'string', text);
+
+  shape.appendChild(pathElement);
+  shape.appendChild(textPathElement);
+  var wrapper = new goog.graphics.VmlTextElement(shape, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * 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.VmlGraphics.prototype.drawPath = function(path, stroke, fill,
+    opt_group) {
+  var element = this.createFullSizeElement_('shape');
+  goog.graphics.VmlGraphics.setAttribute(element, 'path',
+      goog.graphics.VmlGraphics.getVmlPath(path));
+
+  var wrapper = new goog.graphics.VmlPathElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Returns a string representation of a logical path suitable for use in
+ * a VML element.
+ *
+ * @param {goog.graphics.Path} path The logical path.
+ * @return {string} The VML path representation.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.VmlGraphics.getVmlPath = function(path) {
+  var list = [];
+  path.forEachSegment(function(segment, args) {
+    switch (segment) {
+      case goog.graphics.Path.Segment.MOVETO:
+        list.push('m');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.LINETO:
+        list.push('l');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.CURVETO:
+        list.push('c');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.CLOSE:
+        list.push('x');
+        break;
+      case goog.graphics.Path.Segment.ARCTO:
+        var toAngle = args[2] + args[3];
+        var cx = goog.graphics.VmlGraphics.toSizeCoord(
+            args[4] - goog.math.angleDx(toAngle, args[0]));
+        var cy = goog.graphics.VmlGraphics.toSizeCoord(
+            args[5] - goog.math.angleDy(toAngle, args[1]));
+        var rx = goog.graphics.VmlGraphics.toSizeCoord(args[0]);
+        var ry = goog.graphics.VmlGraphics.toSizeCoord(args[1]);
+        // VML angles are in fd units (see http://www.w3.org/TR/NOTE-VML) and
+        // are positive counter-clockwise.
+        var fromAngle = Math.round(args[2] * -65536);
+        var extent = Math.round(args[3] * -65536);
+        list.push('ae', cx, cy, rx, ry, fromAngle, extent);
+        break;
+    }
+  });
+  return list.join(' ');
+};
+
+
+/**
+ * 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.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.createGroup = function(opt_group) {
+  var element = this.createFullSizeElement_('group');
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element);
+  return new goog.graphics.VmlGroupElement(element, this);
+};
+
+
+/**
+ * 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.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.getTextWidth = function(text, font) {
+  // TODO(arv): Implement
+  return 0;
+};
+
+
+/** @override */
+goog.graphics.VmlGraphics.prototype.enterDocument = function() {
+  goog.graphics.VmlGraphics.superClass_.enterDocument.call(this);
+  this.handleContainerResize_();
+  this.updateGraphics_();
+};
+
+
+/**
+ * Disposes of the component by removing event handlers, detacing DOM nodes from
+ * the document body, and removing references to them.
+ * @override
+ * @protected
+ */
+goog.graphics.VmlGraphics.prototype.disposeInternal = function() {
+  this.canvasElement = null;
+  goog.graphics.VmlGraphics.superClass_.disposeInternal.call(this);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/event.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/event.js b/externs/GCL/externs/goog/history/event.js
new file mode 100644
index 0000000..19250df
--- /dev/null
+++ b/externs/GCL/externs/goog/history/event.js
@@ -0,0 +1,55 @@
+// Copyright 2010 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 The event object dispatched when the history changes.
+ *
+ */
+
+
+goog.provide('goog.history.Event');
+
+goog.require('goog.events.Event');
+goog.require('goog.history.EventType');
+
+
+
+/**
+ * Event object dispatched after the history state has changed.
+ * @param {string} token The string identifying the new history state.
+ * @param {boolean} isNavigation True if the event was triggered by a browser
+ *     action, such as forward or back, clicking on a link, editing the URL, or
+ *     calling {@code window.history.(go|back|forward)}.
+ *     False if the token has been changed by a {@code setToken} or
+ *     {@code replaceToken} call.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.history.Event = function(token, isNavigation) {
+  goog.events.Event.call(this, goog.history.EventType.NAVIGATE);
+
+  /**
+   * The current history state.
+   * @type {string}
+   */
+  this.token = token;
+
+  /**
+   * Whether the event was triggered by browser navigation.
+   * @type {boolean}
+   */
+  this.isNavigation = isNavigation;
+};
+goog.inherits(goog.history.Event, goog.events.Event);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/eventtype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/eventtype.js b/externs/GCL/externs/goog/history/eventtype.js
new file mode 100644
index 0000000..4268df3
--- /dev/null
+++ b/externs/GCL/externs/goog/history/eventtype.js
@@ -0,0 +1,30 @@
+// Copyright 2010 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 Event types for goog.history.
+ *
+ */
+
+
+goog.provide('goog.history.EventType');
+
+
+/**
+ * Event types for goog.history.
+ * @enum {string}
+ */
+goog.history.EventType = {
+  NAVIGATE: 'navigate'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/history.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/history.js b/externs/GCL/externs/goog/history/history.js
new file mode 100644
index 0000000..af82ba0
--- /dev/null
+++ b/externs/GCL/externs/goog/history/history.js
@@ -0,0 +1,1005 @@
+// 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 Browser history stack management class.
+ *
+ * The goog.History object allows a page to create history state without leaving
+ * the current document. This allows users to, for example, hit the browser's
+ * back button without leaving the current page.
+ *
+ * The history object can be instantiated in one of two modes. In user visible
+ * mode, the current history state is shown in the browser address bar as a
+ * document location fragment (the portion of the URL after the '#'). These
+ * addresses can be bookmarked, copied and pasted into another browser, and
+ * modified directly by the user like any other URL.
+ *
+ * If the history object is created in invisible mode, the user can still
+ * affect the state using the browser forward and back buttons, but the current
+ * state is not displayed in the browser address bar. These states are not
+ * bookmarkable or editable.
+ *
+ * It is possible to use both types of history object on the same page, but not
+ * currently recommended due to browser deficiencies.
+ *
+ * Tested to work in:
+ * <ul>
+ *   <li>Firefox 1.0-4.0
+ *   <li>Internet Explorer 5.5-9.0
+ *   <li>Opera 9+
+ *   <li>Safari 4+
+ * </ul>
+ *
+ * @author brenneman@google.com (Shawn Brenneman)
+ * @see ../demos/history1.html
+ * @see ../demos/history2.html
+ */
+
+/* Some browser specific implementation notes:
+ *
+ * Firefox (through version 2.0.0.1):
+ *
+ * Ideally, navigating inside the hidden iframe could be done using
+ * about:blank#state instead of a real page on the server. Setting the hash on
+ * about:blank creates history entries, but the hash is not recorded and is lost
+ * when the user hits the back button. This is true in Opera as well. A blank
+ * HTML page must be provided for invisible states to be recorded in the iframe
+ * hash.
+ *
+ * After leaving the page with the History object and returning to it (by
+ * hitting the back button from another site), the last state of the iframe is
+ * overwritten. The most recent state is saved in a hidden input field so the
+ * previous state can be restored.
+ *
+ * Firefox does not store the previous value of dynamically generated input
+ * elements. To save the state, the hidden element must be in the HTML document,
+ * either in the original source or added with document.write. If a reference
+ * to the input element is not provided as a constructor argument, then the
+ * history object creates one using document.write, in which case the history
+ * object must be created from a script in the body element of the page.
+ *
+ * Manually editing the address field to a different hash link prevents further
+ * updates to the address bar. The page continues to work as normal, but the
+ * address shown will be incorrect until the page is reloaded.
+ *
+ * NOTE(user): It should be noted that Firefox will URL encode any non-regular
+ * ascii character, along with |space|, ", <, and >, when added to the fragment.
+ * If you expect these characters in your tokens you should consider that
+ * setToken('<b>') would result in the history fragment "%3Cb%3E", and
+ * "esp&eacute;re" would show "esp%E8re".  (IE allows unicode characters in the
+ * fragment)
+ *
+ * TODO(user): Should we encapsulate this escaping into the API for visible
+ * history and encode all characters that aren't supported by Firefox?  It also
+ * needs to be optional so apps can elect to handle the escaping themselves.
+ *
+ *
+ * Internet Explorer (through version 7.0):
+ *
+ * IE does not modify the history stack when the document fragment is changed.
+ * We create history entries instead by using document.open and document.write
+ * into a hidden iframe.
+ *
+ * IE destroys the history stack when navigating from /foo.html#someFragment to
+ * /foo.html. The workaround is to always append the # to the URL. This is
+ * somewhat unfortunate when loading the page without any # specified, because
+ * a second "click" sound will play on load as the fragment is automatically
+ * appended. If the hash is always present, this can be avoided.
+ *
+ * Manually editing the hash in the address bar in IE6 and then hitting the back
+ * button can replace the page with a blank page. This is a Bad User Experience,
+ * but probably not preventable.
+ *
+ * IE also has a bug when the page is loaded via a server redirect, setting
+ * a new hash value on the window location will force a page reload. This will
+ * happen the first time setToken is called with a new token. The only known
+ * workaround is to force a client reload early, for example by setting
+ * window.location.hash = window.location.hash, which will otherwise be a no-op.
+ *
+ * Internet Explorer 8.0, Webkit 532.1 and Gecko 1.9.2:
+ *
+ * IE8 has introduced the support to the HTML5 onhashchange event, which means
+ * we don't have to do any polling to detect fragment changes. Chrome and
+ * Firefox have added it on their newer builds, wekbit 532.1 and gecko 1.9.2.
+ * http://www.w3.org/TR/html5/history.html
+ * NOTE(goto): it is important to note that the document needs to have the
+ * <!DOCTYPE html> tag to enable the IE8 HTML5 mode. If the tag is not present,
+ * IE8 will enter IE7 compatibility mode (which can also be enabled manually).
+ *
+ * Opera (through version 9.02):
+ *
+ * Navigating through pages at a rate faster than some threshhold causes Opera
+ * to cancel all outstanding timeouts and intervals, including the location
+ * polling loop. Since this condition cannot be detected, common input events
+ * are captured to cause the loop to restart.
+ *
+ * location.replace is adding a history entry inside setHash_, despite
+ * documentation that suggests it should not.
+ *
+ *
+ * Safari (through version 2.0.4):
+ *
+ * After hitting the back button, the location.hash property is no longer
+ * readable from JavaScript. This is fixed in later WebKit builds, but not in
+ * currently shipping Safari. For now, the only recourse is to disable history
+ * states in Safari. Pages are still navigable via the History object, but the
+ * back button cannot restore previous states.
+ *
+ * Safari sets history states on navigation to a hashlink, but doesn't allow
+ * polling of the hash, so following actual anchor links in the page will create
+ * useless history entries. Using location.replace does not seem to prevent
+ * this. Not a terribly good user experience, but fixed in later Webkits.
+ *
+ *
+ * WebKit (nightly version 420+):
+ *
+ * This almost works. Returning to a page with an invisible history object does
+ * not restore the old state, however, and there is no pageshow event that fires
+ * in this browser. Holding off on finding a solution for now.
+ *
+ *
+ * HTML5 capable browsers (Firefox 4, Chrome, Safari 5)
+ *
+ * No known issues. The goog.history.Html5History class provides a simpler
+ * implementation more suitable for recent browsers. These implementations
+ * should be merged so the history class automatically invokes the correct
+ * implementation.
+ */
+
+
+goog.provide('goog.History');
+goog.provide('goog.History.Event');
+goog.provide('goog.History.EventType');
+
+goog.require('goog.Timer');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.InputType');
+goog.require('goog.dom.safe');
+/** @suppress {extraRequire} */
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.history.Event');
+goog.require('goog.history.EventType');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.html.legacyconversions');
+goog.require('goog.labs.userAgent.device');
+goog.require('goog.memoize');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A history management object. Can be instantiated in user-visible mode (uses
+ * the address fragment to manage state) or in hidden mode. This object should
+ * be created from a script in the document body before the document has
+ * finished loading.
+ *
+ * To store the hidden states in browsers other than IE, a hidden iframe is
+ * used. It must point to a valid html page on the same domain (which can and
+ * probably should be blank.)
+ *
+ * Sample instantiation and usage:
+ *
+ * <pre>
+ * // Instantiate history to use the address bar for state.
+ * var h = new goog.History();
+ * goog.events.listen(h, goog.history.EventType.NAVIGATE, navCallback);
+ * h.setEnabled(true);
+ *
+ * // Any changes to the location hash will call the following function.
+ * function navCallback(e) {
+ *   alert('Navigated to state "' + e.token + '"');
+ * }
+ *
+ * // The history token can also be set from code directly.
+ * h.setToken('foo');
+ * </pre>
+ *
+ * @param {boolean=} opt_invisible True to use hidden history states instead of
+ *     the user-visible location hash.
+ * @param {!goog.html.TrustedResourceUrl|string=} opt_blankPageUrl A URL to a
+ *     blank page on the same server. Required if opt_invisible is true.  If
+ *     possible pass a TrustedResourceUrl; string is supported for
+ *     backwards-compatibility only and uses goog.html.legacyconversions.
+ *     This URL is also used as the src for the iframe used to track history
+ *     state in IE (if not specified the iframe is not given a src attribute).
+ *     Access is Denied error may occur in IE7 if the window's URL's scheme
+ *     is https, and this URL is not specified.
+ * @param {HTMLInputElement=} opt_input The hidden input element to be used to
+ *     store the history token.  If not provided, a hidden input element will
+ *     be created using document.write.
+ * @param {HTMLIFrameElement=} opt_iframe The hidden iframe that will be used by
+ *     IE for pushing history state changes, or by all browsers if opt_invisible
+ *     is true. If not provided, a hidden iframe element will be created using
+ *     document.write.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.History = function(opt_invisible, opt_blankPageUrl, opt_input,
+                        opt_iframe) {
+  goog.events.EventTarget.call(this);
+
+  if (opt_invisible && !opt_blankPageUrl) {
+    throw Error('Can\'t use invisible history without providing a blank page.');
+  }
+
+  var input;
+  if (opt_input) {
+    input = opt_input;
+  } else {
+    var inputId = 'history_state' + goog.History.historyCount_;
+    var inputHtml = goog.html.SafeHtml.create('input',
+        {type: goog.dom.InputType.TEXT, name: inputId, id: inputId,
+          style: goog.string.Const.from('display:none')});
+    goog.dom.safe.documentWrite(document, inputHtml);
+    input = goog.dom.getElement(inputId);
+  }
+
+  /**
+   * An input element that stores the current iframe state. Used to restore
+   * the state when returning to the page on non-IE browsers.
+   * @type {HTMLInputElement}
+   * @private
+   */
+  this.hiddenInput_ = /** @type {HTMLInputElement} */ (input);
+
+  /**
+   * The window whose location contains the history token fragment. This is
+   * the window that contains the hidden input. It's typically the top window.
+   * It is not necessarily the same window that the js code is loaded in.
+   * @type {Window}
+   * @private
+   */
+  this.window_ = opt_input ?
+      goog.dom.getWindow(goog.dom.getOwnerDocument(opt_input)) : window;
+
+  var iframeSrc;
+  if (goog.isString(opt_blankPageUrl)) {
+    iframeSrc = goog.html.legacyconversions.trustedResourceUrlFromString(
+        opt_blankPageUrl);
+  } else {
+    iframeSrc = opt_blankPageUrl;
+  }
+
+  /**
+   * The base URL for the hidden iframe. Must refer to a document in the
+   * same domain as the main page.
+   * @type {!goog.html.TrustedResourceUrl|undefined}
+   * @private
+   */
+  this.iframeSrc_ = iframeSrc;
+
+  if (goog.userAgent.IE && !opt_blankPageUrl) {
+    if (window.location.protocol == 'https') {
+      this.iframeSrc_ = goog.html.TrustedResourceUrl.fromConstant(
+          goog.string.Const.from('https:///'));
+    } else {
+      this.iframeSrc_ = goog.html.TrustedResourceUrl.fromConstant(
+          goog.string.Const.from('javascript:""'));
+    }
+  }
+
+  /**
+   * A timer for polling the current history state for changes.
+   * @type {goog.Timer}
+   * @private
+   */
+  this.timer_ = new goog.Timer(goog.History.PollingType.NORMAL);
+  this.registerDisposable(this.timer_);
+
+  /**
+   * True if the state tokens are displayed in the address bar, false for hidden
+   * history states.
+   * @type {boolean}
+   * @private
+   */
+  this.userVisible_ = !opt_invisible;
+
+  /**
+   * An object to keep track of the history event listeners.
+   * @type {goog.events.EventHandler<!goog.History>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  if (opt_invisible || goog.History.LEGACY_IE) {
+    var iframe;
+    if (opt_iframe) {
+      iframe = opt_iframe;
+    } else {
+      var iframeId = 'history_iframe' + goog.History.historyCount_;
+      // Using a "sandbox" attribute on the iframe might be possible, but
+      // this HTML didn't initially have it and when it was refactored
+      // to SafeHtml it was kept without it.
+      var iframeHtml = goog.html.SafeHtml.createIframe(this.iframeSrc_, null,
+          {id: iframeId, style: goog.string.Const.from('display:none'),
+            sandbox: undefined});
+      goog.dom.safe.documentWrite(document, iframeHtml);
+      iframe = goog.dom.getElement(iframeId);
+    }
+
+    /**
+     * Internet Explorer uses a hidden iframe for all history changes. Other
+     * browsers use the iframe only for pushing invisible states.
+     * @type {HTMLIFrameElement}
+     * @private
+     */
+    this.iframe_ = /** @type {HTMLIFrameElement} */ (iframe);
+
+    /**
+     * Whether the hidden iframe has had a document written to it yet in this
+     * session.
+     * @type {boolean}
+     * @private
+     */
+    this.unsetIframe_ = true;
+  }
+
+  if (goog.History.LEGACY_IE) {
+    // IE relies on the hidden input to restore the history state from previous
+    // sessions, but input values are only restored after window.onload. Set up
+    // a callback to poll the value after the onload event.
+    this.eventHandler_.listen(this.window_,
+                              goog.events.EventType.LOAD,
+                              this.onDocumentLoaded);
+
+    /**
+     * IE-only variable for determining if the document has loaded.
+     * @type {boolean}
+     * @protected
+     */
+    this.documentLoaded = false;
+
+    /**
+     * IE-only variable for storing whether the history object should be enabled
+     * once the document finishes loading.
+     * @type {boolean}
+     * @private
+     */
+    this.shouldEnable_ = false;
+  }
+
+  // Set the initial history state.
+  if (this.userVisible_) {
+    this.setHash_(this.getToken(), true);
+  } else {
+    this.setIframeToken_(this.hiddenInput_.value);
+  }
+
+  goog.History.historyCount_++;
+};
+goog.inherits(goog.History, goog.events.EventTarget);
+
+
+/**
+ * Status of when the object is active and dispatching events.
+ * @type {boolean}
+ * @private
+ */
+goog.History.prototype.enabled_ = false;
+
+
+/**
+ * Whether the object is performing polling with longer intervals. This can
+ * occur for instance when setting the location of the iframe when in invisible
+ * mode and the server that is hosting the blank html page is down. In FF, this
+ * will cause the location of the iframe to no longer be accessible, with
+ * permision denied exceptions being thrown on every access of the history
+ * token. When this occurs, the polling interval is elongated. This causes
+ * exceptions to be thrown at a lesser rate while allowing for the history
+ * object to resurrect itself when the html page becomes accessible.
+ * @type {boolean}
+ * @private
+ */
+goog.History.prototype.longerPolling_ = false;
+
+
+/**
+ * The last token set by the history object, used to poll for changes.
+ * @type {?string}
+ * @private
+ */
+goog.History.prototype.lastToken_ = null;
+
+
+/**
+ * Whether the browser supports HTML5 history management's onhashchange event.
+ * {@link http://www.w3.org/TR/html5/history.html}. IE 9 in compatibility mode
+ * indicates that onhashchange is in window, but testing reveals the event
+ * isn't actually fired.
+ * @return {boolean} Whether onhashchange is supported.
+ */
+goog.History.isOnHashChangeSupported = goog.memoize(function() {
+  return goog.userAgent.IE ?
+      goog.userAgent.isDocumentModeOrHigher(8) :
+      'onhashchange' in goog.global;
+});
+
+
+/**
+ * Whether the current browser is Internet Explorer prior to version 8. Many IE
+ * specific workarounds developed before version 8 are unnecessary in more
+ * current versions.
+ * @type {boolean}
+ */
+goog.History.LEGACY_IE = goog.userAgent.IE &&
+    !goog.userAgent.isDocumentModeOrHigher(8);
+
+
+/**
+ * Whether the browser always requires the hash to be present. Internet Explorer
+ * before version 8 will reload the HTML page if the hash is omitted.
+ * @type {boolean}
+ */
+goog.History.HASH_ALWAYS_REQUIRED = goog.History.LEGACY_IE;
+
+
+/**
+ * If not null, polling in the user invisible mode will be disabled until this
+ * token is seen. This is used to prevent a race condition where the iframe
+ * hangs temporarily while the location is changed.
+ * @type {?string}
+ * @private
+ */
+goog.History.prototype.lockedToken_ = null;
+
+
+/** @override */
+goog.History.prototype.disposeInternal = function() {
+  goog.History.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+  this.setEnabled(false);
+};
+
+
+/**
+ * Starts or stops the History polling loop. When enabled, the History object
+ * will immediately fire an event for the current location. The caller can set
+ * up event listeners between the call to the constructor and the call to
+ * setEnabled.
+ *
+ * On IE, actual startup may be delayed until the iframe and hidden input
+ * element have been loaded and can be polled. This behavior is transparent to
+ * the caller.
+ *
+ * @param {boolean} enable Whether to enable the history polling loop.
+ */
+goog.History.prototype.setEnabled = function(enable) {
+
+  if (enable == this.enabled_) {
+    return;
+  }
+
+  if (goog.History.LEGACY_IE && !this.documentLoaded) {
+    // Wait until the document has actually loaded before enabling the
+    // object or any saved state from a previous session will be lost.
+    this.shouldEnable_ = enable;
+    return;
+  }
+
+  if (enable) {
+    if (goog.userAgent.OPERA) {
+      // Capture events for common user input so we can restart the timer in
+      // Opera if it fails. Yes, this is distasteful. See operaDefibrillator_.
+      this.eventHandler_.listen(this.window_.document,
+                                goog.History.INPUT_EVENTS_,
+                                this.operaDefibrillator_);
+    } else if (goog.userAgent.GECKO) {
+      // Firefox will not restore the correct state after navigating away from
+      // and then back to the page with the history object. This can be fixed
+      // by restarting the history object on the pageshow event.
+      this.eventHandler_.listen(this.window_, 'pageshow', this.onShow_);
+    }
+
+    // TODO(user): make HTML5 and invisible history work by listening to the
+    // iframe # changes instead of the window.
+    if (goog.History.isOnHashChangeSupported() &&
+        this.userVisible_) {
+      this.eventHandler_.listen(
+          this.window_, goog.events.EventType.HASHCHANGE, this.onHashChange_);
+      this.enabled_ = true;
+      this.dispatchEvent(new goog.history.Event(this.getToken(), false));
+    } else if (!(goog.userAgent.IE && !goog.labs.userAgent.device.isMobile()) ||
+               this.documentLoaded) {
+      // Start dispatching history events if all necessary loading has
+      // completed (always true for browsers other than IE.)
+      this.eventHandler_.listen(this.timer_, goog.Timer.TICK,
+          goog.bind(this.check_, this, true));
+
+      this.enabled_ = true;
+
+      // Initialize last token at startup except on IE < 8, where the last token
+      // must only be set in conjunction with IFRAME updates, or the IFRAME will
+      // start out of sync and remove any pre-existing URI fragment.
+      if (!goog.History.LEGACY_IE) {
+        this.lastToken_ = this.getToken();
+        this.dispatchEvent(new goog.history.Event(this.getToken(), false));
+      }
+
+      this.timer_.start();
+    }
+
+  } else {
+    this.enabled_ = false;
+    this.eventHandler_.removeAll();
+    this.timer_.stop();
+  }
+};
+
+
+/**
+ * Callback for the window onload event in IE. This is necessary to read the
+ * value of the hidden input after restoring a history session. The value of
+ * input elements is not viewable until after window onload for some reason (the
+ * iframe state is similarly unavailable during the loading phase.)  If
+ * setEnabled is called before the iframe has completed loading, the history
+ * object will actually be enabled at this point.
+ * @protected
+ */
+goog.History.prototype.onDocumentLoaded = function() {
+  this.documentLoaded = true;
+
+  if (this.hiddenInput_.value) {
+    // Any saved value in the hidden input can only be read after the document
+    // has been loaded due to an IE limitation. Restore the previous state if
+    // it has been set.
+    this.setIframeToken_(this.hiddenInput_.value, true);
+  }
+
+  this.setEnabled(this.shouldEnable_);
+};
+
+
+/**
+ * Handler for the Gecko pageshow event. Restarts the history object so that the
+ * correct state can be restored in the hash or iframe.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.History.prototype.onShow_ = function(e) {
+  // NOTE(user): persisted is a property passed in the pageshow event that
+  // indicates whether the page is being persisted from the cache or is being
+  // loaded for the first time.
+  if (e.getBrowserEvent()['persisted']) {
+    this.setEnabled(false);
+    this.setEnabled(true);
+  }
+};
+
+
+/**
+ * Handles HTML5 onhashchange events on browsers where it is supported.
+ * This is very similar to {@link #check_}, except that it is not executed
+ * continuously. It is only used when
+ * {@code goog.History.isOnHashChangeSupported()} is true.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.History.prototype.onHashChange_ = function(e) {
+  var hash = this.getLocationFragment_(this.window_);
+  if (hash != this.lastToken_) {
+    this.update_(hash, true);
+  }
+};
+
+
+/**
+ * @return {string} The current token.
+ */
+goog.History.prototype.getToken = function() {
+  if (this.lockedToken_ != null) {
+    return this.lockedToken_;
+  } else if (this.userVisible_) {
+    return this.getLocationFragment_(this.window_);
+  } else {
+    return this.getIframeToken_() || '';
+  }
+};
+
+
+/**
+ * Sets the history state. When user visible states are used, the URL fragment
+ * will be set to the provided token.  Sometimes it is necessary to set the
+ * history token before the document title has changed, in this case IE's
+ * history drop down can be out of sync with the token.  To get around this
+ * problem, the app can pass in a title to use with the hidden iframe.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ */
+goog.History.prototype.setToken = function(token, opt_title) {
+  this.setHistoryState_(token, false, opt_title);
+};
+
+
+/**
+ * Replaces the current history state without affecting the rest of the history
+ * stack.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ */
+goog.History.prototype.replaceToken = function(token, opt_title) {
+  this.setHistoryState_(token, true, opt_title);
+};
+
+
+/**
+ * Gets the location fragment for the current URL.  We don't use location.hash
+ * directly as the browser helpfully urlDecodes the string for us which can
+ * corrupt the tokens.  For example, if we want to store: label/%2Froot it would
+ * be returned as label//root.
+ * @param {Window} win The window object to use.
+ * @return {string} The fragment.
+ * @private
+ */
+goog.History.prototype.getLocationFragment_ = function(win) {
+  var href = win.location.href;
+  var index = href.indexOf('#');
+  return index < 0 ? '' : href.substring(index + 1);
+};
+
+
+/**
+ * Sets the history state. When user visible states are used, the URL fragment
+ * will be set to the provided token. Setting opt_replace to true will cause the
+ * navigation to occur, but will replace the current history entry without
+ * affecting the length of the stack.
+ *
+ * @param {string} token The history state identifier.
+ * @param {boolean} replace Set to replace the current history entry instead of
+ *    appending a new history state.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ * @private
+ */
+goog.History.prototype.setHistoryState_ = function(token, replace, opt_title) {
+  if (this.getToken() != token) {
+    if (this.userVisible_) {
+      this.setHash_(token, replace);
+
+      if (!goog.History.isOnHashChangeSupported()) {
+        if (goog.userAgent.IE && !goog.labs.userAgent.device.isMobile()) {
+          // IE must save state using the iframe.
+          this.setIframeToken_(token, replace, opt_title);
+        }
+      }
+
+      // This condition needs to be called even if
+      // goog.History.isOnHashChangeSupported() is true so the NAVIGATE event
+      // fires sychronously.
+      if (this.enabled_) {
+        this.check_(false);
+      }
+    } else {
+      // Fire the event immediately so that setting history is synchronous, but
+      // set a suspendToken so that polling doesn't trigger a 'back'.
+      this.setIframeToken_(token, replace);
+      this.lockedToken_ = this.lastToken_ = this.hiddenInput_.value = token;
+      this.dispatchEvent(new goog.history.Event(token, false));
+    }
+  }
+};
+
+
+/**
+ * Sets or replaces the URL fragment. The token does not need to be URL encoded
+ * according to the URL specification, though certain characters (like newline)
+ * are automatically stripped.
+ *
+ * If opt_replace is not set, non-IE browsers will append a new entry to the
+ * history list. Setting the hash does not affect the history stack in IE
+ * (unless there is a pre-existing named anchor for that hash.)
+ *
+ * Older versions of Webkit cannot query the location hash, but it still can be
+ * set. If we detect one of these versions, always replace instead of creating
+ * new history entries.
+ *
+ * window.location.replace replaces the current state from the history stack.
+ * http://www.whatwg.org/specs/web-apps/current-work/#dom-location-replace
+ * http://www.whatwg.org/specs/web-apps/current-work/#replacement-enabled
+ *
+ * @param {string} token The new string to set.
+ * @param {boolean=} opt_replace Set to true to replace the current token
+ *    without appending a history entry.
+ * @private
+ */
+goog.History.prototype.setHash_ = function(token, opt_replace) {
+  // If the page uses a BASE element, setting location.hash directly will
+  // navigate away from the current document. Also, the original URL path may
+  // possibly change from HTML5 history pushState. To account for these, the
+  // full path is always specified.
+  var loc = this.window_.location;
+  var url = loc.href.split('#')[0];
+
+  // If a hash has already been set, then removing it programmatically will
+  // reload the page. Once there is a hash, we won't remove it.
+  var hasHash = goog.string.contains(loc.href, '#');
+
+  if (goog.History.HASH_ALWAYS_REQUIRED || hasHash || token) {
+    url += '#' + token;
+  }
+
+  if (url != loc.href) {
+    if (opt_replace) {
+      loc.replace(url);
+    } else {
+      loc.href = url;
+    }
+  }
+};
+
+
+/**
+ * Sets the hidden iframe state. On IE, this is accomplished by writing a new
+ * document into the iframe. In Firefox, the iframe's URL fragment stores the
+ * state instead.
+ *
+ * Older versions of webkit cannot set the iframe, so ignore those browsers.
+ *
+ * @param {string} token The new string to set.
+ * @param {boolean=} opt_replace Set to true to replace the current iframe state
+ *     without appending a new history entry.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ * @private
+ */
+goog.History.prototype.setIframeToken_ = function(token,
+                                                  opt_replace,
+                                                  opt_title) {
+  if (this.unsetIframe_ || token != this.getIframeToken_()) {
+
+    this.unsetIframe_ = false;
+    token = goog.string.urlEncode(token);
+
+    if (goog.userAgent.IE) {
+      // Caching the iframe document results in document permission errors after
+      // leaving the page and returning. Access it anew each time instead.
+      var doc = goog.dom.getFrameContentDocument(this.iframe_);
+
+      doc.open('text/html', opt_replace ? 'replace' : undefined);
+      var iframeSourceHtml = goog.html.SafeHtml.concat(
+          goog.html.SafeHtml.create('title', {},
+              (opt_title || this.window_.document.title)),
+          goog.html.SafeHtml.create('body', {}, token));
+      goog.dom.safe.documentWrite(doc, iframeSourceHtml);
+      doc.close();
+    } else {
+      goog.asserts.assertInstanceof(
+          this.iframeSrc_, goog.html.TrustedResourceUrl,
+          'this.iframeSrc_ must be set on calls to setIframeToken_');
+      var url = goog.html.TrustedResourceUrl.unwrap(
+          /** @type {!goog.html.TrustedResourceUrl} */ (this.iframeSrc_)) +
+              '#' + token;
+
+      // In Safari, it is possible for the contentWindow of the iframe to not
+      // be present when the page is loading after a reload.
+      var contentWindow = this.iframe_.contentWindow;
+      if (contentWindow) {
+        if (opt_replace) {
+          contentWindow.location.replace(url);
+        } else {
+          contentWindow.location.href = url;
+        }
+      }
+    }
+  }
+};
+
+
+/**
+ * Return the current state string from the hidden iframe. On internet explorer,
+ * this is stored as a string in the document body. Other browsers use the
+ * location hash of the hidden iframe.
+ *
+ * Older versions of webkit cannot access the iframe location, so always return
+ * null in that case.
+ *
+ * @return {?string} The state token saved in the iframe (possibly null if the
+ *     iframe has never loaded.).
+ * @private
+ */
+goog.History.prototype.getIframeToken_ = function() {
+  if (goog.userAgent.IE) {
+    var doc = goog.dom.getFrameContentDocument(this.iframe_);
+    return doc.body ? goog.string.urlDecode(doc.body.innerHTML) : null;
+  } else {
+    // In Safari, it is possible for the contentWindow of the iframe to not
+    // be present when the page is loading after a reload.
+    var contentWindow = this.iframe_.contentWindow;
+    if (contentWindow) {
+      var hash;
+      /** @preserveTry */
+      try {
+        // Iframe tokens are urlEncoded
+        hash = goog.string.urlDecode(this.getLocationFragment_(contentWindow));
+      } catch (e) {
+        // An exception will be thrown if the location of the iframe can not be
+        // accessed (permission denied). This can occur in FF if the the server
+        // that is hosting the blank html page goes down and then a new history
+        // token is set. The iframe will navigate to an error page, and the
+        // location of the iframe can no longer be accessed. Due to the polling,
+        // this will cause constant exceptions to be thrown. In this case,
+        // we enable longer polling. We do not have to attempt to reset the
+        // iframe token because (a) we already fired the NAVIGATE event when
+        // setting the token, (b) we can rely on the locked token for current
+        // state, and (c) the token is still in the history and
+        // accesible on forward/back.
+        if (!this.longerPolling_) {
+          this.setLongerPolling_(true);
+        }
+
+        return null;
+      }
+
+      // There was no exception when getting the hash so turn off longer polling
+      // if it is on.
+      if (this.longerPolling_) {
+        this.setLongerPolling_(false);
+      }
+
+      return hash || null;
+    } else {
+      return null;
+    }
+  }
+};
+
+
+/**
+ * Checks the state of the document fragment and the iframe title to detect
+ * navigation changes. If {@code goog.HistoryisOnHashChangeSupported()} is
+ * {@code false}, then this runs approximately twenty times per second.
+ * @param {boolean} isNavigation True if the event was initiated by a browser
+ *     action, false if it was caused by a setToken call. See
+ *     {@link goog.history.Event}.
+ * @private
+ */
+goog.History.prototype.check_ = function(isNavigation) {
+  if (this.userVisible_) {
+    var hash = this.getLocationFragment_(this.window_);
+    if (hash != this.lastToken_) {
+      this.update_(hash, isNavigation);
+    }
+  }
+
+  // Old IE uses the iframe for both visible and non-visible versions.
+  if (!this.userVisible_ || goog.History.LEGACY_IE) {
+    var token = this.getIframeToken_() || '';
+    if (this.lockedToken_ == null || token == this.lockedToken_) {
+      this.lockedToken_ = null;
+      if (token != this.lastToken_) {
+        this.update_(token, isNavigation);
+      }
+    }
+  }
+};
+
+
+/**
+ * Updates the current history state with a given token. Called after a change
+ * to the location or the iframe state is detected by poll_.
+ *
+ * @param {string} token The new history state.
+ * @param {boolean} isNavigation True if the event was initiated by a browser
+ *     action, false if it was caused by a setToken call. See
+ *     {@link goog.history.Event}.
+ * @private
+ */
+goog.History.prototype.update_ = function(token, isNavigation) {
+  this.lastToken_ = this.hiddenInput_.value = token;
+
+  if (this.userVisible_) {
+    if (goog.History.LEGACY_IE) {
+      this.setIframeToken_(token);
+    }
+
+    this.setHash_(token);
+  } else {
+    this.setIframeToken_(token);
+  }
+
+  this.dispatchEvent(new goog.history.Event(this.getToken(), isNavigation));
+};
+
+
+/**
+ * Sets if the history oject should use longer intervals when polling.
+ *
+ * @param {boolean} longerPolling Whether to enable longer polling.
+ * @private
+ */
+goog.History.prototype.setLongerPolling_ = function(longerPolling) {
+  if (this.longerPolling_ != longerPolling) {
+    this.timer_.setInterval(longerPolling ?
+        goog.History.PollingType.LONG : goog.History.PollingType.NORMAL);
+  }
+  this.longerPolling_ = longerPolling;
+};
+
+
+/**
+ * Opera cancels all outstanding timeouts and intervals after any rapid
+ * succession of navigation events, including the interval used to detect
+ * navigation events. This function restarts the interval so that navigation can
+ * continue. Ideally, only events which would be likely to cause a navigation
+ * change (mousedown and keydown) would be bound to this function. Since Opera
+ * seems to ignore keydown events while the alt key is pressed (such as
+ * alt-left or right arrow), this function is also bound to the much more
+ * frequent mousemove event. This way, when the update loop freezes, it will
+ * unstick itself as the user wiggles the mouse in frustration.
+ * @private
+ */
+goog.History.prototype.operaDefibrillator_ = function() {
+  this.timer_.stop();
+  this.timer_.start();
+};
+
+
+/**
+ * List of user input event types registered in Opera to restart the history
+ * timer (@see goog.History#operaDefibrillator_).
+ * @type {Array<string>}
+ * @private
+ */
+goog.History.INPUT_EVENTS_ = [
+  goog.events.EventType.MOUSEDOWN,
+  goog.events.EventType.KEYDOWN,
+  goog.events.EventType.MOUSEMOVE
+];
+
+
+/**
+ * Counter for the number of goog.History objects that have been instantiated.
+ * Used to create unique IDs.
+ * @type {number}
+ * @private
+ */
+goog.History.historyCount_ = 0;
+
+
+/**
+ * Types of polling. The values are in ms of the polling interval.
+ * @enum {number}
+ */
+goog.History.PollingType = {
+  NORMAL: 150,
+  LONG: 10000
+};
+
+
+/**
+ * Constant for the history change event type.
+ * @enum {string}
+ * @deprecated Use goog.history.EventType.
+ */
+goog.History.EventType = goog.history.EventType;
+
+
+
+/**
+ * Constant for the history change event type.
+ * @param {string} token The string identifying the new history state.
+ * @extends {goog.events.Event}
+ * @constructor
+ * @deprecated Use goog.history.Event.
+ * @final
+ */
+goog.History.Event = goog.history.Event;


Mime
View raw message