Bug 928969 - Update Shumway to version 0.7.501. r=till
authorYury Delendik <ydelendik@mozilla.com>
Mon, 21 Oct 2013 11:01:48 -0500
changeset 165669 7a457cfcaa9ad94ff64dd9fa5df52e94b622c806
parent 165668 8d7026e79fae67e7ffe4a67f31c38e6f58a070c9
child 165670 a61d898ea4facb179c6ba93820acbbbb0b1885a8
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs928969
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 928969 - Update Shumway to version 0.7.501. r=till
browser/extensions/shumway/content/ShumwayStreamConverter.jsm
browser/extensions/shumway/content/avm2/generated/avm1lib/avm1lib.abc
browser/extensions/shumway/content/shumway-worker.js
browser/extensions/shumway/content/shumway.js
browser/extensions/shumway/content/version.txt
--- a/browser/extensions/shumway/content/ShumwayStreamConverter.jsm
+++ b/browser/extensions/shumway/content/ShumwayStreamConverter.jsm
@@ -239,49 +239,56 @@ ChromeActions.prototype = {
 
     // TODO flash cross-origin request
     if (url === this.url) {
       // allow downloading for the original file
       return callback({success: true});
     }
 
     // allows downloading from the same origin
-    var urlPrefix = /^(https?):\/\/([A-Za-z0-9\-_\.\[\]]+)/i.exec(url);
-    var basePrefix = /^(https?):\/\/([A-Za-z0-9\-_\.\[\]]+)/i.exec(this.url);
-    if (basePrefix && urlPrefix && basePrefix[0] === urlPrefix[0]) {
+    var parsedUrl, parsedBaseUrl;
+    try {
+      parsedUrl = NetUtil.newURI(url);
+    } catch (ex) { /* skipping invalid urls */ }
+    try {
+      parsedBaseUrl = NetUtil.newURI(this.url);
+    } catch (ex) { /* skipping invalid urls */ }
+
+    if (parsedUrl && parsedBaseUrl &&
+        parsedUrl.prePath === parsedBaseUrl.prePath) {
       return callback({success: true});
     }
 
     // additionally using internal whitelist
     var whitelist = getStringPref('shumway.whitelist', '');
-    if (whitelist && urlPrefix) {
+    if (whitelist && parsedUrl) {
       var whitelisted = whitelist.split(',').some(function (i) {
-        return domainMatches(urlPrefix[2], i);
+        return domainMatches(parsedUrl.host, i);
       });
       if (whitelisted) {
         return callback({success: true});
       }
     }
 
-    if (!checkPolicyFile || !urlPrefix || !basePrefix) {
+    if (!checkPolicyFile || !parsedUrl || !parsedBaseUrl) {
       return callback({success: false});
     }
 
     // we can request crossdomain.xml
-    fetchPolicyFile(urlPrefix[0] + '/crossdomain.xml', this.crossdomainRequestsCache,
+    fetchPolicyFile(parsedUrl.prePath + '/crossdomain.xml', this.crossdomainRequestsCache,
       function (policy, error) {
 
       if (!policy || policy.siteControl === 'none') {
         return callback({success: false});
       }
       // TODO assuming master-only, there are also 'by-content-type', 'all', etc.
 
       var allowed = policy.allowAccessFrom.some(function (i) {
-        return domainMatches(basePrefix[2], i.domain) &&
-          (!i.secure || basePrefix[1].toLowerCase() === 'https');
+        return domainMatches(parsedBaseUrl.host, i.domain) &&
+          (!i.secure || parsedBaseUrl.scheme.toLowerCase() === 'https');
       });
       return callback({success: allowed});
     }.bind(this));
   },
   loadFile: function loadFile(data) {
     var url = data.url;
     var checkPolicyFile = data.checkPolicyFile;
     var sessionId = data.sessionId;
index a452e2b10f82e5b07f3bd261cb98b1555fc31848..0f9c67914b5135a8fbda922d10a03e2335fef5a1
GIT binary patch
literal 26518
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
--- a/browser/extensions/shumway/content/shumway-worker.js
+++ b/browser/extensions/shumway/content/shumway-worker.js
@@ -218,16 +218,19 @@ var Promise = function PromiseClosure() 
         subpromises[i].fulfill(value);
       }
       delete subject.subpromises;
     }
     function propagateRejected(subject, reason) {
       subject.subpromisesReason = reason;
       var subpromises = subject.subpromises;
       if (!subpromises) {
+        if (!true) {
+          console.warn(reason);
+        }
         return;
       }
       for (var i = 0; i < subpromises.length; i++) {
         subpromises[i].reject(reason);
       }
       delete subject.subpromises;
     }
     function performCall(callback, arg, subject) {
@@ -436,16 +439,22 @@ QuadTree.prototype._subdivide = function
   this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, level);
 };
 var EXTERNAL_INTERFACE_FEATURE = 1;
 var CLIPBOARD_FEATURE = 2;
 var SHAREDOBJECT_FEATURE = 3;
 var VIDEO_FEATURE = 4;
 var SOUND_FEATURE = 5;
 var NETCONNECTION_FEATURE = 6;
+if (!this.performance) {
+  this.performance = {};
+}
+if (!this.performance.now) {
+  this.performance.now = Date.now;
+}
 var create = Object.create;
 var defineProperty = Object.defineProperty;
 var keys = Object.keys;
 var isArray = Array.isArray;
 var fromCharCode = String.fromCharCode;
 var logE = Math.log;
 var max = Math.max;
 var min = Math.min;
@@ -910,19 +919,20 @@ function defineFont(tag, dictionary) {
       indices.push(i);
     }
     ranges.push([
       UAC_OFFSET,
       UAC_OFFSET + glyphCount - 1,
       indices
     ]);
   }
-  var ascent = Math.ceil(tag.ascent / 20) || 1024;
-  var descent = -Math.ceil(tag.descent / 20) || 0;
-  var leading = Math.floor(tag.leading / 20) || 0;
+  var resolution = tag.resolution || 1;
+  var ascent = Math.ceil(tag.ascent / resolution) || 1024;
+  var descent = -Math.ceil(tag.descent / resolution) | 0;
+  var leading = tag.leading / resolution | 0;
   tables['OS/2'] = '\0\x01\0\0' + toString16(tag.bold ? 700 : 400) + '\0\x05' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0\0\0\0\0\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + 'ALF ' + toString16((tag.italic ? 1 : 0) | (tag.bold ? 32 : 0)) + toString16(codes[0]) + toString16(codes[codes.length - 1]) + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(ascent) + toString16(-descent) + '\0\0\0\0' + '\0\0\0\0';
   ;
   var startCount = '';
   var endCount = '';
   var idDelta = '';
   var idRangeOffset = '';
   var i = 0;
   var range;
@@ -943,17 +953,16 @@ function defineFont(tag, dictionary) {
   var searchRange = maxPower2(segCount) * 2;
   var rangeShift = 2 * segCount - searchRange;
   var format314 = '\0\0' + toString16(segCount * 2) + toString16(searchRange) + toString16(logE(segCount) / logE(2)) + toString16(rangeShift) + endCount + '\0\0' + startCount + idDelta + idRangeOffset;
   ;
   tables['cmap'] = '\0\0\0\x01\0\x03\0\x01\0\0\0\f\0\x04' + toString16(format314.length + 4) + format314;
   ;
   var glyf = '\0\x01\0\0\0\0\0\0\0\0\0\0\0\x001\0';
   var loca = '\0\0';
-  var resolution = tag.resolution || 1;
   var offset = 16;
   var maxPoints = 0;
   var xMins = [];
   var xMaxs = [];
   var yMins = [];
   var yMaxs = [];
   var maxContours = 0;
   var i = 0;
@@ -1068,20 +1077,19 @@ function defineFont(tag, dictionary) {
     yMaxs.push(yMax);
     if (numberOfContours > maxContours)
       maxContours = numberOfContours;
     if (endPoint > maxPoints)
       maxPoints = endPoint;
   }
   loca += toString16(offset / 2);
   tables['glyf'] = glyf;
-  tables['head'] = '\0\x01\0\0\0\x01\0\0\0\0\0\0_\x0f<\xf5\0\v\x04\0\0\0\0\0' + toString32(+new Date()) + '\0\0\0\0' + toString32(+new Date()) + toString16(min.apply(null, xMins)) + toString16(min.apply(null, yMins)) + toString16(max.apply(null, xMaxs)) + toString16(max.apply(null, yMaxs)) + toString16((tag.italic ? 2 : 0) | (tag.bold ? 1 : 0)) + '\0\b' + '\0\x02' + '\0\0' + '\0\0';
+  tables['head'] = '\0\x01\0\0\0\x01\0\0\0\0\0\0_\x0f<\xf5\0\v\x04\0\0\0\0\0' + toString32(Date.now()) + '\0\0\0\0' + toString32(Date.now()) + toString16(min.apply(null, xMins)) + toString16(min.apply(null, yMins)) + toString16(max.apply(null, xMaxs)) + toString16(max.apply(null, yMaxs)) + toString16((tag.italic ? 2 : 0) | (tag.bold ? 1 : 0)) + '\0\b' + '\0\x02' + '\0\0' + '\0\0';
   ;
   var advance = tag.advance;
-  var resolution = tag.resolution || 1;
   tables['hhea'] = '\0\x01\0\0' + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(advance ? max.apply(null, advance) : 1024) + '\0\0' + '\0\0' + '\x03\xb8' + '\0\x01' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + toString16(glyphCount + 1);
   ;
   var hmtx = '\0\0\0\0';
   for (var i = 0; i < glyphCount; ++i)
     hmtx += toString16(advance ? advance[i] / resolution : 1024) + '\0\0';
   tables['hmtx'] = hmtx;
   if (tag.kerning) {
     var kerning = tag.kerning;
@@ -1148,26 +1156,28 @@ function defineFont(tag, dictionary) {
     while (offset & 3)
       ++offset;
     offset += length;
   }
   var otf = header + data;
   var unitPerEm = 1024;
   var metrics = {
       ascent: ascent / unitPerEm,
-      descent: descent / unitPerEm,
+      descent: -descent / unitPerEm,
       leading: leading / unitPerEm
     };
   return {
     type: 'font',
     id: tag.id,
     name: fontName,
     uniqueName: psName + uniqueId,
     codes: codes,
     metrics: metrics,
+    bold: tag.bold === 1,
+    italic: tag.italic === 1,
     data: otf
   };
 }
 function getUint16(buff, pos) {
   return buff[pos] << 8 | buff[pos + 1];
 }
 function parseJpegChunks(imgDef, bytes) {
   var i = 0;
@@ -1235,18 +1245,18 @@ function defineLabel(tag, dictionary) {
   var m = tag.matrix;
   var cmds = [
       'c.save()',
       'c.transform(' + [
         m.a,
         m.b,
         m.c,
         m.d,
-        m.tx,
-        m.ty
+        m.tx / 20,
+        m.ty / 20
       ].join(',') + ')',
       'c.scale(0.05, 0.05)'
     ];
   var dependencies = [];
   var x = 0;
   var y = 0;
   var i = 0;
   var record;
@@ -1728,19 +1738,18 @@ SegmentedPath.prototype = {
   }
 };
 var SHAPE_MOVE_TO = 1;
 var SHAPE_LINE_TO = 2;
 var SHAPE_CURVE_TO = 3;
 var SHAPE_WIDE_MOVE_TO = 4;
 var SHAPE_WIDE_LINE_TO = 5;
 var SHAPE_CUBIC_CURVE_TO = 6;
-var SHAPE_ROUND_CORNER = 7;
-var SHAPE_CIRCLE = 8;
-var SHAPE_ELLIPSE = 9;
+var SHAPE_CIRCLE = 7;
+var SHAPE_ELLIPSE = 8;
 function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   if (commandsCount) {
     this.commands = new Uint8Array(commandsCount);
     this.data = new Int32Array(dataLength);
     this.morphData = isMorph ? new Int32Array(dataLength) : null;
   } else {
@@ -1779,20 +1788,16 @@ ShapePath.prototype = {
     var y2 = y + h;
     this.commands.push(SHAPE_MOVE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO);
     this.data.push(x, y, x2, y, x2, y2, x, y2, x, y);
   },
   circle: function (x, y, radius) {
     this.commands.push(SHAPE_CIRCLE);
     this.data.push(x, y, radius);
   },
-  drawRoundCorner: function (cornerX, cornerY, curveEndX, curveEndY, radiusX, radiusY) {
-    this.commands.push(SHAPE_ROUND_CORNER);
-    this.data.push(cornerX, cornerY, curveEndX, curveEndY, radiusX, radiusY);
-  },
   ellipse: function (x, y, radiusX, radiusY) {
     this.commands.push(SHAPE_ELLIPSE);
     this.data.push(x, y, radiusX, radiusY);
   },
   draw: function (ctx, clip, ratio, colorTransform) {
     if (clip && !this.fillStyle) {
       return;
     }
@@ -1824,19 +1829,16 @@ ShapePath.prototype = {
           k += 2;
           break;
         case SHAPE_CURVE_TO:
           ctx.quadraticCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
           break;
         case SHAPE_CUBIC_CURVE_TO:
           ctx.bezierCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
           break;
-        case SHAPE_ROUND_CORNER:
-          ctx.arcTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
-          break;
         case SHAPE_CIRCLE:
           if (formOpen) {
             ctx.lineTo(formOpenX, formOpenY);
             formOpen = false;
           }
           ctx.moveTo((data[k] + data[k + 2]) / 20, data[k + 1] / 20);
           ctx.arc(data[k++] / 20, data[k++] / 20, data[k++] / 20, 0, Math.PI * 2, false);
           break;
@@ -1889,16 +1891,17 @@ ShapePath.prototype = {
           console.warn('Drawing command not supported for morph shapes: ' + commands[j]);
         }
       }
     }
     if (!clip) {
       var fillStyle = this.fillStyle;
       if (fillStyle) {
         colorTransform.setFillStyle(ctx, fillStyle.style);
+        ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = fillStyle.smooth;
         var m = fillStyle.transform;
         ctx.save();
         colorTransform.setAlpha(ctx);
         if (m) {
           ctx.transform(m.a, m.b, m.c, m.d, m.e / 20, m.f / 20);
         }
         ctx.fill();
         ctx.restore();
@@ -2018,43 +2021,16 @@ ShapePath.prototype = {
         }
         var roots = cubicXAtY(fromX, fromY, cpX, cpY, cp2X, cp2Y, toX, toY, y);
         for (var i = roots.length; i--;) {
           if (roots[i] >= x) {
             inside = !inside;
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        cpX = data[dataIndex++];
-        cpY = data[dataIndex++];
-        toX = data[dataIndex++];
-        toY = data[dataIndex++];
-        rX = data[dataIndex++];
-        rY = data[dataIndex++];
-        if (toY > y === fromY > y || fromX < x && toX < x) {
-          break;
-        }
-        if (fromX >= x && toX >= x) {
-          inside = !inside;
-          break;
-        }
-        if (toX > fromX === toY > fromY) {
-          cp2X = fromX;
-          cp2Y = toY;
-        } else {
-          cp2X = toX;
-          cp2Y = fromY;
-        }
-        localX = x - cp2X;
-        localY = y - cp2Y;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) <= 1 !== localX <= 0) {
-          inside = !inside;
-        }
-        break;
       case SHAPE_CIRCLE:
         toX = data[dataIndex++];
         toY = data[dataIndex++];
         var r = data[dataIndex++];
         localX = x - toX;
         localY = y - toY;
         if (localX * localX + localY * localY < r * r) {
           inside = !inside;
@@ -2207,46 +2183,16 @@ ShapePath.prototype = {
           if (curveY < minY || curveY > maxY) {
             continue;
           }
           if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
             return true;
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        cpX = data[dataIndex++];
-        cpY = data[dataIndex++];
-        toX = data[dataIndex++];
-        toY = data[dataIndex++];
-        rX = data[dataIndex++];
-        rY = data[dataIndex++];
-        if (maxX < fromX && maxX < toX || minX > fromX && minX > toX || maxY < fromY && maxY < toY || minY > fromY && minY > toY) {
-          break;
-        }
-        if (toX > fromX === toY > fromY) {
-          cp2X = fromX;
-          cp2Y = toY;
-        } else {
-          cp2X = toX;
-          cp2Y = fromY;
-        }
-        localX = Math.abs(x - cp2X);
-        localY = Math.abs(y - cp2Y);
-        localX -= halfWidth;
-        localY -= halfWidth;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
-          break;
-        }
-        localX += width;
-        localY += width;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
-          return true;
-        }
-        break;
       case SHAPE_CIRCLE:
         cpX = data[dataIndex++];
         cpY = data[dataIndex++];
         var r = data[dataIndex++];
         toX = cpX + r;
         toY = cpY;
         if (maxX < cpX - r || minX > cpX + r || maxY < cpY - r || minY > cpY + r) {
           break;
@@ -2298,17 +2244,17 @@ ShapePath.prototype = {
     }
     return bounds;
   },
   _calculateBounds: function () {
     var commands = this.commands;
     var data = this.data;
     var length = commands.length;
     var bounds;
-    if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_ROUND_CORNER) {
+    if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_CUBIC_CURVE_TO) {
       bounds = {
         xMin: data[0],
         yMin: data[1]
       };
     } else {
       bounds = {
         xMin: 0,
         yMin: 0
@@ -2369,19 +2315,16 @@ ShapePath.prototype = {
         }
         if (cpY < fromY || cp2Y < fromY || cpY > toY || cp2Y > toY) {
           extremes = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
           for (i = extremes.length; i--;) {
             extendBoundsByY(bounds, extremes[i]);
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        dataIndex += 6;
-        break;
       case SHAPE_CIRCLE:
         toX = data[dataIndex++];
         toY = data[dataIndex++];
         var radius = data[dataIndex++];
         extendBoundsByPoint(bounds, toX - radius, toY - radius);
         extendBoundsByPoint(bounds, toX + radius, toY + radius);
         toX += radius;
         break;
@@ -2649,17 +2592,17 @@ function finishShapePaths(paths, diction
       path.morphData = untypedPath.morphData;
     }
     path.fillStyle && initStyle(path.fillStyle, dictionary);
     path.lineStyle && initStyle(path.lineStyle, dictionary);
     path.fullyInitialized = true;
   }
 }
 var inWorker = typeof window === 'undefined';
-var factoryCtx = !inWorker ? document.createElement('canvas').getContext('kanvas-2d') : null;
+var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
 function buildLinearGradientFactory(colorStops) {
   var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createLinearGradient(ctx, colorTransform) {
     var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
     for (var i = 0; i < colorStops.length; i++) {
@@ -4027,16 +3970,18 @@ var LoaderDefinition = function () {
                 }, 200);
                 promiseQueue.push(fontPromise);
               }
             }
             className = 'flash.text.Font';
             props.name = symbol.name;
             props.uniqueName = symbol.uniqueName;
             props.charset = symbol.charset;
+            props.bold = symbol.bold;
+            props.italic = symbol.italic;
             props.metrics = symbol.metrics;
             this._registerFont(className, props);
             break;
           case 'image':
             var img = new Image();
             var imgPromise = new Promise();
             img.onload = function () {
               if (symbol.mask) {
@@ -4199,16 +4144,19 @@ var LoaderDefinition = function () {
           });
           loader._dictionary[0] = documentPromise;
           loader._lastPromise = documentPromise;
           loader._vmPromise = vmPromise;
           loader._isAvm2Enabled = info.fileAttributes.doAbc;
           this._setup();
         },
         _load: function (request, checkPolicyFile, applicationDomain, securityDomain, deblockingFilter) {
+          if (!isWorker && flash.net.URLRequest.class.isInstanceOf(request)) {
+            this._contentLoaderInfo._url = request._url;
+          }
           if (!isWorker && WORKERS_ENABLED) {
             var loader = this;
             var worker = loader._worker = new Worker(SHUMWAY_ROOT + LOADER_PATH);
             worker.onmessage = function (evt) {
               loader._commitData(evt.data);
             };
             if (flash.net.URLRequest.class.isInstanceOf(request)) {
               var session = FileLoadingService.createSession();
@@ -4286,17 +4234,17 @@ var LoaderDefinition = function () {
           _getJPEGLoaderContextdeblockingfilter: function (context) {
             return 0;
           },
           _load: def._load,
           _loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) {
             def._load(bytes.a);
           },
           _unload: function _unload(halt, gc) {
-            notImplemented('Loader._unload');
+            somewhatImplemented('Loader._unload, do we even need to do anything here?');
           },
           _close: function _close() {
             somewhatImplemented('Loader._close');
           },
           _getUncaughtErrorEvents: function _getUncaughtErrorEvents() {
             somewhatImplemented('Loader._getUncaughtErrorEvents');
             return this._uncaughtErrorEvents;
           },
@@ -4946,187 +4894,23 @@ var tagHandler = function (global) {
             $29.depth = readUi16($bytes, $stream);
             var $30 = $29.matrix = {};
             matrix($bytes, $stream, $30, swfVersion, tagCode);
             if (tagCode === 34) {
               var $31 = $29.cxform = {};
               cxform($bytes, $stream, $31, swfVersion, tagCode);
             }
             if (hasFilters) {
-              $29.filterCount = readUi8($bytes, $stream);
-              var $32 = $29.filters = {};
-              var type = $32.type = readUi8($bytes, $stream);
-              switch (type) {
-              case 0:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $33 = $32.colors = [];
-                var $34 = count;
-                while ($34--) {
-                  var $35 = {};
-                  rgba($bytes, $stream, $35, swfVersion, tagCode);
-                  $33.push($35);
-                }
-                if (type === 3) {
-                  var $36 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $36, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $37 = $32.ratios = [];
-                  var $38 = count;
-                  while ($38--) {
-                    $37.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              case 1:
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                $32.passes = readUb($bytes, $stream, 5);
-                var reserved = readUb($bytes, $stream, 3);
-                break;
-              case 2:
-              case 3:
-              case 4:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $39 = $32.colors = [];
-                var $40 = count;
-                while ($40--) {
-                  var $41 = {};
-                  rgba($bytes, $stream, $41, swfVersion, tagCode);
-                  $39.push($41);
-                }
-                if (type === 3) {
-                  var $42 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $42, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $43 = $32.ratios = [];
-                  var $44 = count;
-                  while ($44--) {
-                    $43.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              case 5:
-                var columns = $32.columns = readUi8($bytes, $stream);
-                var rows = $32.rows = readUi8($bytes, $stream);
-                $32.divisor = readFloat($bytes, $stream);
-                $32.bias = readFloat($bytes, $stream);
-                var $45 = $32.weights = [];
-                var $46 = columns * rows;
-                while ($46--) {
-                  $45.push(readFloat($bytes, $stream));
-                }
-                var $47 = $32.defaultColor = {};
-                rgba($bytes, $stream, $47, swfVersion, tagCode);
-                var reserved = readUb($bytes, $stream, 6);
-                $32.clamp = readUb($bytes, $stream, 1);
-                $32.preserveAlpha = readUb($bytes, $stream, 1);
-                break;
-              case 6:
-                var $48 = $32.matrix = [];
-                var $49 = 20;
-                while ($49--) {
-                  $48.push(readFloat($bytes, $stream));
-                }
-                break;
-              case 7:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $50 = $32.colors = [];
-                var $51 = count;
-                while ($51--) {
-                  var $52 = {};
-                  rgba($bytes, $stream, $52, swfVersion, tagCode);
-                  $50.push($52);
-                }
-                if (type === 3) {
-                  var $53 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $53, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $54 = $32.ratios = [];
-                  var $55 = count;
-                  while ($55--) {
-                    $54.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              default:
+              var count = readUi8($bytes, $stream);
+              var $2 = $.filters = [];
+              var $3 = count;
+              while ($3--) {
+                var $4 = {};
+                anyFilter($bytes, $stream, $4, swfVersion, tagCode);
+                $2.push($4);
               }
             }
             if (blend) {
               $29.blendMode = readUi8($bytes, $stream);
             }
           }
           $28.push($29);
         } while (!eob);
@@ -6510,19 +6294,19 @@ BodyParser.prototype = {
     } else {
       buffer.push(data);
       stream = buffer.createStream();
     }
     if (progressInfo) {
       swf.bytesLoaded = progressInfo.bytesLoaded;
       swf.bytesTotal = progressInfo.bytesTotal;
     }
-    var readStartTime = Date.now();
+    var readStartTime = performance.now();
     readTags(swf, stream, swfVersion, options.onprogress);
-    swf.parseTime += Date.now() - readStartTime;
+    swf.parseTime += performance.now() - readStartTime;
     var read = stream.pos;
     buffer.removeHead(read);
     this.totalRead += read;
     if (this.totalRead >= this.length && options.oncomplete) {
       options.oncomplete(swf);
     }
   }
 };
--- a/browser/extensions/shumway/content/shumway.js
+++ b/browser/extensions/shumway/content/shumway.js
@@ -151,1604 +151,16 @@
       for (var i = 0; i < size; i++)
         view._bytes[offset + i] = temp[size - 1 - i];
     }
   }
   function fail(msg) {
     throw new Error(msg);
   }
 }(this));
-;
-var Kanvas = Kanvas || function (doc, undefined) {
-    var PATH_OP_CLOSE = 0;
-    var PATH_OP_MOVE = 1;
-    var PATH_OP_LINE = 2;
-    var PATH_OP_CURVE = 3;
-    var PATH_OP_BEZIER = 4;
-    var PATH_OP_ARCTO = 5;
-    var PATH_OP_RECT = 6;
-    var PATH_OP_ARC = 7;
-    var PATH_OP_ELLIPSE = 8;
-    var PATH_OP_TRANSFORM = 9;
-    var PI = Math.PI;
-    var PI_DOUBLE = PI * 2;
-    var PI_HALF = PI / 2;
-    var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
-    var Kanvas = {
-        VERSION: '0.0.0'
-      };
-    var nativeCanvas = doc.createElement('canvas');
-    var nativeCanvasClass = nativeCanvas.constructor;
-    var native2dCtx = nativeCanvas.getContext('2d');
-    var native2dCtxClass = native2dCtx.constructor;
-    var nativeCanvasProto = nativeCanvasClass.prototype;
-    var native2dCtxProto = native2dCtxClass.prototype;
-    var kanvas2dCtxProto = Object.create(null);
-    var nativePathClass = typeof Path === 'undefined' ? undefined : Path;
-    var nativePathProto = nativePathClass && nativePathClass.prototype;
-    var kanvasPathProto = Object.create(null);
-    var shimCurrentTransform = !('currentTransform' in native2dCtx);
-    var shimResetTransform = !('resetTransform' in native2dCtxProto);
-    var shimEllipticalArcTo = false;
-    try {
-      native2dCtx.arcTo(0, 0, 1, 1, 1, -1);
-    } catch (e) {
-      shimEllipticalArcTo = true;
-    }
-    var shimEllipse = !('ellipse' in native2dCtxProto);
-    var shimPath = !nativePathClass;
-    var shimBounds = shimPath;
-    var shimStrokePath = shimPath;
-    if (!shimPath) {
-      shimBounds = !('getBounds' in nativePathProto);
-      shimStrokePath = !('StrokePath' in nativePathProto);
-      shimPath = shimBounds || shimStrokePath;
-    }
-    var shimHitRegions = !('addHitRegions' in native2dCtxProto);
-    var defineProp = Object.defineProperty;
-    var getOwnPropDesc = Object.getOwnPropertyDescriptor;
-    var getOwnPropNames = Object.getOwnPropertyNames;
-    var transformClass, idTransform, pathClass;
-    function defineLazyProp(obj, prop, desc) {
-      defineProp(obj, prop, {
-        get: function () {
-          if (this === obj)
-            return;
-          var existing = getOwnPropDesc(this, prop);
-          if (existing && 'value' in existing) {
-            return existing.value;
-          }
-          var val;
-          if (desc.get) {
-            val = desc.get.call(this);
-            defineProp(this, prop, {
-              value: val,
-              writable: desc.writable,
-              configurable: desc.configurable,
-              enumerable: desc.enumerable
-            });
-          } else {
-            val = desc.value;
-          }
-          return val;
-        },
-        configurable: true
-      });
-    }
-    function mixinProps(dest, source) {
-      var props = getOwnPropNames(source);
-      for (var i = 0; i < props.length; i++) {
-        var key = props[i];
-        var desc = getOwnPropDesc(source, key);
-        safeReplaceProp(dest, key, desc);
-      }
-    }
-    function safeReplaceProp(obj, prop, desc) {
-      if (prop in obj) {
-        defineProp(obj, '_' + prop, {
-          value: obj[prop],
-          configurable: true
-        });
-      }
-      defineProp(obj, prop, desc);
-    }
-    function tmplf(format) {
-      if (arguments.length === 1)
-        return tmplf.bind(null, format);
-      var params = [
-          '_'
-        ];
-      var args = [
-          mapf
-        ];
-      for (var i = 1; i < arguments.length; i++) {
-        params[i] = '$' + i;
-        args[i] = arguments[i];
-      }
-      return Function(params.join(','), 'return "' + format.replace(/\$(\$|[1-9]\d*|\(((?:(['"]).*?\3|.)*?);\))|"/g, function sub(match, p1, p2) {
-        if (p1) {
-          if (p1 === '$')
-            return p1;
-          if (p2)
-            return '"+(' + p2 + ')+"';
-          return '"+' + match + '+"';
-        }
-        return '\\"';
-      }) + '"').apply(null, args);
-    }
-    function mapf(array, format, separator) {
-      if (+array == array)
-        array = Array(array);
-      else if (typeof array === 'string')
-        array = array.split(',');
-      if (format)
-        array = array.map(tmplf(format));
-      if (separator !== undefined)
-        return array.join(separator);
-      return array;
-    }
-    function evalf(format) {
-      return (1, eval)('1,' + tmplf.apply(null, arguments));
-    }
-    function parseSvgDataStr(sink, d) {
-      var chunks = (d + '').match(/[a-z][^a-z]*/gi);
-      var x0 = 0;
-      var y0 = 0;
-      var cpx = 0;
-      var cpy = 0;
-      var x = 0;
-      var y = 0;
-      for (var i = 0; i < chunks.length; i++) {
-        var seg = chunks[i];
-        var cmd = seg[0].toUpperCase();
-        if (cmd === 'Z') {
-          sink.closePath();
-          continue;
-        }
-        var abs = cmd === seg[0];
-        var args = seg.slice(1).trim().replace(/(\d)-/g, '$1 -').split(/,|\s/).map(parseFloat);
-        var narg = args.length;
-        var j = 0;
-        while (j < narg) {
-          x0 = x;
-          y0 = y;
-          if (abs)
-            x = y = 0;
-          switch (cmd) {
-          case 'A':
-            var rx = args[j++];
-            var ry = args[j++];
-            var rotation = args[j++] * PI / 180;
-            var large = args[j++];
-            var sweep = args[j++];
-            x += args[j++];
-            y += args[j++];
-            var u = Math.cos(rotation);
-            var v = Math.sin(rotation);
-            var h1x = (x0 - x) / 2;
-            var h1y = (y0 - y) / 2;
-            var x1 = u * h1x + v * h1y;
-            var y1 = -v * h1x + u * h1y;
-            var prx = rx * rx;
-            var pry = ry * ry;
-            var plx = x1 * x1;
-            var ply = y1 * y1;
-            var pl = plx / prx + ply / pry;
-            if (pl > 1) {
-              rx *= Math.sqrt(pl);
-              ry *= Math.sqrt(pl);
-              prx = rx * rx;
-              pry = ry * ry;
-            }
-            var sq = (prx * pry - prx * ply - pry * plx) / (prx * ply + pry * plx);
-            var coef = (large === sweep ? -1 : 1) * (sq < 0 ? 0 : Math.sqrt(sq));
-            var ox = coef * rx * y1 / ry;
-            var oy = coef * -ry * x1 / rx;
-            var h2x = (x0 + x) / 2;
-            var h2y = (y0 + y) / 2;
-            var cx = u * ox - v * oy + h2x;
-            var cy = v * ox + u * oy + h2y;
-            var ux = (x1 - ox) / rx;
-            var uy = (y1 - oy) / ry;
-            var vx = (-x1 - ox) / rx;
-            var vy = (-y1 - oy) / ry;
-            var n0 = Math.sqrt(ux * ux + uy * uy);
-            var a0 = (uy < 0 ? -1 : 1) * Math.acos(ux / n0);
-            var n1 = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
-            var p = ux * vx + uy * vy;
-            var aext = (ux * vy - uy * vx < 0 ? -1 : 1) * Math.acos(p / n1);
-            if (sweep) {
-              if (aext < 0)
-                aext += PI_DOUBLE;
-            } else if (aext > 0) {
-              aext += PI_DOUBLE;
-            }
-            var a1 = a0 + aext;
-            sink.ellipse(cx, cy, rx, ry, rotation, a0, a1, !sweep);
-            break;
-          case 'C':
-            var x1 = x + args[j++];
-            var y1 = y + args[j++];
-            cpx = x + args[j++];
-            cpy = y + args[j++];
-            x += args[j++];
-            y += args[j++];
-            sink.bezierCurveTo(x1, y1, cpx, cpy, x, y);
-            break;
-          case 'H':
-            x += args[j++];
-            sink.lineTo(x, y);
-            break;
-          case 'L':
-            x += args[j++];
-            y += args[j++];
-            sink.lineTo(x, y);
-            break;
-          case 'M':
-            x += args[j++];
-            y += args[j++];
-            sink.moveTo(x, y);
-            break;
-          case 'Q':
-            cpx = x + args[j++];
-            cpy = y + args[j++];
-            x += args[j++];
-            y += args[j++];
-            sink.quadraticCurveTo(cpx, cpy, x, y);
-            break;
-          case 'S':
-            var x1 = x0 * 2 - cpx;
-            var y1 = y0 * 2 - cpy;
-            cpx = x + args[j++];
-            cpy = y + args[j++];
-            x += args[j++];
-            y += args[j++];
-            sink.bezierCurveTo(x1, y1, cpx, cpy, x, y);
-            break;
-          case 'T':
-            cpx = x0 * 2 - cpx;
-            cpy = y0 * 2 - cpy;
-            x += args[j++];
-            y += args[j++];
-            sink.quadraticCurveTo(cpx, cpy, x, y);
-            break;
-          case 'V':
-            y += args[j++];
-            sink.lineTo(x, y);
-            break;
-          default:
-            return;
-          }
-        }
-      }
-    }
-    function arcToCurveSegs(sink, cx, cy, r, a0, a1, ccw, m11, m12, m21, m22, tx, ty) {
-      var x = cx + Math.cos(a0) * r;
-      var y = cy + Math.sin(a0) * r;
-      var x1 = x * m11 + y * m12 + tx;
-      var y1 = x * m21 + y * m22 + ty;
-      if (ccw) {
-        if (a0 < a1)
-          a0 += Math.ceil((a1 - a0) / PI_DOUBLE + 0.1) * PI_DOUBLE;
-        if (a0 - a1 > PI_DOUBLE)
-          a1 = a0 - PI_DOUBLE;
-      } else {
-        if (a1 < a0)
-          a1 += Math.ceil((a0 - a1) / PI_DOUBLE + 0.1) * PI_DOUBLE;
-        if (a1 - a0 > PI_DOUBLE)
-          a1 = a0 + PI_DOUBLE;
-      }
-      var sweep = Math.abs(a1 - a0);
-      var dir = ccw ? -1 : 1;
-      while (sweep > 0) {
-        a1 = a0 + (sweep > PI_HALF ? PI_HALF : sweep) * dir;
-        var kappa = 4 / 3 * Math.tan((a1 - a0) / 4) * r;
-        var cos0 = Math.cos(a0);
-        var sin0 = Math.sin(a0);
-        var cp1x = cx + cos0 * r + -sin0 * kappa;
-        var cp1y = cy + sin0 * r + cos0 * kappa;
-        var cos1 = Math.cos(a1);
-        var sin1 = Math.sin(a1);
-        x = cx + cos1 * r;
-        y = cy + sin1 * r;
-        var cp2x = x + sin1 * kappa;
-        var cp2y = y + -cos1 * kappa;
-        var x2 = x * m11 + y * m12 + tx;
-        var y2 = x * m21 + y * m22 + ty;
-        sink._curveSeg(x1, y1, cp1x * m11 + cp1y * m12 + tx, cp1x * m21 + cp1y * m22 + ty, cp2x * m11 + cp2y * m12 + tx, cp2x * m21 + cp2y * m22 + ty, x2, y2);
-        x1 = x2;
-        y1 = y2;
-        a0 = a1;
-        sweep -= PI_HALF;
-      }
-    }
-    function getDerivativeRoots(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y) {
-      var res = [];
-      var dn1x = -x0 + 3 * cp1x - 3 * cp2x + x;
-      if (dn1x) {
-        var txl = -x0 + 2 * cp1x - cp2x;
-        var txr = -Math.sqrt(-x0 * (cp2x - x) + cp1x * cp1x - cp1x * (cp2x + x) + cp2x * cp2x);
-        var r1 = (txl + txr) / dn1x;
-        if (r1 > 0 && r1 < 1)
-          res.push(r1);
-        var r2 = (txl - txr) / dn1x;
-        if (r2 > 0 && r2 < 1)
-          res.push(r2);
-      }
-      var dn2x = x0 - 3 * cp1x + 3 * cp2x - x;
-      if (dn2x) {
-        var r3 = (x0 - 2 * cp1x + cp2x) / dn2x;
-        if (r3 > 0 && r3 < 1)
-          res.push(r3);
-      }
-      var dn1y = -y0 + 3 * cp1x - 3 * cp2x + y;
-      if (dn1y) {
-        var tyl = -y0 + 2 * cp1y - cp2y;
-        var tyr = -Math.sqrt(-y0 * (cp2y - y) + cp1y * cp1y - cp1y * (cp2y + y) + cp2y * cp2y);
-        var r4 = (tyl + tyr) / dn1y;
-        if (r4 > 0 && r4 < 1)
-          res.push(r4);
-        var r5 = (tyl - tyr) / dn1y;
-        if (r5 > 0 && r5 < 1)
-          res.push(r5);
-      }
-      var dn2y = y0 - 3 * cp1y + 3 * cp2y - y;
-      if (dn2y) {
-        var r6 = (y0 - 2 * cp1y + cp2y) / dn2y;
-        if (r6 > 0 && r6 < 1)
-          res.push(r6);
-      }
-      return res;
-    }
-    function getRoots(a, b, c, d) {
-      var res = [];
-      var bb = 6 * a - 12 * b + 6 * c;
-      var aa = -3 * a + 9 * b - 9 * c + 3 * d;
-      var cc = 3 * b - 3 * a;
-      if (aa == 0) {
-        if (bb == 0) {
-          return res;
-        }
-        var t = -cc / bb;
-        if (0 < t && t < 1) {
-          res.push(t);
-        }
-        return res;
-      }
-      var b2ac = Math.pow(bb, 2) - 4 * cc * aa;
-      if (b2ac < 0) {
-        return res;
-      }
-      var t1 = (-bb + Math.sqrt(b2ac)) / (2 * aa);
-      if (0 < t1 && t1 < 1) {
-        res.push(t1);
-      }
-      var t2 = (-bb - Math.sqrt(b2ac)) / (2 * aa);
-      if (0 < t2 && t2 < 1) {
-        res.push(t2);
-      }
-      ;
-      return res;
-    }
-    function computeCubicBaseValue(t, a, b, c, d) {
-      var mt = 1 - t;
-      return mt * mt * mt * a + 3 * mt * mt * t * b + 3 * mt * t * t * c + t * t * t * d;
-    }
-    function findCubicRoot(a, b, c, d, offset) {
-      var t = 1;
-      do {
-        var r = t;
-        var depth = 1;
-        do {
-          var tt = r;
-          var f = computeCubicBaseValue(tt, a, b, c, d) - offset;
-          var t2 = tt * tt;
-          var t6 = 6 * tt;
-          var t12 = 2 * t6;
-          var t92 = t2 * 9;
-          var mt2 = (tt - 1) * (tt - 1);
-          var df = 3 * d * t2 + c * (t6 - t92) + b * (t92 - t12 + 3) - 3 * a * mt2;
-          r = tt - f / df;
-          if (!df)
-            return -1;
-          if (depth > 12) {
-            if (Math.abs(tt - r) < 0.001)
-              break;
-            return -1;
-          }
-        } while (Math.abs(tt - r) > 0.0001);
-        if (r < 0 || r > 1)
-          continue;
-        var y = computeCubicBaseValue(r, a, b, c, d);
-        var dy = offset - y;
-        if (dy * dy > 1)
-          continue;
-        return r;
-      } while (t--);
-      return -1;
-    }
-    function scaleCurve(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y, distance) {
-      var pas = getAngularDir(cp1x - x0, cp1y - y0) + PI_HALF;
-      var pdxs = Math.cos(pas);
-      var pdys = Math.sin(pas);
-      var pae = getAngularDir(x - cp2x, y - cp2y) + PI_HALF;
-      var pdxe = Math.cos(pae);
-      var pdye = Math.sin(pae);
-      if (pdxs == pdxe && pdys == pdye)
-        return null;
-      var sx, sy;
-      if (pdxs == pdxe || pdys == pdye) {
-        sx = (x0 + x) / 2;
-        sy = (y0 + y) / 2;
-      } else {
-        var s = getLineIntersect(x0, y0, x0 + pdxs, y0 + pdys, x + pdxe, y + pdye, x, y);
-        sx = s[0];
-        sy = s[1];
-      }
-      var a1 = getAngularDir(x0 - sx, y0 - sy);
-      var a2 = getAngularDir(cp1x - sx, cp1y - sy);
-      var a3 = getAngularDir(cp2x - sx, cp2y - sy);
-      var a4 = getAngularDir(x - sx, y - sy);
-      if (a1 === a2 || a2 > a3)
-        distance = -distance;
-      var nax = x0 - distance * Math.cos(a1);
-      var nay = y0 - distance * Math.sin(a1);
-      var ndx = x - distance * Math.cos(a4);
-      var ndy = y - distance * Math.sin(a4);
-      var nbx, nby, ncx, ncy;
-      var nb = getLineIntersect(nax, nay, nax + (cp1x - x0), nay + (cp1y - y0), sx, sy, cp1x, cp1y);
-      if (nb) {
-        nbx = nb[0];
-        nby = nb[1];
-      } else {
-        nbx = nax;
-        nby = nay;
-      }
-      var nc = getLineIntersect(ndx, ndy, ndx + (cp2x - x), ndy + (cp2y - y), sx, sy, cp2x, cp2y);
-      if (nc) {
-        ncx = nc[0];
-        ncy = nc[1];
-      } else {
-        ncx = ndx;
-        ncy = ndy;
-      }
-      return [
-        nax,
-        nay,
-        nbx,
-        nby,
-        ncx,
-        ncy,
-        ndx,
-        ndy
-      ];
-    }
-    function getAngularDir(x, y) {
-      var d1 = 0;
-      var d2 = PI_HALF;
-      var d3 = PI;
-      var d4 = 3 * PI_HALF;
-      var angle = 0;
-      var ax = Math.abs(x);
-      var ay = Math.abs(y);
-      if (!x)
-        angle = y >= 0 ? d2 : d4;
-      else if (!y)
-        angle = x >= 0 ? d1 : d3;
-      else if (x > 0 && y > 0)
-        angle = d1 + Math.atan(ay / ax);
-      else if (x < 0 && y < 0)
-        angle = d3 + Math.atan(ay / ax);
-      else if (x < 0 && y > 0)
-        angle = d2 + Math.atan(ax / ay);
-      else if (x > 0 && y < 0)
-        angle = d4 + Math.atan(ax / ay);
-      return (angle + PI_DOUBLE) % PI_DOUBLE;
-    }
-    function getLineIntersect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
-      var nx = (ax1 * ay2 - ay1 * ax2) * (bx1 - bx2) - (ax1 - ax2) * (bx1 * by2 - by1 * bx2);
-      var ny = (ax1 * ay2 - ay1 * ax2) * (by1 - by2) - (ay1 - ay2) * (bx1 * by2 - by1 * bx2);
-      var dn = (ax1 - ax2) * (by1 - by2) - (ay1 - ay2) * (bx1 - bx2);
-      if (!dn)
-        return null;
-      var px = nx / dn;
-      var py = ny / dn;
-      return [
-        px,
-        py
-      ];
-    }
-    function buildOutline(sink, data, styles) {
-      sink.moveTo(data[1], data[2]);
-      for (var i = 0; i < data.length;) {
-        var npoint = data[i];
-        var x0 = data[i + 1];
-        var y0 = data[i + 2];
-        var a1x, a1y, a2x, a2y;
-        if (npoint === 2) {
-          var x = data[i + 3];
-          var y = data[i + 4];
-          sink.lineTo(x, y);
-          a1x = x0;
-          a1y = y0;
-          a2x = x;
-          a2y = y;
-          i += 5;
-        } else {
-          var cp1x = data[i + 3];
-          var cp1y = data[i + 4];
-          var cp2x = data[i + 5];
-          var cp2y = data[i + 6];
-          var x = data[i + 7];
-          var y = data[i + 8];
-          sink.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
-          a1x = cp2x;
-          a1y = cp2y;
-          a2x = x;
-          a2y = y;
-          i += 9;
-        }
-        var lineJoin = styles.lineJoin || 'bevel';
-        var p = i % data.length;
-        var b1x = data[p + 1];
-        var b1y = data[p + 2];
-        if (~(~(a2x + 0.5)) === ~(~(b1x + 0.5)) && ~(~(a2y + 0.5)) === ~(~(b1y + 0.5)))
-          continue;
-        var b2x = data[p + 3];
-        var b2y = data[p + 4];
-        var a1 = a2y - a1y;
-        var b1 = -(a2x - a1x);
-        var c1 = a1x * a2y - a2x * a1y;
-        var a2 = b2y - b1y;
-        var b2 = -(b2x - b1x);
-        var c2 = b1x * b2y - b2x * b1y;
-        var d = a1 * b2 - b1 * a2;
-        if (!d) {
-          sink.lineTo(b1x, b1y);
-        } else {
-          var x = (c1 * b2 - b1 * c2) / d;
-          var y = (a1 * c2 - c1 * a2) / d;
-          var ona = !(x < a1x && x < a2x || x > a1x && x > a2x || y < a1y && y < a2y || y > a1y && y > a2y);
-          var onb = !(x < b1x && x < b2x || x > b1x && x > b2x || y < b1y && y < b2y || y > b1y && y > b2y);
-          if (!ona && !onb) {
-            switch (lineJoin) {
-            case 'bevel':
-              sink.lineTo(b1x, b1y);
-              break;
-            case 'round':
-              sink.quadraticCurveTo(x, y, b1x, b1y);
-              break;
-            case 'miter':
-            default:
-              var a = -a2y - b1y;
-              var b = a2x - b1x;
-              var d = Math.sqrt(a * a + b * b);
-              var miterLen = (a * (x - b1x) + b * (y - b1y)) / d;
-              var maxLen = styles.miterLimit * styles.lineWidth / 2;
-              if (miterLen > maxLen) {
-                var p2 = maxLen / miterLen;
-                var p1 = 1 - p2;
-                sink.lineTo(a2x * p1 + x * p2, a2y * p1 + y * p2);
-                sink.lineTo(b1x * p1 + x * p2, b1y * p1 + y * p2);
-              } else {
-                sink.lineTo(x, y);
-              }
-              sink.lineTo(b1x, b1y);
-              break;
-            }
-          } else {
-            if (ona)
-              sink.lineTo(x, y);
-            sink.lineTo(b1x, b1y);
-          }
-        }
-      }
-      sink.closePath();
-    }
-    function addLineCap(data, x, y, styles) {
-      var p = data.length;
-      var x1 = data[p - 4];
-      var y1 = data[p - 3];
-      var x2 = data[p - 2];
-      var y2 = data[p - 1];
-      switch (styles.lineCap) {
-      case 'round':
-        var cx = (x2 + x) / 2;
-        var cy = (y2 + y) / 2;
-        var a0 = Math.atan2(y2 - cy, x2 - cx);
-        var a1 = Math.atan2(y - cy, x - cx);
-        var sweep = Math.abs(a1 - a0);
-        var r = styles.lineWidth / 2;
-        while (sweep > 0) {
-          a1 = a0 + (sweep > PI_HALF ? PI_HALF : sweep);
-          var kappa = 4 / 3 * Math.tan((a1 - a0) / 4) * r;
-          var cos0 = Math.cos(a0);
-          var sin0 = Math.sin(a0);
-          var cp1x = cx + cos0 * r + -sin0 * kappa;
-          var cp1y = cy + sin0 * r + cos0 * kappa;
-          var cos1 = Math.cos(a1);
-          var sin1 = Math.sin(a1);
-          var x = cx + cos1 * r;
-          var y = cy + sin1 * r;
-          var cp2x = x + sin1 * kappa;
-          var cp2y = y + -cos1 * kappa;
-          data[p] = 4;
-          data[p + 1] = x2;
-          data[p + 2] = y2;
-          data[p + 3] = cp1x;
-          data[p + 4] = cp1y;
-          data[p + 5] = cp2x;
-          data[p + 6] = cp2y;
-          data[p + 7] = x;
-          data[p + 8] = y;
-          p += 9;
-          x2 = x;
-          y2 = y;
-          a0 = a1;
-          sweep -= PI_HALF;
-        }
-        break;
-      case 'square':
-        var distance = styles.lineWidth / 2;
-        var dx = x2 - x1;
-        var dy = y2 - y1;
-        var d = Math.sqrt(dx * dx + dy * dy);
-        var x3 = x2 + dx * distance / d;
-        var y3 = y2 + dy * distance / d;
-        var x4 = x + dx * distance / d;
-        var y4 = y + dy * distance / d;
-        data[p] = 2;
-        data[p + 1] = x2;
-        data[p + 2] = y2;
-        data[p + 3] = x3;
-        data[p + 4] = y3;
-        data[p + 5] = 2;
-        data[p + 6] = x3;
-        data[p + 7] = y3;
-        data[p + 8] = x4;
-        data[p + 9] = y4;
-        x2 = x4;
-        y2 = y4;
-        p += 10;
-      case 'none':
-      default:
-        data[p] = 2;
-        data[p + 1] = x2;
-        data[p + 2] = y2;
-        data[p + 3] = x;
-        data[p + 4] = y;
-        break;
-      }
-    }
-    var borrowSVGMatrix = !('currentTransform' in native2dCtxProto);
-    if (!borrowSVGMatrix) {
-      try {
-        idTransform = new SVGMatrix();
-        transformClass = idTransform.constructor;
-      } catch (e) {
-        borrowSVGMatrix = true;
-      }
-    }
-    if (borrowSVGMatrix) {
-      var svgElement = doc.createElementNS(SVG_NAMESPACE, 'svg');
-      transformClass = function SVGMatrix() {
-        return svgElement.createSVGMatrix();
-      };
-      transformClass.prototype = SVGMatrix.prototype;
-      idTransform = new transformClass();
-    }
-    if (shimCurrentTransform) {
-      defineLazyProp(kanvas2dCtxProto, '_ct', {
-        get: function () {
-          return new transformClass();
-        }
-      });
-      defineLazyProp(kanvas2dCtxProto, '_ctm', {
-        get: function () {
-          return new Float32Array([
-            1,
-            0,
-            0,
-            1,
-            0,
-            0
-          ]);
-        }
-      });
-      defineLazyProp(kanvas2dCtxProto, '_stack', {
-        get: Array
-      });
-      defineProp(kanvas2dCtxProto, 'currentTransform', {
-        get: function () {
-          return this._ct;
-        },
-        set: function (val) {
-          if (!(val instanceof transformClass))
-            throw new TypeError();
-          if (this._ct === val)
-            return;
-          this.setTransform(val.a, val.b, val.c, val.d, val.e, val.f);
-        }
-      });
-      kanvas2dCtxProto.save = function () {
-        this._save();
-        var ctm = this._ctm;
-        this._stack.push([
-          ctm[0],
-          ctm[1],
-          ctm[2],
-          ctm[3],
-          ctm[4],
-          ctm[5]
-        ]);
-      };
-      kanvas2dCtxProto.restore = function () {
-        this._restore();
-        var stack = this._stack;
-        if (stack.length) {
-          var m = stack.pop();
-          this.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
-        }
-      };
-      kanvas2dCtxProto.scale = function (x, y) {
-        var ctm = this._ctm;
-        this.setTransform(ctm[0] * x, ctm[1] * x, ctm[2] * y, ctm[3] * y, ctm[4], ctm[5]);
-      };
-      kanvas2dCtxProto.rotate = function (angle) {
-        var ctm = this._ctm;
-        var u = Math.cos(angle);
-        var v = Math.sin(angle);
-        this.setTransform(ctm[0] * u + ctm[2] * v, ctm[1] * u + ctm[3] * v, ctm[0] * -v + ctm[2] * u, ctm[1] * -v + ctm[3] * u, ctm[4], ctm[5]);
-      };
-      kanvas2dCtxProto.translate = function (x, y) {
-        var ctm = this._ctm;
-        this.setTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[0] * x + ctm[2] * y + ctm[4], ctm[1] * x + ctm[3] * y + ctm[5]);
-      };
-      kanvas2dCtxProto.transform = function (a, b, c, d, e, f) {
-        var ctm = this._ctm;
-        this.setTransform(ctm[0] * a + ctm[2] * b, ctm[1] * a + ctm[3] * b, ctm[0] * c + ctm[2] * d, ctm[1] * c + ctm[3] * d, ctm[0] * e + ctm[2] * f + ctm[4], ctm[1] * e + ctm[3] * f + ctm[5]);
-      };
-      kanvas2dCtxProto.setTransform = function (a, b, c, d, e, f) {
-        this._setTransform(a, b, c, d, e, f);
-        var ct = this._ct;
-        var ctm = this._ctm;
-        ct.a = ctm[0] = a;
-        ct.b = ctm[1] = b;
-        ct.c = ctm[2] = c;
-        ct.d = ctm[3] = d;
-        ct.e = ctm[4] = e;
-        ct.f = ctm[5] = f;
-      };
-      shimResetTransform = true;
-    }
-    if (shimResetTransform) {
-      kanvas2dCtxProto.resetTransform = function () {
-        this.setTransform(1, 0, 0, 1, 0, 0);
-      };
-    }
-    if (shimEllipticalArcTo) {
-      kanvas2dCtxProto.arcTo = function (x1, y1, x2, y2, rx, ry, rotation) {
-        if (rx < 0 || ry < 0)
-          throw new RangeError();
-        var x0 = x1;
-        var y0 = y1;
-        var m11 = 1;
-        var m12 = 0;
-        var m21 = 0;
-        var m22 = 1;
-        var tx = 0;
-        var ty = 0;
-        var ops = this._ops;
-        var p = ops.length;
-        while (p) {
-          switch (ops[p - 1]) {
-          case PATH_OP_CLOSE:
-            p = ops[p - 2];
-            if (p) {
-              x0 = ops[p];
-              y0 = ops[p + 1];
-            }
-            break;
-          case PATH_OP_RECT:
-            x0 = ops[p - 5];
-            y0 = ops[p - 4];
-            break;
-          case PATH_OP_ARC:
-            var r = ops[p - 5];
-            var a = ops[p - 3];
-            x0 = ops[p - 7] + Math.cos(a) * r;
-            y0 = ops[p - 6] + Math.sin(a) * r;
-            break;
-          case PATH_OP_ELLIPSE:
-            var sx = ops[p - 7];
-            var sy = ops[p - 6];
-            var rot = ops[p - 5];
-            var a = ops[p - 3];
-            var u = Math.cos(rot);
-            var v = Math.sin(rot);
-            var x = Math.cos(a);
-            var y = Math.sin(a);
-            x0 = x * u * sx + y * v * sy + ops[p - 9];
-            y0 = x * -v * sx + y * u * sy + ops[p - 8];
-            break;
-          case PATH_OP_TRANSFORM:
-            var a = ops[p - 7];
-            var b = ops[p - 6];
-            var c = ops[p - 5];
-            var d = ops[p - 4];
-            var e = ops[p - 3];
-            var f = ops[p - 2];
-            p -= 8;
-            continue;
-          default:
-            x0 = ops[p - 3];
-            y0 = ops[p - 2];
-          }
-          break;
-        }
-        if (x1 === x0 && y1 === y0) {
-          this.moveTo(x1, y1);
-          return;
-        }
-        var dir = (x2 - x1) * (y0 - y1) + (y2 - y1) * (x1 - x0);
-        if (x1 === x0 && y1 === y0 || x1 === x2 && y1 === y2 || !rx || !ry || !dir) {
-          this.lineTo(x1, y1);
-          return;
-        }
-        if (rx !== ry) {
-          var scale = ry / rx;
-          m22 = Math.cos(-rotation);
-          m12 = Math.sin(-rotation);
-          m11 = m22 / scale;
-          m21 = -m12 / scale;
-          var ox1 = x0;
-          x0 = (ox1 * m22 - y0 * m12) * scale;
-          y0 = ox1 * m12 + y0 * m22;
-          var ox2 = x1;
-          x1 = (ox2 * m22 - y1 * m12) * scale;
-          y1 = ox2 * m12 + y1 * m22;
-          var ox3 = x2;
-          x2 = (ox3 * m22 - y2 * m12) * scale;
-          y2 = ox3 * m12 + y2 * m22;
-        }
-        var pa = (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1);
-        var pb = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
-        var pc = (x0 - x2) * (x0 - x2) + (y0 - y2) * (y0 - y2);
-        var cosx = (pa + pb - pc) / (2 * Math.sqrt(pa * pb));
-        var sinx = Math.sqrt(1 - cosx * cosx);
-        var d = ry / ((1 - cosx) / sinx);
-        var sqa = Math.sqrt(pa);
-        var anx = (x1 - x0) / sqa;
-        var any = (y1 - y0) / sqa;
-        var sqb = Math.sqrt(pb);
-        var bnx = (x1 - x2) / sqb;
-        var bny = (y1 - y2) / sqb;
-        var x3 = x1 - anx * d;
-        var y3 = y1 - any * d;
-        var x4 = x1 - bnx * d;
-        var y4 = y1 - bny * d;
-        var ccw = dir < 0;
-        var cx = x3 + any * ry * (ccw ? 1 : -1);
-        var cy = y3 - anx * ry * (ccw ? 1 : -1);
-        var a0 = Math.atan2(y3 - cy, x3 - cx);
-        var a1 = Math.atan2(y4 - cy, x4 - cx);
-        this.save();
-        this.transform(m11, m12, m21, m22, 0, 0);
-        this.lineTo(x3, y3);
-        this.arc(cx, cy, ry, a0, a1, ccw);
-        this.restore();
-      };
-    }
-    if (shimEllipse) {
-      kanvas2dCtxProto.ellipse = function (cx, cy, rx, ry, rotation, a0, a1, ccw) {
-        if (rx < 0 || ry < 0)
-          throw new RangeError();
-        if (rx === ry) {
-          this.arc(cx, cy, rx, a0, a1, ccw);
-          return;
-        }
-        var u = Math.cos(rotation);
-        var v = Math.sin(rotation);
-        this.save();
-        this.transform(u * rx, v * rx, -v * ry, u * ry, cx, cy);
-        this.arc(0, 0, 1, a0, a1, ccw);
-        this.restore();
-      };
-    }
-    if (shimPath) {
-      pathClass = function Path(d) {
-        if (!(this instanceof Path))
-          return new Path(d);
-        var obj = this;
-        if (nativePathClass) {
-          obj = new nativePathClass();
-          mixinProps(obj, kanvasPathProto);
-        }
-        if (arguments.length) {
-          if (d instanceof Path)
-            obj.addPath(d);
-          else {
-            Timer.start('parseSvgDataStr');
-            parseSvgDataStr(obj, d);
-            Timer.stop();
-          }
-        }
-        return obj;
-      };
-      pathClass.prototype = nativePathProto || kanvasPathProto;
-      defineLazyProp(kanvasPathProto, '_state', {
-        get: function () {
-          return new Float32Array([
-            65535,
-            65535,
-            -65535,
-            -65535,
-            0,
-            0
-          ]);
-        }
-      });
-      defineLazyProp(kanvasPathProto, '_segs', {
-        get: Array
-      });
-      kanvasPathProto._lineSeg = function (x0, y0, x, y, close) {
-        var state = this._state;
-        if (x0 < state[0])
-          state[0] = x0;
-        if (y0 < state[1])
-          state[1] = y0;
-        if (x0 > state[2])
-          state[2] = x0;
-        if (y0 > state[3])
-          state[3] = y0;
-        if (x < state[0])
-          state[0] = x;
-        if (y < state[1])
-          state[1] = y;
-        if (x > state[2])
-          state[2] = x;
-        if (y > state[3])
-          state[3] = y;
-        var segs = this._segs;
-        var p = segs.length;
-        segs[p] = 2;
-        segs[p + 1] = x0;
-        segs[p + 2] = y0;
-        segs[p + 3] = x;
-        segs[p + 4] = y;
-        if (close)
-          segs[p + 5] = 0;
-        state[4] = x;
-        state[5] = y;
-      };
-      kanvasPathProto._curveSeg = function (x0, y0, cp1x, cp1y, cp2x, cp2y, x, y) {
-        var state = this._state;
-        var segs = this._segs;
-        var p = segs.length;
-        if (x0 < state[0])
-          state[0] = x0;
-        if (y0 < state[1])
-          state[1] = y0;
-        if (x0 > state[2])
-          state[2] = x0;
-        if (y0 > state[3])
-          state[3] = y0;
-        var roots = getDerivativeRoots(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y);
-        if (!roots.length) {
-          roots = getRoots(x0, cp1x, cp2x, x);
-          for (var i = 0; i < roots.length; i++) {
-            var t = roots[i];
-            var x = computeCubicBaseValue(t, x0, cp1x, cp2x, x);
-            if (x < state[0])
-              state[0] = x;
-            if (x > state[2])
-              state[2] = x;
-          }
-          roots = getRoots(y0, cp1y, cp2y, y);
-          for (var i = 0; i < roots.length; i++) {
-            var t = roots[i];
-            var y = computeCubicBaseValue(t, y0, cp1y, cp2y, y);
-            if (y < state[1])
-              state[1] = y;
-            if (y > state[3])
-              state[3] = y;
-          }
-          if (x < state[0])
-            state[0] = x;
-          if (y < state[1])
-            state[1] = y;
-          if (x > state[2])
-            state[2] = x;
-          if (y > state[3])
-            state[3] = y;
-          segs[p] = 4;
-          segs[p + 1] = x0;
-          segs[p + 2] = y0;
-          segs[p + 3] = cp1x;
-          segs[p + 4] = cp1y;
-          segs[p + 5] = cp2x;
-          segs[p + 6] = cp2y;
-          segs[p + 7] = x;
-          segs[p + 8] = y;
-          state[4] = x;
-          state[5] = y;
-          return;
-        }
-        for (var i = 0; i <= roots.length; i++) {
-          var t = roots[i] || 1;
-          if (t > 0 && t <= 1) {
-            segs[p] = 4;
-            segs[p + 1] = x0;
-            segs[p + 2] = y0;
-            var mt = 1 - t;
-            var mx1 = mt * x0 + t * cp1x;
-            var my1 = mt * y0 + t * cp1y;
-            var mx2 = mt * cp1x + t * cp2x;
-            var my2 = mt * cp1y + t * cp2y;
-            cp2x = mt * cp2x + t * x;
-            cp2y = mt * cp2y + t * y;
-            var pcx = mt * mx1 + t * mx2;
-            var pcy = mt * my1 + t * my2;
-            cp1x = mt * mx2 + t * cp2x;
-            cp1y = mt * my2 + t * cp2y;
-            x0 = mt * pcx + t * cp1x;
-            y0 = mt * pcy + t * cp1y;
-            if (x0 < state[0])
-              state[0] = x0;
-            if (y0 < state[1])
-              state[1] = y0;
-            if (x0 > state[2])
-              state[2] = x0;
-            if (y0 > state[3])
-              state[3] = y0;
-            segs[p + 3] = mx1;
-            segs[p + 4] = my1;
-            segs[p + 5] = pcx;
-            segs[p + 6] = pcy;
-            segs[p + 7] = x0;
-            segs[p + 8] = y0;
-            p += 9;
-          }
-        }
-        state[4] = x;
-        state[5] = y;
-      };
-      kanvasPathProto.closePath = function () {
-        if (this._sp) {
-          this._lineSeg(this._state[4], this._state[5], this._ops[this._sp], this._ops[this._sp + 1], true);
-        }
-      };
-      kanvasPathProto.moveTo = function (x, y) {
-        this._state[4] = x;
-        this._state[5] = y;
-      };
-      kanvasPathProto.lineTo = function (x, y) {
-        if (this._sp) {
-          this._lineSeg(this._state[4], this._state[5], x, y);
-        } else {
-          this._state[4] = x;
-          this._state[5] = y;
-        }
-      };
-      kanvasPathProto.quadraticCurveTo = function (cpx, cpy, x, y) {
-        var x0, y0;
-        if (this._sp) {
-          x0 = this._state[4];
-          y0 = this._state[5];
-        } else {
-          x0 = cpx;
-          y0 = cpy;
-        }
-        var cp1x = x0 + 2 / 3 * (cpx - x0);
-        var cp1y = y0 + 2 / 3 * (cpy - y0);
-        var cp2x = cp1x + (x - x0) / 3;
-        var cp2y = cp1y + (y - y0) / 3;
-        this._curveSeg(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y);
-      };
-      kanvasPathProto.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) {
-        var x0, y0;
-        if (this._sp) {
-          x0 = this._state[4];
-          y0 = this._state[5];
-        } else {
-          x0 = cp1x;
-          y0 = cp1y;
-        }
-        this._curveSeg(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y);
-      };
-      kanvasPathProto.arcTo = function (x1, y1, x2, y2, rx, ry, rotation) {
-        if (arguments.length < 7) {
-          ry = rx;
-          rotation = 0;
-        }
-        if (rx < 0 || ry < 0)
-          throw new RangeError();
-        var x0, y0;
-        if (this._sp) {
-          x0 = this._state[4];
-          y0 = this._state[5];
-        } else {
-          x0 = x1;
-          y0 = y1;
-        }
-        if (x1 === x0 && y1 === y0)
-          return;
-        var dir = (x2 - x1) * (y0 - y1) + (y2 - y1) * (x1 - x0);
-        if (x1 === x0 && y1 === y0 || x1 === x2 && y1 === y2 || !rx || !ry || !dir) {
-          this.lineTo(x1, y1);
-          return;
-        }
-        if (rx !== ry) {
-          var scale = ry / rx;
-          var u = Math.cos(-rotation);
-          var v = Math.sin(-rotation);
-          var ox1 = x0;
-          x0 = (ox1 * u - y0 * v) * scale;
-          y0 = ox1 * v + y0 * u;
-          var ox2 = x1;
-          x1 = (ox2 * u - y1 * v) * scale;
-          y1 = ox2 * v + y1 * u;
-          var ox3 = x2;
-          x2 = (ox3 * u - y2 * v) * scale;
-          y2 = ox3 * v + y2 * u;
-        } else {
-          var scale = 1;
-          var u = 1;
-          var v = 0;
-        }
-        var pa = (x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1);
-        var pb = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
-        var pc = (x0 - x2) * (x0 - x2) + (y0 - y2) * (y0 - y2);
-        var cosx = (pa + pb - pc) / (2 * Math.sqrt(pa * pb));
-        var sinx = Math.sqrt(1 - cosx * cosx);
-        var d = ry / ((1 - cosx) / sinx);
-        var anx = (x1 - x0) / Math.sqrt(pa);
-        var any = (y1 - y0) / Math.sqrt(pa);
-        var bnx = (x1 - x2) / Math.sqrt(pb);
-        var bny = (y1 - y2) / Math.sqrt(pb);
-        var x3 = x1 - anx * d;
-        var y3 = y1 - any * d;
-        var x4 = x1 - bnx * d;
-        var y4 = y1 - bny * d;
-        var ccw = dir < 0;
-        var cx = x3 + any * ry * (ccw ? 1 : -1);
-        var cy = y3 - anx * ry * (ccw ? 1 : -1);
-        var a0 = Math.atan2(y3 - cy, x3 - cx);
-        var a1 = Math.atan2(y4 - cy, x4 - cx);
-        var m11 = u / scale;
-        var m21 = -v / scale;
-        this._lineSeg(x0 * m11 + y0 * v, x0 * m21 + y0 * u, x3 * m11 + y3 * v, x3 * m21 + y3 * u);
-        arcToCurveSegs(this, cx, cy, ry, a0, a1, ccw, m11, v, m21, u, 0, 0);
-      };
-      kanvasPathProto.rect = function (x, y, w, h) {
-        var tr = x + w;
-        var br = y + h;
-        this._lineSeg(x, y, tr, y);
-        this._lineSeg(tr, y, tr, br);
-        this._lineSeg(tr, br, x, br);
-        this._lineSeg(x, br, x, y, true);
-      };
-      kanvasPathProto.arc = function (cx, cy, r, a0, a1, ccw) {
-        arcToCurveSegs(this, cx, cy, r, a0, a1, ccw, 1, 0, 0, 1, 0, 0);
-        if (a1 - a0 === PI_DOUBLE)
-          this._segs.push(0);
-      };
-      kanvasPathProto.ellipse = function (x, y, rx, ry, rotation, a0, a1, ccw) {
-        var u = Math.cos(rotation);
-        var v = Math.sin(rotation);
-        var m11 = u * rx;
-        var m12 = v * ry;
-        var m21 = -v * rx;
-        var m22 = u * ry;
-        arcToCurveSegs(this, 0, 0, 1, a0, a1, ccw, m11, m12, m21, m22, x, y);
-      };
-      kanvasPathProto.isPointInPath = function (x, y, winding) {
-        var state = this._state;
-        if (x < state[0] || y < state[1] || x > state[2] || y > state[3])
-          return false;
-        var wn = 0;
-        var segs = this._segs;
-        for (var i = 0; i < segs.length; i++) {
-          var npoint = segs[i];
-          if (!npoint)
-            continue;
-          var x0 = segs[i + 1];
-          var y0 = segs[i + 2];
-          if (npoint === 2) {
-            var x1 = segs[i + 3];
-            var y1 = segs[i + 4];
-            if (y0 <= y) {
-              if (y1 > y) {
-                if ((x1 - x0) * (y - y0) - (x - x0) * (y1 - y0) > 0)
-                  ++wn;
-              }
-            } else {
-              if (y1 <= y) {
-                if ((x1 - x0) * (y - y0) - (x - x0) * (y1 - y0) < 0)
-                  --wn;
-              }
-            }
-            i += 4;
-          } else {
-            var cp1x = segs[i + 3];
-            var cp1y = segs[i + 4];
-            var cp2x = segs[i + 5];
-            var cp2y = segs[i + 6];
-            var x1 = segs[i + 7];
-            var y1 = segs[i + 8];
-            if (y0 <= y) {
-              if (y1 > y) {
-                var t = findCubicRoot(y0, cp1y, cp2y, y1, y);
-                if (t > -1 && computeCubicBaseValue(t, x0, cp1x, cp1x, x1) > x)
-                  ++wn;
-              }
-            } else {
-              if (y1 <= y) {
-                var t = findCubicRoot(y0, cp1y, cp2y, y1, y);
-                if (t > -1 && computeCubicBaseValue(t, x0, cp1x, cp1x, x1) > x)
-                  --wn;
-              }
-            }
-            x0 = x1;
-            y0 = y1;
-            i += 8;
-          }
-        }
-        return !(!wn);
-      };
-      if (shimBounds) {
-        kanvasPathProto.getBounds = function () {
-          var state = this._state;
-          return {
-            x: state[0],
-            y: state[1],
-            width: state[2] - state[0],
-            height: state[3] - state[1]
-          };
-        };
-      }
-      if (shimStrokePath) {
-        kanvasPathProto.strokePath = function (styles, transformation) {
-          if (!styles || !styles.lineWidth)
-            return;
-          if (arguments.length > 2) {
-            if (!(transform instanceof transformClass))
-              throw new TypeError();
-          }
-          var path = new pathClass();
-          var distance = styles.lineWidth / 2;
-          var segs = this._segs;
-          var outer = [];
-          var inner = [];
-          var p = 0;
-          var x, y;
-          for (var i = 0; i < segs.length;) {
-            var npoint = segs[i];
-            if (!npoint) {
-              if (outer.length) {
-                buildOutline(path, outer, styles);
-                inner.reverse();
-                buildOutline(path, inner, styles);
-                outer = [];
-                inner = [];
-                p = 0;
-              }
-              i++;
-              continue;
-            }
-            var x0 = segs[i + 1];
-            var y0 = segs[i + 2];
-            if (x !== x0 || y !== y0) {
-              if (outer.length) {
-                inner.reverse();
-                addLineCap(inner, outer[1], outer[2], styles);
-                addLineCap(outer, inner[1], inner[2], styles);
-                [].push.apply(outer, inner);
-                buildOutline(path, outer, styles);
-                outer = [];
-                inner = [];
-                p = 0;
-              }
-            }
-            if (npoint === 2) {
-              x = segs[i + 3];
-              y = segs[i + 4];
-              var dx = x - x0;
-              var dy = y - y0;
-              if (dx || dy) {
-                var k = distance / Math.sqrt(dx * dx + dy * dy);
-                dx *= k;
-                dy *= k;
-                outer[p] = 2;
-                outer[p + 1] = x0 + dy;
-                outer[p + 2] = y0 - dx;
-                outer[p + 3] = x + dy;
-                outer[p + 4] = y - dx;
-                inner[p] = y0 + dx;
-                inner[p + 1] = x0 - dy;
-                inner[p + 2] = y + dx;
-                inner[p + 3] = x - dy;
-                inner[p + 4] = 2;
-              }
-              p += 5;
-              i += 5;
-            } else {
-              var cp1x = segs[i + 3];
-              var cp1y = segs[i + 4];
-              var cp2x = segs[i + 5];
-              var cp2y = segs[i + 6];
-              x = segs[i + 7];
-              y = segs[i + 8];
-              var sc1 = scaleCurve(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y, distance);
-              var sc2 = scaleCurve(x0, y0, cp1x, cp1y, cp2x, cp2y, x, y, -distance);
-              if (sc1 && sc2) {
-                outer[p] = 4;
-                outer[p + 1] = sc1[0];
-                outer[p + 2] = sc1[1];
-                outer[p + 3] = sc1[2];
-                outer[p + 4] = sc1[3];
-                outer[p + 5] = sc1[4];
-                outer[p + 6] = sc1[5];
-                outer[p + 7] = sc1[6];
-                outer[p + 8] = sc1[7];
-                inner[p] = sc2[1];
-                inner[p + 1] = sc2[0];
-                inner[p + 2] = sc2[3];
-                inner[p + 3] = sc2[2];
-                inner[p + 4] = sc2[5];
-                inner[p + 5] = sc2[4];
-                inner[p + 6] = sc2[7];
-                inner[p + 7] = sc2[6];
-                inner[p + 8] = 4;
-              }
-              p += 9;
-              i += 9;
-            }
-          }
-          if (outer.length) {
-            inner.reverse();
-            addLineCap(inner, outer[1], outer[2], styles);
-            addLineCap(outer, inner[1], inner[2], styles);
-            [].push.apply(outer, inner);
-            buildOutline(path, outer, styles);
-          }
-          return path;
-        };
-      }
-      defineProp(kanvas2dCtxProto, 'currentPath', {
-        get: function () {
-          var path = new pathClass();
-          path._copyFrom(this);
-          return path;
-        },
-        set: function (val) {
-          if (!(val instanceof pathClass))
-            throw new TypeError();
-          this.beginPath();
-          this._copyFrom(val);
-        }
-      });
-      kanvas2dCtxProto.beginPath = function () {
-        this._beginPath();
-        this._ops = this._ops.slice(this._tp - 1, this._tp + 1);
-        this._sp = this._tp = 0;
-      };
-      kanvas2dCtxProto.addPath = function (path) {
-        if (!(path instanceof pathClass))
-          throw new TypeError();
-        this.closePath();
-        this._addFrom(path);
-      };
-    }
-    if (shimEllipticalArcTo || shimPath) {
-      var recorderProto = Object.create(null);
-      defineLazyProp(recorderProto, '_ops', {
-        get: Array,
-        writable: true
-      });
-      defineProp(recorderProto, '_sp', {
-        value: 0,
-        writable: true
-      });
-      var pathMethods = [
-          [
-            PATH_OP_CLOSE,
-            'closePath',
-            '',
-            true
-          ],
-          [
-            PATH_OP_MOVE,
-            'moveTo',
-            'x,y',
-            true
-          ],
-          [
-            PATH_OP_LINE,
-            'lineTo',
-            'x,y'
-          ],
-          [
-            PATH_OP_CURVE,
-            'quadraticCurveTo',
-            'cpx,cpy,x,y'
-          ],
-          [
-            PATH_OP_BEZIER,
-            'bezierCurveTo',
-            'cp1x,cp1y,cp2x,cp2y,x,y'
-          ],
-          [
-            PATH_OP_ARCTO,
-            'arcTo',
-            'x1,y1,x2,y2,rx,ry,rotation'
-          ],
-          [
-            PATH_OP_RECT,
-            'rect',
-            'x,y,w,h'
-          ],
-          [
-            PATH_OP_ARC,
-            'arc',
-            'cx,cy,r,a0,a1,ccw'
-          ],
-          [
-            PATH_OP_ELLIPSE,
-            'ellipse',
-            'cx,cy,rx,ry,rotation,a0,a1,ccw'
-          ]
-        ];
-      var opArgPartial = 'o[p+$($2+1;)]';
-      pathMethods.forEach(function (tuple) {
-        var code = tuple[0];
-        var name = tuple[1];
-        var params = tuple[2];
-        var move = tuple[3];
-        var tmpl = tmplf('function($2){this._$1($2);$$1;var o=this._ops,p=o.length;o[p]=$3,$(_($4,$6+"=+$1");),o[p+$(_($4).length+1;)]=$3;$($2&&!$5?"if(!this._sp)":"";)this._sp=p+1}', name, params, code, params || 'this._sp', move, opArgPartial);
-        var fn = evalf(tmpl, '');
-        kanvas2dCtxProto[name] = fn;
-        if (nativePathClass && /{([\s\S]*)}/.test(kanvasPathProto[name]))
-          kanvasPathProto[name] = evalf(tmpl, RegExp.$1);
-        else
-          safeReplaceProp(kanvasPathProto, name, {
-            value: fn
-          });
-      });
-      defineProp(recorderProto, '_tp', {
-        value: 0,
-        writable: true
-      });
-      var transformProps = 'a,b,c,d,e,f';
-      var transformTmpl = tmplf('function($$2){this._$$1($$2);var t=this.currentTransform,o=this._ops,p=o.length$3;if(o[p-1]===$1)$(_($2,$4+$6););else o[p]=$1,$(_($2,$5+$6);),o[p+7]=$1,this._tp=p+1}', PATH_OP_TRANSFORM, transformProps, shimCurrentTransform ? ',m=this._ctm' : '', 'o[p-$(7-$2;)]', opArgPartial, '=$1=t.$1' + (shimCurrentTransform ? '=m[$2]=$1' : ''));
-      if (!shimCurrentTransform) {
-        [
-          [
-            'scale',
-            'x,y'
-          ],
-          [
-            'rotate',
-            'angle'
-          ],
-          [
-            'translate',
-            'x,y'
-          ],
-          [
-            'transform',
-            transformProps
-          ],
-          [
-            'resetTransform',
-            ''
-          ]
-        ].forEach(function (tuple) {
-          var name = tuple[0];
-          var params = tuple[1];
-          if (!(name in kanvas2dCtxProto))
-            kanvas2dCtxProto[name] = evalf(transformTmpl, name, params);
-        });
-      }
-      kanvas2dCtxProto.setTransform = evalf(transformTmpl, 'setTransform', transformProps);
-      var concatPathTmpl = tmplf('function(path){this.beginPath();var o=path._ops,p=0;while(p<o.length)switch(o[p]){$(_($1,"case $($1[0];):this._$($1[1];)($(_($1[2],\'"+$3+"\');));p+=$(_($1[2]).length+2;);break;","");)default:this._$$1($(_($2,$3);));p+=8}}', pathMethods, transformProps, opArgPartial);
-      defineProp(recorderProto, '_copyFrom', {
-        value: evalf(concatPathTmpl, 'setTransform')
-      });
-      defineProp(recorderProto, '_addFrom', {
-        value: evalf(concatPathTmpl, 'transform')
-      });
-      mixinProps(kanvas2dCtxProto, recorderProto);
-      mixinProps(kanvasPathProto, recorderProto);
-    }
-    if (shimHitRegions) {
-      defineLazyProp(kanvas2dCtxProto, '_map', {
-        get: function () {
-          var c = this.canvas;
-          var hrlist = this._hrlist;
-          c.addEventListener('mousemove', function (e) {
-            var x = e.clientX - c.offsetLeft;
-            var y = e.clientY - c.offsetTop;
-            var px = map.getImageData(x, y, 1, 1).data;
-            var p = (px[0] << 16 | px[1] << 8 | px[2]) / 255;
-            var region = hrlist[p - 1];
-            if (region) {
-              e.region = region.id;
-              if (region.control) {
-                var evt = doc.createEvent('MouseEvents');
-                evt.initMouseEvent('mousemove', e.bubbles, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, c);
-                region.control.dispatchEvent(evt);
-              }
-            } else {
-              e.region = '';
-            }
-          }, true);
-          var c2 = this.canvas.cloneNode();
-          var map = c2.getContext('kanvas-2d');
-          return map;
-        }
-      });
-      defineLazyProp(kanvas2dCtxProto, '_hrlist', {
-        get: Array
-      });
-      kanvas2dCtxProto.addHitRegion = function (options) {
-        if (typeof options !== 'object')
-          return;
-        var path = options.path || this.currentPath;
-        var color = (this._hrlist.length + 1) * 255;
-        var map = this._map;
-        var ct = this.currentTransform;
-        map.beginPath();
-        map.setTransform(ct.a, ct.b, ct.c, ct.d, ct.e, ct.f);
-        map.addPath(path);
-        map.fillStyle = '#' + ('000000' + color.toString(16)).substr(-6);
-        map.fill();
-        this._hrlist.push({
-          color: color,
-          bounding: path.getBounds(),
-          id: options.id || '',
-          parent: options.parent || null,
-          cursor: options.cursor || 'inherit',
-          control: options.control || null
-        });
-      };
-      kanvas2dCtxProto.removeHitRegion = function (options) {
-        if (options.id)
-          delete this._hrlist[options.id];
-      };
-      kanvas2dCtxProto.clearRect = function (x, y, w, h) {
-        this._clearRect(x, y, w, h);
-        this._map._clearRect(x, y, w, h);
-      };
-    }
-    defineProp(nativeCanvasProto, '_pctx', {
-      value: null
-    });
-    nativeCanvasProto._getContext = nativeCanvasProto.getContext;
-    nativeCanvasProto.getContext = function (ctxId) {
-      var pctx = this._pctx;
-      var ctx;
-      if (ctxId === 'kanvas-2d') {
-        ctx = this._getContext('2d');
-        if (pctx)
-          return pctx === ctx ? ctx : null;
-        mixinProps(ctx, kanvas2dCtxProto);
-      } else {
-        ctx = this._getContext.apply(this, arguments);
-      }
-      if (!pctx && ctx !== null)
-        defineProp(ctx, '_pctx', {
-          value: ctx
-        });
-      return ctx;
-    };
-    Kanvas.SVGMatrix = transformClass;
-    Kanvas.Path = pathClass;
-    return Kanvas;
-  }(document);
 (function (exports) {
   var ArgumentParser = function () {
       var Argument = function () {
           function argument(shortName, longName, type, options) {
             this.shortName = shortName;
             this.longName = longName;
             this.type = type;
             options = options || {};
@@ -2660,19 +1072,20 @@ function defineFont(tag, dictionary) {
       indices.push(i);
     }
     ranges.push([
       UAC_OFFSET,
       UAC_OFFSET + glyphCount - 1,
       indices
     ]);
   }
-  var ascent = Math.ceil(tag.ascent / 20) || 1024;
-  var descent = -Math.ceil(tag.descent / 20) || 0;
-  var leading = Math.floor(tag.leading / 20) || 0;
+  var resolution = tag.resolution || 1;
+  var ascent = Math.ceil(tag.ascent / resolution) || 1024;
+  var descent = -Math.ceil(tag.descent / resolution) | 0;
+  var leading = tag.leading / resolution | 0;
   tables['OS/2'] = '\0\x01\0\0' + toString16(tag.bold ? 700 : 400) + '\0\x05' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0\0\0\0\0\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + '\0\0\0\0' + 'ALF ' + toString16((tag.italic ? 1 : 0) | (tag.bold ? 32 : 0)) + toString16(codes[0]) + toString16(codes[codes.length - 1]) + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(ascent) + toString16(-descent) + '\0\0\0\0' + '\0\0\0\0';
   ;
   var startCount = '';
   var endCount = '';
   var idDelta = '';
   var idRangeOffset = '';
   var i = 0;
   var range;
@@ -2693,17 +1106,16 @@ function defineFont(tag, dictionary) {
   var searchRange = maxPower2(segCount) * 2;
   var rangeShift = 2 * segCount - searchRange;
   var format314 = '\0\0' + toString16(segCount * 2) + toString16(searchRange) + toString16(logE(segCount) / logE(2)) + toString16(rangeShift) + endCount + '\0\0' + startCount + idDelta + idRangeOffset;
   ;
   tables['cmap'] = '\0\0\0\x01\0\x03\0\x01\0\0\0\f\0\x04' + toString16(format314.length + 4) + format314;
   ;
   var glyf = '\0\x01\0\0\0\0\0\0\0\0\0\0\0\x001\0';
   var loca = '\0\0';
-  var resolution = tag.resolution || 1;
   var offset = 16;
   var maxPoints = 0;
   var xMins = [];
   var xMaxs = [];
   var yMins = [];
   var yMaxs = [];
   var maxContours = 0;
   var i = 0;
@@ -2818,20 +1230,19 @@ function defineFont(tag, dictionary) {
     yMaxs.push(yMax);
     if (numberOfContours > maxContours)
       maxContours = numberOfContours;
     if (endPoint > maxPoints)
       maxPoints = endPoint;
   }
   loca += toString16(offset / 2);
   tables['glyf'] = glyf;
-  tables['head'] = '\0\x01\0\0\0\x01\0\0\0\0\0\0_\x0f<\xf5\0\v\x04\0\0\0\0\0' + toString32(+new Date()) + '\0\0\0\0' + toString32(+new Date()) + toString16(min.apply(null, xMins)) + toString16(min.apply(null, yMins)) + toString16(max.apply(null, xMaxs)) + toString16(max.apply(null, yMaxs)) + toString16((tag.italic ? 2 : 0) | (tag.bold ? 1 : 0)) + '\0\b' + '\0\x02' + '\0\0' + '\0\0';
+  tables['head'] = '\0\x01\0\0\0\x01\0\0\0\0\0\0_\x0f<\xf5\0\v\x04\0\0\0\0\0' + toString32(Date.now()) + '\0\0\0\0' + toString32(Date.now()) + toString16(min.apply(null, xMins)) + toString16(min.apply(null, yMins)) + toString16(max.apply(null, xMaxs)) + toString16(max.apply(null, yMaxs)) + toString16((tag.italic ? 2 : 0) | (tag.bold ? 1 : 0)) + '\0\b' + '\0\x02' + '\0\0' + '\0\0';
   ;
   var advance = tag.advance;
-  var resolution = tag.resolution || 1;
   tables['hhea'] = '\0\x01\0\0' + toString16(ascent) + toString16(descent) + toString16(leading) + toString16(advance ? max.apply(null, advance) : 1024) + '\0\0' + '\0\0' + '\x03\xb8' + '\0\x01' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + toString16(glyphCount + 1);
   ;
   var hmtx = '\0\0\0\0';
   for (var i = 0; i < glyphCount; ++i)
     hmtx += toString16(advance ? advance[i] / resolution : 1024) + '\0\0';
   tables['hmtx'] = hmtx;
   if (tag.kerning) {
     var kerning = tag.kerning;
@@ -2898,26 +1309,28 @@ function defineFont(tag, dictionary) {
     while (offset & 3)
       ++offset;
     offset += length;
   }
   var otf = header + data;
   var unitPerEm = 1024;
   var metrics = {
       ascent: ascent / unitPerEm,
-      descent: descent / unitPerEm,
+      descent: -descent / unitPerEm,
       leading: leading / unitPerEm
     };
   return {
     type: 'font',
     id: tag.id,
     name: fontName,
     uniqueName: psName + uniqueId,
     codes: codes,
     metrics: metrics,
+    bold: tag.bold === 1,
+    italic: tag.italic === 1,
     data: otf
   };
 }
 function getUint16(buff, pos) {
   return buff[pos] << 8 | buff[pos + 1];
 }
 function parseJpegChunks(imgDef, bytes) {
   var i = 0;
@@ -2985,18 +1398,18 @@ function defineLabel(tag, dictionary) {
   var m = tag.matrix;
   var cmds = [
       'c.save()',
       'c.transform(' + [
         m.a,
         m.b,
         m.c,
         m.d,
-        m.tx,
-        m.ty
+        m.tx / 20,
+        m.ty / 20
       ].join(',') + ')',
       'c.scale(0.05, 0.05)'
     ];
   var dependencies = [];
   var x = 0;
   var y = 0;
   var i = 0;
   var record;
@@ -3478,19 +1891,18 @@ SegmentedPath.prototype = {
   }
 };
 var SHAPE_MOVE_TO = 1;
 var SHAPE_LINE_TO = 2;
 var SHAPE_CURVE_TO = 3;
 var SHAPE_WIDE_MOVE_TO = 4;
 var SHAPE_WIDE_LINE_TO = 5;
 var SHAPE_CUBIC_CURVE_TO = 6;
-var SHAPE_ROUND_CORNER = 7;
-var SHAPE_CIRCLE = 8;
-var SHAPE_ELLIPSE = 9;
+var SHAPE_CIRCLE = 7;
+var SHAPE_ELLIPSE = 8;
 function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   if (commandsCount) {
     this.commands = new Uint8Array(commandsCount);
     this.data = new Int32Array(dataLength);
     this.morphData = isMorph ? new Int32Array(dataLength) : null;
   } else {
@@ -3529,20 +1941,16 @@ ShapePath.prototype = {
     var y2 = y + h;
     this.commands.push(SHAPE_MOVE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO);
     this.data.push(x, y, x2, y, x2, y2, x, y2, x, y);
   },
   circle: function (x, y, radius) {
     this.commands.push(SHAPE_CIRCLE);
     this.data.push(x, y, radius);
   },
-  drawRoundCorner: function (cornerX, cornerY, curveEndX, curveEndY, radiusX, radiusY) {
-    this.commands.push(SHAPE_ROUND_CORNER);
-    this.data.push(cornerX, cornerY, curveEndX, curveEndY, radiusX, radiusY);
-  },
   ellipse: function (x, y, radiusX, radiusY) {
     this.commands.push(SHAPE_ELLIPSE);
     this.data.push(x, y, radiusX, radiusY);
   },
   draw: function (ctx, clip, ratio, colorTransform) {
     if (clip && !this.fillStyle) {
       return;
     }
@@ -3574,19 +1982,16 @@ ShapePath.prototype = {
           k += 2;
           break;
         case SHAPE_CURVE_TO:
           ctx.quadraticCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
           break;
         case SHAPE_CUBIC_CURVE_TO:
           ctx.bezierCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
           break;
-        case SHAPE_ROUND_CORNER:
-          ctx.arcTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
-          break;
         case SHAPE_CIRCLE:
           if (formOpen) {
             ctx.lineTo(formOpenX, formOpenY);
             formOpen = false;
           }
           ctx.moveTo((data[k] + data[k + 2]) / 20, data[k + 1] / 20);
           ctx.arc(data[k++] / 20, data[k++] / 20, data[k++] / 20, 0, Math.PI * 2, false);
           break;
@@ -3639,16 +2044,17 @@ ShapePath.prototype = {
           console.warn('Drawing command not supported for morph shapes: ' + commands[j]);
         }
       }
     }
     if (!clip) {
       var fillStyle = this.fillStyle;
       if (fillStyle) {
         colorTransform.setFillStyle(ctx, fillStyle.style);
+        ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = fillStyle.smooth;
         var m = fillStyle.transform;
         ctx.save();
         colorTransform.setAlpha(ctx);
         if (m) {
           ctx.transform(m.a, m.b, m.c, m.d, m.e / 20, m.f / 20);
         }
         ctx.fill();
         ctx.restore();
@@ -3768,43 +2174,16 @@ ShapePath.prototype = {
         }
         var roots = cubicXAtY(fromX, fromY, cpX, cpY, cp2X, cp2Y, toX, toY, y);
         for (var i = roots.length; i--;) {
           if (roots[i] >= x) {
             inside = !inside;
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        cpX = data[dataIndex++];
-        cpY = data[dataIndex++];
-        toX = data[dataIndex++];
-        toY = data[dataIndex++];
-        rX = data[dataIndex++];
-        rY = data[dataIndex++];
-        if (toY > y === fromY > y || fromX < x && toX < x) {
-          break;
-        }
-        if (fromX >= x && toX >= x) {
-          inside = !inside;
-          break;
-        }
-        if (toX > fromX === toY > fromY) {
-          cp2X = fromX;
-          cp2Y = toY;
-        } else {
-          cp2X = toX;
-          cp2Y = fromY;
-        }
-        localX = x - cp2X;
-        localY = y - cp2Y;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) <= 1 !== localX <= 0) {
-          inside = !inside;
-        }
-        break;
       case SHAPE_CIRCLE:
         toX = data[dataIndex++];
         toY = data[dataIndex++];
         var r = data[dataIndex++];
         localX = x - toX;
         localY = y - toY;
         if (localX * localX + localY * localY < r * r) {
           inside = !inside;
@@ -3957,46 +2336,16 @@ ShapePath.prototype = {
           if (curveY < minY || curveY > maxY) {
             continue;
           }
           if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
             return true;
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        cpX = data[dataIndex++];
-        cpY = data[dataIndex++];
-        toX = data[dataIndex++];
-        toY = data[dataIndex++];
-        rX = data[dataIndex++];
-        rY = data[dataIndex++];
-        if (maxX < fromX && maxX < toX || minX > fromX && minX > toX || maxY < fromY && maxY < toY || minY > fromY && minY > toY) {
-          break;
-        }
-        if (toX > fromX === toY > fromY) {
-          cp2X = fromX;
-          cp2Y = toY;
-        } else {
-          cp2X = toX;
-          cp2Y = fromY;
-        }
-        localX = Math.abs(x - cp2X);
-        localY = Math.abs(y - cp2Y);
-        localX -= halfWidth;
-        localY -= halfWidth;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
-          break;
-        }
-        localX += width;
-        localY += width;
-        if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
-          return true;
-        }
-        break;
       case SHAPE_CIRCLE:
         cpX = data[dataIndex++];
         cpY = data[dataIndex++];
         var r = data[dataIndex++];
         toX = cpX + r;
         toY = cpY;
         if (maxX < cpX - r || minX > cpX + r || maxY < cpY - r || minY > cpY + r) {
           break;
@@ -4048,17 +2397,17 @@ ShapePath.prototype = {
     }
     return bounds;
   },
   _calculateBounds: function () {
     var commands = this.commands;
     var data = this.data;
     var length = commands.length;
     var bounds;
-    if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_ROUND_CORNER) {
+    if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_CUBIC_CURVE_TO) {
       bounds = {
         xMin: data[0],
         yMin: data[1]
       };
     } else {
       bounds = {
         xMin: 0,
         yMin: 0
@@ -4119,19 +2468,16 @@ ShapePath.prototype = {
         }
         if (cpY < fromY || cp2Y < fromY || cpY > toY || cp2Y > toY) {
           extremes = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
           for (i = extremes.length; i--;) {
             extendBoundsByY(bounds, extremes[i]);
           }
         }
         break;
-      case SHAPE_ROUND_CORNER:
-        dataIndex += 6;
-        break;
       case SHAPE_CIRCLE:
         toX = data[dataIndex++];
         toY = data[dataIndex++];
         var radius = data[dataIndex++];
         extendBoundsByPoint(bounds, toX - radius, toY - radius);
         extendBoundsByPoint(bounds, toX + radius, toY + radius);
         toX += radius;
         break;
@@ -4399,17 +2745,17 @@ function finishShapePaths(paths, diction
       path.morphData = untypedPath.morphData;
     }
     path.fillStyle && initStyle(path.fillStyle, dictionary);
     path.lineStyle && initStyle(path.lineStyle, dictionary);
     path.fullyInitialized = true;
   }
 }
 var inWorker = typeof window === 'undefined';
-var factoryCtx = !inWorker ? document.createElement('canvas').getContext('kanvas-2d') : null;
+var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
 function buildLinearGradientFactory(colorStops) {
   var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createLinearGradient(ctx, colorTransform) {
     var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
     for (var i = 0; i < colorStops.length; i++) {
@@ -5109,17 +3455,17 @@ if (isWorker) {
       onloaded(null, null, error);
     };
     session.pushAsync(data);
     session.close();
   };
 }
 SWF.embed = function (file, doc, container, options) {
   var canvas = doc.createElement('canvas');
-  var ctx = canvas.getContext('kanvas-2d');
+  var ctx = canvas.getContext('2d');
   var loader = new flash.display.Loader();
   var loaderInfo = loader.contentLoaderInfo;
   var stage = new flash.display.Stage();
   stage._loader = loader;
   loaderInfo._parameters = options.movieParams;
   loaderInfo._url = options.url || (typeof file === 'string' ? file : null);
   loaderInfo._loaderURL = options.loaderURL || loaderInfo._url;
   var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
@@ -5156,53 +3502,53 @@ SWF.embed = function (file, doc, contain
         canvasHolder.style.height = stage._stageHeight / 20 + 'px';
       }
       canvas.width = stage._stageWidth * pixelRatio / 20;
       canvas.height = stage._stageHeight * pixelRatio / 20;
     }
     container.setAttribute('style', 'position: relative');
     canvas.addEventListener('click', function () {
       ShumwayKeyboardListener.focus = stage;
-      stage._clickTarget._dispatchEvent(new flash.events.MouseEvent('click'));
+      stage._mouseTarget._dispatchEvent('click');
     });
     canvas.addEventListener('dblclick', function () {
-      if (stage._clickTarget._doubleClickEnabled) {
-        stage._clickTarget._dispatchEvent(new flash.events.MouseEvent('doubleClick'));
+      if (stage._mouseTarget._doubleClickEnabled) {
+        stage._mouseTarget._dispatchEvent('doubleClick');
       }
     });
     canvas.addEventListener('mousedown', function () {
-      if (stage._clickTarget._buttonMode) {
-        stage._clickTarget._gotoButtonState('down');
-      }
-      stage._clickTarget._dispatchEvent(new flash.events.MouseEvent('mouseDown'));
+      if (stage._mouseTarget._buttonMode) {
+        stage._mouseTarget._gotoButtonState('down');
+      }
+      stage._mouseTarget._dispatchEvent('mouseDown');
     });
     canvas.addEventListener('mousemove', function (domEvt) {
       var node = this;
       var left = 0;
       var top = 0;
       if (node.offsetParent) {
         do {
           left += node.offsetLeft;
           top += node.offsetTop;
         } while (node = node.offsetParent);
       }
-      var canvasState = stage._canvasState;
-      var mouseX = ((domEvt.pageX - left) * pixelRatio - canvasState.offsetX) / canvasState.scaleX;
-      var mouseY = ((domEvt.pageY - top) * pixelRatio - canvasState.offsetY) / canvasState.scaleY;
+      var m = stage._concatenatedTransform;
+      var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx) / m.a;
+      var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty) / m.d;
       if (mouseX !== stage._mouseX || mouseY !== stage._mouseY) {
         stage._mouseMoved = true;
         stage._mouseX = mouseX * 20;
         stage._mouseY = mouseY * 20;
       }
     });
     canvas.addEventListener('mouseup', function () {
-      if (stage._clickTarget._buttonMode) {
-        stage._clickTarget._gotoButtonState('over');
-      }
-      stage._clickTarget._dispatchEvent(new flash.events.MouseEvent('mouseUp'));
+      if (stage._mouseTarget._buttonMode) {
+        stage._mouseTarget._gotoButtonState('over');
+      }
+      stage._mouseTarget._dispatchEvent('mouseUp');
     });
     canvas.addEventListener('mouseover', function () {
       stage._mouseMoved = true;
       stage._mouseOver = true;
     });
     canvas.addEventListener('mouseout', function () {
       stage._mouseMoved = true;
       stage._mouseOver = false;
@@ -5267,17 +3613,17 @@ if (typeof FirefoxCom !== 'undefined') {
 var CanvasCache = {
     cache: [],
     getCanvas: function getCanvas(protoCanvas) {
       var tempCanvas = this.cache.shift();
       if (!tempCanvas) {
         tempCanvas = {
           canvas: document.createElement('canvas')
         };
-        tempCanvas.ctx = tempCanvas.canvas.getContext('kanvas-2d');
+        tempCanvas.ctx = tempCanvas.canvas.getContext('2d');
       }
       tempCanvas.canvas.width = protoCanvas.width;
       tempCanvas.canvas.height = protoCanvas.height;
       tempCanvas.ctx.save();
       return tempCanvas;
     },
     releaseCanvas: function releaseCanvas(tempCanvas) {
       tempCanvas.ctx.restore();
@@ -5303,38 +3649,28 @@ function visitContainer(container, visit
     }
     if (visitor.ignoreVisibleAttribute || child._visible && !child._maskedObject) {
       var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child) || flash.display.SimpleButton.class.isInstanceOf(child);
       visitor.visit(child, isContainer, visitContainer, context);
     }
   }
   visitor.childrenEnd(container);
 }
+var BlendModeNameMap = {
+    'normal': 'normal',
+    'multiply': 'multiply',
+    'screen': 'screen',
+    'lighten': 'lighten',
+    'darken': 'darken',
+    'difference': 'difference',
+    'overlay': 'overlay',
+    'hardlight': 'hard-light'
+  };
 function getBlendModeName(blendMode) {
-  var blendModeClass = flash.display.BlendMode.class;
-  if (blendMode === blendModeClass.NORMAL) {
-    return 'normal';
-  }
-  switch (blendMode) {
-  case blendModeClass.MULTIPLY:
-    return 'multiply';
-  case blendModeClass.SCREEN:
-    return 'screen';
-  case blendModeClass.LIGHTEN:
-    return 'lighten';
-  case blendModeClass.DARKEN:
-    return 'darken';
-  case blendModeClass.DIFFERENCE:
-    return 'difference';
-  case blendModeClass.OVERLAY:
-    return 'overlay';
-  case blendModeClass.HARDLIGHT:
-    return 'hard-light';
-  }
-  return 'normal';
+  return BlendModeNameMap[blendMode] || 'normal';
 }
 function RenderVisitor(root, ctx, invalidPath, refreshStage) {
   this.root = root;
   this.ctx = ctx;
   this.depth = 0;
   this.invalidPath = invalidPath;
   this.refreshStage = refreshStage;
   this.clipDepth = null;
@@ -5451,27 +3787,28 @@ RenderVisitor.prototype = {
       ctx.clip();
       context.isClippingMask = parentHasClippingMask;
       context.colorTransform = parentColorTransform;
       return;
     }
     ctx.save();
     ctx.globalCompositeOperation = getBlendModeName(child._blendMode);
     if (child._mask) {
+      var m = child._parent._getConcatenatedTransform(true);
       var tempCanvas, tempCtx, maskCanvas, maskCtx;
       maskCanvas = CanvasCache.getCanvas(ctx.canvas);
       maskCtx = maskCanvas.ctx;
-      maskCtx.currentTransform = ctx.currentTransform;
+      maskCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty);
       var isMaskContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child._mask) || flash.display.SimpleButton.class.isInstanceOf(child._mask);
       this.ctx = maskCtx;
       this.visit(child._mask, isMaskContainer, visitContainer, new RenderingContext(this.refreshStage));
       this.ctx = ctx;
       tempCanvas = CanvasCache.getCanvas(ctx.canvas);
       tempCtx = tempCanvas.ctx;
-      tempCtx.currentTransform = ctx.currentTransform;
+      tempCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty);
       renderDisplayObject(child, tempCtx, context);
       if (isContainer) {
         this.ctx = tempCtx;
         visitContainer(child, this, context);
         this.ctx = ctx;
       }
       tempCtx.globalCompositeOperation = 'destination-in';
       tempCtx.setTransform(1, 0, 0, 1, 0, 0);
@@ -5745,39 +4082,37 @@ function renderStage(stage, ctx, events)
     if (align.indexOf('T') >= 0) {
       offsetY = 0;
     } else if (align.indexOf('B') >= 0) {
       offsetY = frameHeight - scaleY * stage._stageHeight / 20;
     } else {
       offsetY = (frameHeight - scaleY * stage._stageHeight / 20) / 2;
     }
     ctx.setTransform(scaleX, 0, 0, scaleY, offsetX, offsetY);
-    stage._canvasState = {
-      canvas: ctx.canvas,
-      scaleX: scaleX,
-      scaleY: scaleY,
-      offsetX: offsetX,
-      offsetY: offsetY
-    };
+    var m = stage._concatenatedTransform;
+    m.a = scaleX;
+    m.d = scaleY;
+    m.tx = offsetX;
+    m.ty = offsetY;
   }
   updateRenderTransform();
   var frameTime = 0;
   var maxDelay = 1000 / stage._frameRate;
   var nextRenderAt = performance.now();
   var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout;
   var renderDummyBalls;
   var dummyBalls;
   if (typeof FirefoxCom !== 'undefined' && FirefoxCom.requestSync('getBoolPref', {
       pref: 'shumway.dummyMode',
       def: false
     })) {
     var radius = 10;
     var speed = 1;
-    var canvasState = stage._canvasState;
-    var scaleX = canvasState.scaleX, scaleY = canvasState.scaleY;
+    var m = stage._concatenatedTransform;
+    var scaleX = m.a, scaleY = m.d;
     dummyBalls = [];
     for (var i = 0; i < 10; i++) {
       dummyBalls.push({
         position: {
           x: radius + Math.random() * ((ctx.canvas.width - 2 * radius) / scaleX),
           y: radius + Math.random() * ((ctx.canvas.height - 2 * radius) / scaleY)
         },
         velocity: {
@@ -5876,19 +4211,21 @@ function renderStage(stage, ctx, events)
         stage._deferRenderEvent = false;
         domain.broadcastMessage('render', 'render');
       }
       if (isCanvasVisible(ctx.canvas) && (refreshStage || renderFrame)) {
         var invalidPath = null;
         if (!disablePreVisitor.value) {
           traceRenderer.value && frameWriter.enter('> Pre Visitor');
           fps && fps.enter('PRE');
-          invalidPath = stage._processInvalidRegions();
+          invalidPath = stage._processInvalidRegions(true);
           fps && fps.leave('PRE');
           traceRenderer.value && frameWriter.leave('< Pre Visitor');
+        } else {
+          stage._processInvalidRegions(false);
         }
         if (!disableRenderVisitor.value) {
           fps && fps.enter('RENDER');
           traceRenderer.value && frameWriter.enter('> Render Visitor');
           new RenderVisitor(stage, ctx, invalidPath, refreshStage).start();
           traceRenderer.value && frameWriter.leave('< Render Visitor');
           fps && fps.leave('RENDER');
         }
@@ -6155,187 +4492,23 @@ var tagHandler = function (global) {
             $29.depth = readUi16($bytes, $stream);
             var $30 = $29.matrix = {};
             matrix($bytes, $stream, $30, swfVersion, tagCode);
             if (tagCode === 34) {
               var $31 = $29.cxform = {};
               cxform($bytes, $stream, $31, swfVersion, tagCode);
             }
             if (hasFilters) {
-              $29.filterCount = readUi8($bytes, $stream);
-              var $32 = $29.filters = {};
-              var type = $32.type = readUi8($bytes, $stream);
-              switch (type) {
-              case 0:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $33 = $32.colors = [];
-                var $34 = count;
-                while ($34--) {
-                  var $35 = {};
-                  rgba($bytes, $stream, $35, swfVersion, tagCode);
-                  $33.push($35);
-                }
-                if (type === 3) {
-                  var $36 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $36, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $37 = $32.ratios = [];
-                  var $38 = count;
-                  while ($38--) {
-                    $37.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              case 1:
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                $32.passes = readUb($bytes, $stream, 5);
-                var reserved = readUb($bytes, $stream, 3);
-                break;
-              case 2:
-              case 3:
-              case 4:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $39 = $32.colors = [];
-                var $40 = count;
-                while ($40--) {
-                  var $41 = {};
-                  rgba($bytes, $stream, $41, swfVersion, tagCode);
-                  $39.push($41);
-                }
-                if (type === 3) {
-                  var $42 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $42, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $43 = $32.ratios = [];
-                  var $44 = count;
-                  while ($44--) {
-                    $43.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              case 5:
-                var columns = $32.columns = readUi8($bytes, $stream);
-                var rows = $32.rows = readUi8($bytes, $stream);
-                $32.divisor = readFloat($bytes, $stream);
-                $32.bias = readFloat($bytes, $stream);
-                var $45 = $32.weights = [];
-                var $46 = columns * rows;
-                while ($46--) {
-                  $45.push(readFloat($bytes, $stream));
-                }
-                var $47 = $32.defaultColor = {};
-                rgba($bytes, $stream, $47, swfVersion, tagCode);
-                var reserved = readUb($bytes, $stream, 6);
-                $32.clamp = readUb($bytes, $stream, 1);
-                $32.preserveAlpha = readUb($bytes, $stream, 1);
-                break;
-              case 6:
-                var $48 = $32.matrix = [];
-                var $49 = 20;
-                while ($49--) {
-                  $48.push(readFloat($bytes, $stream));
-                }
-                break;
-              case 7:
-                if (type === 4 || type === 7) {
-                  count = readUi8($bytes, $stream);
-                } else {
-                  count = 1;
-                }
-                var $50 = $32.colors = [];
-                var $51 = count;
-                while ($51--) {
-                  var $52 = {};
-                  rgba($bytes, $stream, $52, swfVersion, tagCode);
-                  $50.push($52);
-                }
-                if (type === 3) {
-                  var $53 = $32.higlightColor = {};
-                  rgba($bytes, $stream, $53, swfVersion, tagCode);
-                }
-                if (type === 4 || type === 7) {
-                  var $54 = $32.ratios = [];
-                  var $55 = count;
-                  while ($55--) {
-                    $54.push(readUi8($bytes, $stream));
-                  }
-                }
-                $32.blurX = readFixed($bytes, $stream);
-                $32.blurY = readFixed($bytes, $stream);
-                if (type !== 2) {
-                  $32.angle = readFixed($bytes, $stream);
-                  $32.distance = readFixed($bytes, $stream);
-                }
-                $32.strength = readFixed8($bytes, $stream);
-                $32.innerShadow = readUb($bytes, $stream, 1);
-                $32.knockout = readUb($bytes, $stream, 1);
-                $32.compositeSource = readUb($bytes, $stream, 1);
-                if (type === 3) {
-                  $32.onTop = readUb($bytes, $stream, 1);
-                } else {
-                  var reserved = readUb($bytes, $stream, 1);
-                }
-                if (type === 4 || type === 7) {
-                  $32.passes = readUb($bytes, $stream, 4);
-                } else {
-                  var reserved = readUb($bytes, $stream, 4);
-                }
-                break;
-              default:
+              var count = readUi8($bytes, $stream);
+              var $2 = $.filters = [];
+              var $3 = count;
+              while ($3--) {
+                var $4 = {};
+                anyFilter($bytes, $stream, $4, swfVersion, tagCode);
+                $2.push($4);
               }
             }
             if (blend) {
               $29.blendMode = readUi8($bytes, $stream);
             }
           }
           $28.push($29);
         } while (!eob);
@@ -7715,19 +5888,19 @@ BodyParser.prototype = {
     } else {
       buffer.push(data);
       stream = buffer.createStream();
     }
     if (progressInfo) {
       swf.bytesLoaded = progressInfo.bytesLoaded;
       swf.bytesTotal = progressInfo.bytesTotal;
     }
-    var readStartTime = Date.now();
+    var readStartTime = performance.now();
     readTags(swf, stream, swfVersion, options.onprogress);
-    swf.parseTime += Date.now() - readStartTime;
+    swf.parseTime += performance.now() - readStartTime;
     var read = stream.pos;
     buffer.removeHead(read);
     this.totalRead += read;
     if (this.totalRead >= this.length && options.oncomplete) {
       options.oncomplete(swf);
     }
   }
 };
@@ -8068,16 +6241,17 @@ function as2ToBoolean(value) {
   case 'null':
     return false;
   case 'boolean':
     return value;
   case 'number':
     return value !== 0 && !isNaN(value);
   case 'string':
     return value.length !== 0;
+  case 'movieclip':
   case 'object':
     return true;
   }
 }
 function as2ToNumber(value) {
   value = as2ToPrimitive(value);
   switch (as2GetType(value)) {
   case 'undefined':
@@ -8311,17 +6485,17 @@ function interpretActions(actionsData, s
       var newScope = {};
       newScope.asSetPublicProperty('this', this);
       newScope.asSetPublicProperty('arguments', arguments);
       newScope.asSetPublicProperty('super', AS2_SUPER_STUB);
       newScope.asSetPublicProperty('__class', ownerClass);
       var newScopeContainer = scopeContainer.create(newScope);
       var i;
       for (i = 0; i < arguments.length || i < parametersNames.length; i++) {
-        newScope[parametersNames[i]] = arguments[i];
+        newScope.asSetPublicProperty(parametersNames[i], arguments[i]);
       }
       var registers = [];
       if (registersAllocation) {
         for (i = 0; i < registersAllocation.length; i++) {
           var registerAllocation = registersAllocation[i];
           if (!registerAllocation) {
             continue;
           }
@@ -8423,47 +6597,72 @@ function interpretActions(actionsData, s
       return {
         obj: obj,
         name: resolvedName || name,
         resolved: resolved
       };
     }
     return null;
   }
+  function getThis() {
+    var _this = scope.asGetPublicProperty('this');
+    if (_this) {
+      return _this;
+    }
+    for (var p = scopeContainer; p; p = p.next) {
+      resolvedName = as2ResolveProperty(p.scope, 'this');
+      if (resolvedName !== null) {
+        return p.scope.asGetPublicProperty(resolvedName);
+      }
+    }
+  }
   function getVariable(variableName) {
     if (scope.asHasProperty(undefined, variableName, 0)) {
       return scope.asGetPublicProperty(variableName);
     }
     var target = resolveVariableName(variableName);
     if (target) {
       return target.obj.asGetPublicProperty(target.name);
     }
+    var resolvedName, _this = getThis();
     for (var p = scopeContainer; p; p = p.next) {
-      var resolvedName = as2ResolveProperty(p.scope, variableName);
+      resolvedName = as2ResolveProperty(p.scope, variableName);
       if (resolvedName !== null) {
         return p.scope.asGetPublicProperty(resolvedName);
       }
     }
+    if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
+      return _this.asGetPublicProperty(resolvedName);
+    }
     var mc = isAS2MovieClip(defaultTarget) && defaultTarget.$lookupChild(variableName);
     if (mc) {
       return mc;
     }
   }
   function setVariable(variableName, value) {
     if (scope.asHasProperty(undefined, variableName, 0)) {
       scope.asSetPublicProperty(variableName, value);
       return;
     }
     var target = resolveVariableName(variableName, true);
     if (target) {
       target.obj.asSetPublicProperty(target.name, value);
       return;
     }
-    var _this = scope.asGetPublicProperty('this') || getVariable('this');
-    _this.asSetPublicProperty(variableName, value);
+    var resolvedName, _this = getThis();
+    if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
+      return _this.asSetPublicProperty(resolvedName, value);
+    }
+    for (var p = scopeContainer; p.next; p = p.next) {
+      resolvedName = as2ResolveProperty(p.scope, variableName);
+      if (resolvedName !== null) {
+        return p.scope.asSetPublicProperty(resolvedName, value);
+      }
+    }
+    (_this || scope).asSetPublicProperty(variableName, value);
   }
   function getFunction(functionName) {
     var fn = getVariable(functionName);
     if (!(fn instanceof Function)) {
       throw new Error('Function "' + functionName + '" is not found');
     }
     return fn;
   }
@@ -8554,17 +6753,19 @@ function interpretActions(actionsData, s
         var frame, type, count, index, target, method, constr, codeSize, offset;
         var name, variableName, methodName, functionName, targetName;
         var paramName, resolvedName, objectName;
         var value, a, b, c, f, sa, sb, obj, args, fn, result, flags, i;
         var dragParams, register;
         switch (actionCode | 0) {
         case 129:
           frame = stream.readUI16();
-          methodName = stream.readUI8() === 6 ? 'gotoAndPlay' : 'gotoAndStop';
+          var nextActionCode = stream.readUI8();
+          nextPosition++;
+          methodName = nextActionCode === 6 ? 'gotoAndPlay' : 'gotoAndStop';
           _global[methodName](frame + 1);
           break;
         case 131:
           var urlString = stream.readString();
           var targetString = stream.readString();
           _global.getURL(urlString, targetString);
           break;
         case 4:
@@ -8812,17 +7013,17 @@ function interpretActions(actionsData, s
         case 36:
           var depth = stack.pop();
           target = stack.pop();
           var source = stack.pop();
           _global.duplicateMovieClip(source, target, depth);
           break;
         case 37:
           target = stack.pop();
-          _global.unloadMovie(target);
+          _global.removeMovieClip(target);
           break;
         case 39:
           target = stack.pop();
           var lockcenter = stack.pop();
           var constrain = !stack.pop() ? null : {
               y2: stack.pop(),
               x2: stack.pop(),
               y1: stack.pop(),
@@ -9460,16 +7661,22 @@ if (!inBrowser) {
     info: print,
     warn: function (x) {
       if (traceWarnings.value) {
         print(x);
       }
     }
   };
 }
+if (!this.performance) {
+  this.performance = {};
+}
+if (!this.performance.now) {
+  this.performance.now = Date.now;
+}
 function backtrace() {
   try {
     throw new Error();
   } catch (e) {
     return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
   }
 }
 function error(message) {
@@ -9640,22 +7847,22 @@ function defineNewNonEnumerableProperty(
 }
 function isNullOrUndefined(value) {
   return value == undefined;
 }
 function isPowerOfTwo(x) {
   return x && (x & x - 1) === 0;
 }
 function time(fn, count) {
-  var start = new Date();
+  var start = performance.now();
   for (var i = 0; i < count; i++) {
     fn();
   }
-  var time = (new Date() - start) / count;
-  console.info('Took: ' + time + 'ms.');
+  var time = (performance.now() - start) / count;
+  console.info('Took: ' + time.toFixed(2) + 'ms.');
   return time;
 }
 function clamp(x, min, max) {
   if (x < min) {
     return min;
   } else if (x > max) {
     return max;
   }
@@ -9682,19 +7889,30 @@ function toKeyValueArray(o) {
         o[k]
       ]);
     }
   }
   return a;
 }
 function isNumeric(x) {
   if (typeof x === 'number') {
-    return true;
-  } else if (typeof x === 'string') {
-    return !isNaN(parseInt(x, 10));
+    return x === (x | 0);
+  }
+  if (typeof x === 'string' && x.length) {
+    if (x === '0') {
+      return true;
+    }
+    if (x[0] >= '1' && x[0] <= '9') {
+      for (var i = 1; i < x.length; i++) {
+        if (!(x[i] >= '1' && x[i] <= '9')) {
+          return false;
+        }
+      }
+      return true;
+    }
   }
   return false;
 }
 function boxValue(value) {
   if (isNullOrUndefined(value)) {
     return value;
   }
   return Object(value);
@@ -9706,34 +7924,18 @@ function isString(value) {
   return typeof value === 'string';
 }
 function isFunction(value) {
   return typeof value === 'function';
 }
 function isNumber(value) {
   return typeof value === 'number';
 }
-function toDouble(x) {
-  return toNumber(x);
-}
 function toNumber(x) {
-  return typeof x === 'number' ? x : Number(x);
-}
-function toBoolean(x) {
-  return !(!x);
-}
-function toUint(x) {
-  x = x | 0;
-  return x < 0 ? x + 4294967296 : x;
-}
-function toInt(x) {
-  return x | 0;
-}
-function toString(x) {
-  return String(x);
+  return +x;
 }
 function setBitFlags(flags, flag, value) {
   return value ? flags | flag : flags & ~flag;
 }
 function getBitFlags(flags, flag) {
   return !(!(flags & flag));
 }
 function popManyInto(src, count, dst) {
@@ -9923,26 +8125,35 @@ function utf8encode(bytes) {
       do {
         var mask = currentPrefix >> 1 | 128;
         if ((b1 & mask) === currentPrefix)
           break;
         currentPrefix = currentPrefix >> 1 | 128;
         --validBits;
       } while (validBits >= 0);
       if (validBits <= 0) {
-        throw 'Invalid UTF8 character';
+        str += String.fromCharCode(b1);
+        continue;
       }
       var code = b1 & (1 << validBits) - 1;
+      var invalid = false;
       for (var i = 5; i >= validBits; --i) {
         var bi = bytes[j++];
         if ((bi & 192) != 128) {
-          throw 'Invalid UTF8 character sequence';
+          invalid = true;
+          break;
         }
         code = code << 6 | bi & 63;
       }
+      if (invalid) {
+        for (var k = j - (7 - i); k < j; ++k) {
+          str += String.fromCharCode(bytes[k] & 255);
+        }
+        continue;
+      }
       if (code >= 65536) {
         str += String.fromCharCode(code - 65536 >> 10 & 1023 | 55296, code & 1023 | 56320);
       } else {
         str += String.fromCharCode(code);
       }
     }
   }
   return str;
@@ -10686,49 +8897,54 @@ var CircularBuffer = function () {
       return this.index + 1 & mask === this.start;
     };
     circularBuffer.prototype.isEmpty = function () {
       return this.index === this.start;
     };
     return circularBuffer;
   }();
 (function (exports) {
+  if (!performance) {
+    performance = {
+      now: Date.now
+    };
+  }
   var Timer = function () {
       var base = new timer(null, 'Total'), top = base;
       var flat = new timer(null, 'Flat'), flatStack = [];
       function timer(parent, name) {
         this.parent = parent;
         this.timers = {};
         this.name = name;
         this.begin = 0;
         this.last = 0;
         this.total = 0;
         this.count = 0;
       }
       timer.flat = flat;
       function getTicks() {
-        return new Date().getTime();
+        return performance.now();
       }
       timer.prototype.start = function () {
         this.begin = getTicks();
       };
       timer.prototype.stop = function () {
         this.last = getTicks() - this.begin;
         this.total += this.last;
         this.count += 1;
       };
       timer.time = function (name, fn) {
         timer.start(name);
         fn();
         timer.stop();
       };
       timer.start = function (name) {
-        top = name in top.timers ? top.timers[name] : top.timers[name] = new timer(top, name);
+        top = top.timers[name] || (top.timers[name] = new timer(top, name));
         top.start();
-        var tmp = name in flat.timers ? flat.timers[name] : flat.timers[name] = new timer(flat, name);
+        var tmp = flat.timers[name] || (flat.timers[name] = new timer(flat, name));
         tmp.start();
         flatStack.push(tmp);
       };
       timer.stop = function () {
         top.stop();
         top = top.parent;
         flatStack.pop().stop();
       };
@@ -11729,20 +9945,16 @@ var Errors = {
     InvalidSocketError: {
       code: 2002,
       message: 'Operation attempted on invalid socket.'
     },
     InvalidSocketPortError: {
       code: 2003,
       message: 'Invalid socket port number specified.'
     },
-    InvalidParamError: {
-      code: 2004,
-      message: 'One of the parameters is invalid.'
-    },
     ParamTypeError: {
       code: 2005,
       message: 'Parameter %1 is of the incorrect type. Should be type %2.'
     },
     HasStyleSheetError: {
       code: 2009,
       message: 'This method cannot be used on a text field with a style sheet.'
     },
@@ -11989,20 +10201,16 @@ var Errors = {
     CloseNotConnectedError: {
       code: 2083,
       message: 'Close failed because the object is not connected.'
     },
     ArgumentSizeError: {
       code: 2084,
       message: 'The AMF encoding of the arguments cannot exceed 40K.'
     },
-    EmptyStringError: {
-      code: 2085,
-      message: 'Parameter %1 must be non-empty string.'
-    },
     FileReferenceProhibitedError: {
       code: 2086,
       message: 'A setting in the mms.cfg file prohibits this FileReference request.'
     },
     DownloadFileNameProhibitedError: {
       code: 2087,
       message: 'The FileReference.download() file name contains prohibited characters.'
     },
@@ -12285,20 +10493,16 @@ var Errors = {
     FragmentMissing: {
       code: 2171,
       message: 'The Shader object contains no byte code to execute.'
     },
     FragmentAlreadyRunning: {
       code: 2172,
       message: 'The ShaderJob is already running or finished.'
     },
-    ReadExternalNotImplementedError: {
-      code: 2173,
-      message: 'Unable to read object in stream.  The class %1 does not implement flash.utils.IExternalizable but is aliased to an externalizable class.'
-    },
     FileReferenceBusyError: {
       code: 2174,
       message: 'Only one download, upload, load or save operation can be active at a time on each FileReference.'
     },
     UnformattedElementError: {
       code: 2175,
       message: 'One or more elements of the content of the TextBlock has a null ElementFormat.'
     },
@@ -15274,16 +13478,23 @@ var Multiname = function () {
         }
         mn = mn.qualifiedName = qualifyNameInternal(mn.namespaces[0].qualifiedName, name);
       }
       return mn;
     };
     multiname.qualifyName = function qualifyName(namespace, name) {
       return qualifyNameInternal(namespace.qualifiedName, name);
     };
+    multiname.stripPublicQualifier = function stripPublicQualifier(qn) {
+      var index = qn.indexOf(PUBLIC_QUALIFIED_NAME_PREFIX);
+      if (index !== 0) {
+        return undefined;
+      }
+      return qn.substring(PUBLIC_QUALIFIED_NAME_PREFIX.length);
+    };
     multiname.fromQualifiedName = function fromQualifiedName(qn) {
       if (qn instanceof Multiname) {
         return qn;
       }
       true;
       var a = qn.indexOf('$');
       if (a < 0 || !ShumwayNamespace.PREFIXES[qn.substring(0, a)]) {
         return undefined;
@@ -15303,17 +13514,16 @@ var Multiname = function () {
     };
     multiname.PUBLIC_QUALIFIED_NAME_PREFIX = PUBLIC_QUALIFIED_NAME_PREFIX;
     multiname.getPublicQualifiedName = function getPublicQualifiedName(name) {
       if (isNumeric(name)) {
         return toNumber(name);
       } else if (name !== null && isObject(name)) {
         return name;
       }
-      true;
       return PUBLIC_QUALIFIED_NAME_PREFIX + name;
     };
     multiname.isPublicQualifiedName = function isPublicQualifiedName(qn) {
       return typeof qn === 'number' || isNumeric(qn) || qn.indexOf(PUBLIC_QUALIFIED_NAME_PREFIX) === 0;
     };
     multiname.getAccessModifier = function getAccessModifier(mn) {
       true;
       if (typeof mn === 'number' || typeof mn === 'string' || mn instanceof Number) {
@@ -23879,23 +22089,22 @@ var createName = function createName(nam
                 value: value
               });
               buildReturnStop();
               break;
             case 30:
             case 35:
               index = pop();
               object = pop();
-              push(call(globalProperty(op === OP_nextname ? 'nextName' : 'nextValue'), null, [
-                object,
+              push(new IR.CallProperty(region, state.store, object, constant(op === OP_nextname ? 'asNextName' : 'asNextValue'), [
                 index
-              ]));
+              ], IR.Flags.PRISTINE));
               break;
             case 50:
-              var temp = call(globalProperty('hasNext2'), null, [
+              var temp = call(globalProperty('asHasNext2'), null, [
                   local[bc.object],
                   local[bc.index]
                 ]);
               local[bc.object] = getJSProperty(temp, 'object');
               push(local[bc.index] = getJSProperty(temp, 'index'));
               break;
             case 32:
               push(Null);
@@ -25996,17 +24205,17 @@ var Compiler = new (function () {
   };
   IR.CallProperty.prototype.compile = function (cx) {
     var object = compileValue(this.object, cx);
     var name = compileValue(this.name, cx);
     var callee = property(object, name);
     var args = this.args.map(function (arg) {
         return compileValue(arg, cx);
       });
-    if (this.pristine) {
+    if (this.flags & IR.Flags.PRISTINE) {
       return call(callee, args);
     } else {
       return callCall(callee, object, args);
     }
   };
   IR.ASCallProperty.prototype.compile = function (cx) {
     var object = compileValue(this.object, cx);
     var args = this.args.map(function (arg) {
@@ -26107,26 +24316,26 @@ var Compiler = new (function () {
       object,
       name
     ]);
   };
   IR.ASSetSlot.prototype.compile = function (cx) {
     var object = compileValue(this.object, cx);
     var name = compileValue(this.name, cx);
     var value = compileValue(this.value, cx);
-    return call(id('setSlot'), [
+    return call(id('asSetSlot'), [
       object,
       name,
       value
     ]);
   };
   IR.ASGetSlot.prototype.compile = function (cx) {
     var object = compileValue(this.object, cx);
     var name = compileValue(this.name, cx);
-    return call(id('getSlot'), [
+    return call(id('asGetSlot'), [
       object,
       name
     ]);
   };
   IR.Projection.prototype.compile = function (cx) {
     true;
     true;
     return compileValue(this.argument.scope, cx);
@@ -27960,24 +26169,19 @@ var globalMultinameAnalysis = runtimeOpt
 var traceInlineCaching = runtimeOptions.register(new Option('tic', 'traceInlineCaching', 'boolean', false, 'Trace inline caching execution.'));
 var compilerEnableExceptions = runtimeOptions.register(new Option('cex', 'exceptions', 'boolean', false, 'Compile functions with catch blocks.'));
 var compilerMaximumMethodSize = runtimeOptions.register(new Option('cmms', 'maximumMethodSize', 'number', 4 * 1024, 'Compiler maximum method size.'));
 var jsGlobal = function () {
     return this || (1, eval)('this');
   }();
 var VM_SLOTS = 'vm slots';
 var VM_LENGTH = 'vm length';
-var VM_TRAITS = 'vm traits';
 var VM_BINDINGS = 'vm bindings';
 var VM_NATIVE_PROTOTYPE_FLAG = 'vm native prototype';
-var VM_ENUMERATION_KEYS = 'vm enumeration keys';
-var VM_TOMBSTONE = createEmptyObject();
 var VM_OPEN_METHODS = 'vm open methods';
-var VM_NEXT_NAME = 'vm next name';
-var VM_NEXT_NAME_INDEX = 'vm next name index';
 var VM_IS_CLASS = 'vm is class';
 var VM_OPEN_METHOD_PREFIX = 'open_';
 var VM_NATIVE_BUILTINS = [
     Object,
     Number,
     Boolean,
     String,
     Array,
@@ -28162,23 +26366,29 @@ function resolveMultinameProperty(namesp
     return Multiname.getPublicQualifiedName(name);
   } else {
     return namespaces[0].qualifiedName + '$' + name;
   }
 }
 function asGetPublicProperty(name) {
   return this.asGetProperty(undefined, name, 0);
 }
-function asGetProperty(namespaces, name, flags, isMethod) {
+function asGetProperty(namespaces, name, flags) {
   var resolved = this.resolveMultinameProperty(namespaces, name, flags);
   if (this.asGetNumericProperty && Multiname.isNumeric(resolved)) {
     return this.asGetNumericProperty(resolved);
   }
   return this[resolved];
 }
+function asGetPropertyLikelyNumeric(namespaces, name, flags) {
+  if (typeof name === 'number') {
+    return this.asGetNumericProperty(name);
+  }
+  return asGetProperty.call(this, namespaces, name, flags);
+}
 function asGetResolvedStringProperty(resolved) {
   true;
   return this[resolved];
 }
 function asCallResolvedStringProperty(resolved, isLex, args) {
   var receiver = isLex ? null : this;
   var openMethods = this[VM_OPEN_METHODS];
   var method;
@@ -28207,16 +26417,23 @@ function asSetProperty(namespaces, name,
     name = String(name);
   }
   var resolved = this.resolveMultinameProperty(namespaces, name, flags);
   if (this.asSetNumericProperty && Multiname.isNumeric(resolved)) {
     return this.asSetNumericProperty(resolved, value);
   }
   this[resolved] = value;
 }
+function asSetPropertyLikelyNumeric(namespaces, name, flags, value) {
+  if (typeof name === 'number') {
+    this.asSetNumericProperty(name, value);
+    return;
+  }
+  return asSetProperty.call(this, namespaces, name, flags, value);
+}
 function asDefinePublicProperty(name, descriptor) {
   return this.asDefineProperty(undefined, name, 0, descriptor);
 }
 function asDefineProperty(namespaces, name, flags, descriptor) {
   if (typeof name === 'object') {
     name = String(name);
   }
   var resolved = this.resolveMultinameProperty(namespaces, name, flags);
@@ -28285,93 +26502,70 @@ function asHasProperty(namespaces, name,
   }
   if (nonProxy) {
     return nonProxyingHasProperty(this, this.resolveMultinameProperty(namespaces, name, flags));
   } else {
     return this.resolveMultinameProperty(namespaces, name, flags) in this;
   }
 }
 function asDeleteProperty(namespaces, name, flags) {
-  if (this.deleteProperty) {
-    return this.deleteProperty(namespaces, name, flags);
-  }
-  if (this.indexDelete && Multiname.isNumeric(name)) {
-    return this.indexDelete(name);
-  }
   var resolved = this.resolveMultinameProperty(namespaces, name, flags);
-  if (this[VM_ENUMERATION_KEYS]) {
-    var index = this[VM_ENUMERATION_KEYS].indexOf(resolved);
-    if (index >= 0) {
-      this[VM_ENUMERATION_KEYS][index] = VM_TOMBSTONE;
-    }
-  }
   return delete this[resolved];
 }
 function asGetNumericProperty(i) {
   return this[i];
 }
 function asSetNumericProperty(i, v) {
   this[i] = v;
 }
 function asGetDescendants(namespaces, name, flags) {
   notImplemented('asGetDescendants');
 }
+function asNextNameIndex(index) {
+  if (index === 0) {
+    defineNonEnumerableProperty(this, 'enumerableKeys', this.asGetEnumerableKeys());
+  }
+  var enumerableKeys = this.enumerableKeys;
+  while (index < enumerableKeys.length) {
+    if (this.asHasProperty(undefined, enumerableKeys[index], 0)) {
+      return index + 1;
+    }
+    index++;
+  }
+  return 0;
+}
 function asNextName(index) {
-  notImplemented('asNextName');
-}
-function asNextNameIndex(index) {
-  notImplemented('asNextNameIndex');
+  var enumerableKeys = this.enumerableKeys;
+  true;
+  return enumerableKeys[index - 1];
 }
 function asNextValue(index) {
-  notImplemented('asNextValue');
+  return this.asGetPublicProperty(this.asNextName(index));
+}
+function asGetEnumerableKeys() {
+  var boxedValue = this.valueOf();
+  if (typeof boxedValue === 'string' || typeof boxedValue === 'number') {
+    return [];
+  }
+  var keys = Object.keys(this);
+  var result = [];
+  for (var i = 0; i < keys.length; i++) {
+    var key = keys[i];
+    if (isNumeric(key)) {
+      result.push(key);
+    } else {
+      var name = Multiname.stripPublicQualifier(key);
+      if (name !== undefined) {
+        result.push(name);
+      }
+    }
+  }
+  return result;
 }
 function initializeGlobalObject(global) {
-  function getEnumerationKeys(object) {
-    if (object.node && object.node.childNodes) {
-      object = object.node.childNodes;
-    }
-    var keys = [];
-    var boxedValue = object.valueOf();
-    if (typeof boxedValue === 'string' || typeof boxedValue === 'number') {
-      return [];
-    }
-    if (object.getEnumerationKeys) {
-      return object.getEnumerationKeys();
-    }
-    for (var key in object) {
-      if (isNumeric(key)) {
-        keys.push(Number(key));
-      } else if (Multiname.isPublicQualifiedName(key)) {
-        if (object[VM_BINDINGS] && object[VM_BINDINGS].indexOf(key) >= 0) {
-          continue;
-        }
-        keys.push(key.substr(Multiname.PUBLIC_QUALIFIED_NAME_PREFIX.length));
-      }
-    }
-    return keys;
-  }
-  defineReadOnlyProperty(global.Object.prototype, VM_NEXT_NAME_INDEX, function (index) {
-    if (index === 0) {
-      this[VM_ENUMERATION_KEYS] = getEnumerationKeys(this);
-    }
-    var keys = this[VM_ENUMERATION_KEYS];
-    while (index < keys.length) {
-      if (keys[index] !== VM_TOMBSTONE) {
-        return index + 1;
-      }
-      index++;
-    }
-    delete this[VM_ENUMERATION_KEYS];
-    return 0;
-  });
-  defineReadOnlyProperty(global.Object.prototype, VM_NEXT_NAME, function (index) {
-    var keys = this[VM_ENUMERATION_KEYS];
-    true;
-    return keys[index - 1];
-  });
   var originals = global[VM_NATIVE_BUILTIN_ORIGINALS] = createEmptyObject();
   VM_NATIVE_BUILTIN_SURROGATES.forEach(function (surrogate) {
     var object = surrogate.object;
     originals[object.name] = createEmptyObject();
     surrogate.methods.forEach(function (originalFunctionName) {
       var originalFunction = object.prototype[originalFunctionName];
       originals[object.name][originalFunctionName] = originalFunction;
       var overrideFunctionName = Multiname.getPublicQualifiedName(originalFunctionName);
@@ -28398,35 +26592,54 @@ function initializeGlobalObject(global) 
   defineNonEnumerableProperty(global.Object.prototype, 'asDefineProperty', asDefineProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asDefinePublicProperty', asDefinePublicProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asCallProperty', asCallProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asCallPublicProperty', asCallPublicProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asCallResolvedStringProperty', asCallResolvedStringProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asConstructProperty', asConstructProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asHasProperty', asHasProperty);
   defineNonEnumerableProperty(global.Object.prototype, 'asDeleteProperty', asDeleteProperty);
+  defineNonEnumerableProperty(global.Object.prototype, 'asNextName', asNextName);
+  defineNonEnumerableProperty(global.Object.prototype, 'asNextValue', asNextValue);
+  defineNonEnumerableProperty(global.Object.prototype, 'asNextNameIndex', asNextNameIndex);
+  defineNonEnumerableProperty(global.Object.prototype, 'asGetEnumerableKeys', asGetEnumerableKeys);
   [
     'Array',
     'Int8Array',
     'Uint8Array',
     'Uint8ClampedArray',
     'Int16Array',
     'Uint16Array',
     'Int32Array',
     'Uint32Array',
     'Float32Array',
     'Float64Array'
   ].forEach(function (name) {
     if (!(name in global)) {
-      console.error(name + ' was not found in globals');
+      print(name + ' was not found in globals');
       return;
     }
     defineNonEnumerableProperty(global[name].prototype, 'asGetNumericProperty', asGetNumericProperty);
     defineNonEnumerableProperty(global[name].prototype, 'asSetNumericProperty', asSetNumericProperty);
+    defineNonEnumerableProperty(global[name].prototype, 'asGetProperty', asGetPropertyLikelyNumeric);
+    defineNonEnumerableProperty(global[name].prototype, 'asSetProperty', asSetPropertyLikelyNumeric);
   });
+  Array.prototype.asGetProperty = function (namespaces, name, flags) {
+    if (typeof name === 'number') {
+      return this[name];
+    }
+    return asGetProperty.call(this, namespaces, name, flags);
+  };
+  Array.prototype.asSetProperty = function (namespaces, name, flags, value) {
+    if (typeof name === 'number') {
+      this[name] = value;
+      return;
+    }
+    return asSetProperty.call(this, namespaces, name, flags, value);
+  };
 }
 initializeGlobalObject(jsGlobal);
 function isNativePrototype(object) {
   return Object.prototype.hasOwnProperty.call(object, VM_NATIVE_PROTOTYPE_FLAG);
 }
 function asTypeOf(x) {
   if (x) {
     if (x.constructor === String) {
@@ -28447,51 +26660,66 @@ function publicizeProperties(object) {
     var k = keys[i];
     if (!Multiname.isPublicQualifiedName(k)) {
       var v = object[k];
       object[Multiname.getPublicQualifiedName(k)] = v;
       delete object[k];
     }
   }
 }
-function getSlot(object, index) {
+function asGetSlot(object, index) {
   return object[object[VM_SLOTS][index].name];
 }
-function setSlot(object, index, value) {
+function asSetSlot(object, index, value) {
   var binding = object[VM_SLOTS][index];
   if (binding.const) {
     return;
   }
   var name = binding.name;
   var type = binding.type;
   if (type && type.coerce) {
     object[name] = type.coerce(value);
   } else {
     object[name] = value;
   }
 }
-function nextName(object, index) {
-  return object[VM_NEXT_NAME](index);
-}
-function nextValue(object, index) {
-  return object.asGetProperty(undefined, object[VM_NEXT_NAME](index));
-}
-function hasNext2(object, index) {
-  if (object === null || object === undefined) {
+function asHasNext2(object, index) {
+  if (isNullOrUndefined(object)) {
     return {
       index: 0,
       object: null
     };
   }
   object = boxValue(object);
-  true;
-  true;
+  var nextIndex = object.asNextNameIndex(index);
+  if (nextIndex > 0) {
+    return {
+      index: nextIndex,
+      object: object
+    };
+  }
+  while (true) {
+    var object = Object.getPrototypeOf(object);
+    if (!object) {
+      return {
+        index: 0,
+        object: null
+      };
+    }
+    nextIndex = object.asNextNameIndex(0);
+    if (nextIndex > 0) {
+      return {
+        index: nextIndex,
+        object: object
+      };
+    }
+  }
   return {
-    index: object[VM_NEXT_NAME_INDEX](index),
-    object: object
+    index: 0,
+    object: null
   };
 }
 function getDescendants(object, mn) {
   if (!isXMLType(object)) {
     throw 'Not XML object in getDescendants';
   }
   return object.descendants(mn);
 }
@@ -29345,23 +27573,23 @@ function asCoerce(type, value) {
   }
 }
 function asCoerceString(x) {
   if (typeof x === 'string') {
     return x;
   } else if (x == undefined) {
     return null;
   }
-  return String(x);
+  return x + '';
 }
 function asCoerceInt(x) {
   return x | 0;
 }
 function asCoerceUint(x) {
-  return toUint(x);
+  return x >>> 0;
 }
 function asCoerceNumber(x) {
   return +x;
 }
 function asCoerceBoolean(x) {
   return !(!x);
 }
 function asCoerceObject(x) {
@@ -29764,22 +27992,39 @@ var TypedArrayVector = function () {
       this._checkFixed();
       this._slide(arguments.length);
       this.offset -= arguments.length;
       this.length += arguments.length;
       for (var i = 0; i < arguments.length; i++) {
         this.buffer[this.offset + i] = arguments[i];
       }
     };
+    vector.prototype.asGetEnumerableKeys = function () {
+      if (vector.prototype === this) {
+        return Object.prototype.asGetEnumerableKeys.call(this);
+      }
+      var keys = [];
+      for (var i = 0; i < this.length; i++) {
+        keys.push(i);
+      }
+      return keys;
+    };
+    vector.prototype.asHasProperty = function (namespaces, name, flags) {
+      if (vector.prototype === this || !isNumeric(name)) {
+        return Object.prototype.asHasProperty.call(this, namespaces, name, flags);
+      }
+      var index = toNumber(name);
+      return index >= 0 && index < this._length;
+    };
     Object.defineProperty(vector.prototype, 'length', {
       get: function () {
         return this._length;
       },
       set: function (length) {
-        length = toUint(length);
+        length = length >>> 0;
         if (length > this._length) {
           this._ensureCapacity(length);
           for (var i = this.offset + this._length, j = this.offset + length; i < j; i++) {
             this.buffer[i] = this.defaultValue;
           }
         }
         this._length = length;
       }
@@ -29791,19 +28036,29 @@ var TypedArrayVector = function () {
       var right = this.offset + index + deleteCount;
       var slice = this.buffer.subarray(right, right + this._length - index - deleteCount);
       this.buffer.set(slice, this.offset + index + insertCount);
       this._length += insertCount - deleteCount;
       for (var i = 0; i < insertCount; i++) {
         this.buffer[this.offset + index + i] = args.asGetNumericProperty(offset + i);
       }
     };
+    vector.prototype.asGetEnumerableKeys = function () {
+      if (vector.prototype === this) {
+        return Object.prototype.asGetEnumerableKeys.call(this);
+      }
+      var keys = [];
+      for (var i = 0; i < this._length; i++) {
+        keys.push(i);
+      }
+      return keys;
+    };
     return vector;
   }();
-var typedArrayVectorTemplate = 'var EXTRA_CAPACITY=4,INITIAL_CAPACITY=10;function vector(a,b){a|=0;this.fixed=!!b;this.buffer=new Int32Array(Math.max(INITIAL_CAPACITY,a+EXTRA_CAPACITY));this.offset=0;this._length=a;this.defaultValue=0}vector.callable=function(a){if(a instanceof vector)return a;var b=a.asGetProperty(void 0,"length");if(void 0!==b){for(var c=new vector(b,!1),d=0;d<b;d++)c.asSetNumericProperty(d,a.asGetPublicProperty(d));return c}unexpected()}; vector.prototype.internalToString=function(){for(var a="",b=this.offset,c=b+this._length,d=0;d<this.buffer.length;d++)d===b&&(a+="["),d===c&&(a+="]"),a+=this.buffer[d],d<this.buffer.length-1&&(a+=",");this.offset+this._length===this.buffer.length&&(a+="]");return a+": offset: "+this.offset+", length: "+this._length+", capacity: "+this.buffer.length};vector.prototype.toString=function(){for(var a="",b=0;b<this._length;b++)a+=this.buffer[this.offset+b],b<this._length-1&&(a+=",");return a}; vector.prototype._view=function(){return this.buffer.subarray(this.offset,this.offset+this._length)};vector.prototype._ensureCapacity=function(a){var b=this.offset+a;b<this.buffer.length||(a<=this.buffer.length?(b=this.buffer.length-a>>2,this.buffer.set(this._view(),b),this.offset=b):(a=3*this.buffer.length>>2,a<b&&(a=b),b=new Int32Array(a),b.set(this.buffer,0),this.buffer=b))};vector.prototype.concat=function(){notImplemented("TypedArrayVector.concat")}; vector.prototype.every=function(a,b){for(var c=0;c<this._length;c++)if(!a.call(b,this.asGetNumericProperty(c),c,this))return!1;return!0};vector.prototype.filter=function(a,b){for(var c=new vector,d=0;d<this._length;d++)a.call(b,this.asGetNumericProperty(d),d,this)&&c.push(this.asGetNumericProperty(d));return c};vector.prototype.forEach=function(a,b){for(var c=0;c<this._length;c++)a.call(b,this.asGetNumericProperty(c),c,this)};vector.prototype.join=function(a){notImplemented("TypedArrayVector.join")}; vector.prototype.indexOf=function(a,b){notImplemented("TypedArrayVector.indexOf")};vector.prototype.lastIndexOf=function(a,b){notImplemented("TypedArrayVector.lastIndexOf")};vector.prototype.map=function(a,b){notImplemented("TypedArrayVector.map")};vector.prototype.push=function(){this._ensureCapacity(this._length+arguments.length);for(var a=0;a<arguments.length;a++)this.buffer[this.offset+this._length++]=arguments[a]}; vector.prototype.pop=function(){this._checkFixed();if(0===this._length)return this.defaultValue;this._length--;return this.buffer[this.offset+this._length]};vector.prototype.reverse=function(){for(var a=this.offset,b=this.offset+this._length-1,c=this.buffer;a<b;){var d=c[a];c[a]=c[b];c[b]=d;a++;b--}};vector.CASEINSENSITIVE=1;vector.DESCENDING=2;vector.UNIQUESORT=4;vector.RETURNINDEXEDARRAY=8;vector.NUMERIC=16;function defaultCompareFunction(a,b){return String(a).localeCompare(String(b))} function compare(a,b,c,d){assertNotImplemented(!(c&vector.CASEINSENSITIVE),"CASEINSENSITIVE");assertNotImplemented(!(c&vector.UNIQUESORT),"UNIQUESORT");assertNotImplemented(!(c&vector.RETURNINDEXEDARRAY),"RETURNINDEXEDARRAY");var f=0;d||(d=defaultCompareFunction);c&vector.NUMERIC?(a=toNumber(a),b=toNumber(b),f=a<b?-1:a>b?1:0):f=d(a,b);c&vector.DESCENDING&&(f*=-1);return f} function _sort(a){for(var b=[],c=-1,d=0,f=a.length-1,e,g,h,k;;)if(100>=f-d){for(g=d+1;g<=f;g++){h=a[g];for(e=g-1;e>=d&&a[e]>h;)a[e+1]=a[e--];a[e+1]=h}if(-1==c)break;f=b[c--];d=b[c--]}else{k=d+f>>1;e=d+1;g=f;h=a[k];a[k]=a[e];a[e]=h;a[d]>a[f]&&(h=a[d],a[d]=a[f],a[f]=h);a[e]>a[f]&&(h=a[e],a[e]=a[f],a[f]=h);a[d]>a[e]&&(h=a[d],a[d]=a[e],a[e]=h);for(k=a[e];;){do e++;while(a[e]<k);do g--;while(a[g]>k);if(g<e)break;h=a[e];a[e]=a[g];a[g]=h}a[d+1]=a[g];a[g]=k;f-e+1>=g-d?(b[++c]=e,b[++c]=f,f=g-1):(b[++c]=d, b[++c]=g-1,d=e)}return a}vector.prototype._sortNumeric=function(a){_sort(this._view());a&&this.reverse()};vector.prototype.sort=function(){if(0===arguments.length)return Array.prototype.sort.call(this._view());var a,b=0;arguments[0]instanceof Function?a=arguments[0]:isNumber(arguments[0])&&(b=arguments[0]);isNumber(arguments[1])&&(b=arguments[1]);if(b&TypedArrayVector.NUMERIC)return this._sortNumeric(b&vector.DESCENDING);Array.prototype.sort.call(this._view(),function(c,d){return compare(c,d,b,a)})}; vector.prototype.asGetNumericProperty=function(a){return this.buffer[this.offset+a]};vector.prototype.asSetNumericProperty=function(a,b){a===this._length&&(this._ensureCapacity(this._length+1),this._length++);this.buffer[this.offset+a]=b};vector.prototype.shift=function(){this._checkFixed();if(0!==this._length)return this._length--,this.buffer[this.offset++]}; vector.prototype._checkFixed=function(){if(this.fixed){var a=Errors.VectorFixedError;throwErrorFromVM(AVM2.currentDomain(),"RangeError",getErrorMessage(a.code),a.code)}};vector.prototype._slide=function(a){this.buffer.set(this._view(),this.offset+a);this.offset+=a};vector.prototype.unshift=function(){this._checkFixed();this._slide(arguments.length);this.offset-=arguments.length;this.length+=arguments.length;for(var a=0;a<arguments.length;a++)this.buffer[this.offset+a]=arguments[a]}; Object.defineProperty(vector.prototype,"length",{get:function(){return this._length},set:function(a){a=toUint(a);if(a>this._length){this._ensureCapacity(a);for(var b=this.offset+this._length,c=this.offset+a;b<c;b++)this.buffer[b]=this.defaultValue}this._length=a}}); vector.prototype._spliceHelper=function(a,b,c,d,f){b=clamp(b,0,d.length-f);c=clamp(c,0,this._length-a);this._ensureCapacity(this._length-c+b);var e=this.offset+a+c,e=this.buffer.subarray(e,e+this._length-a-c);this.buffer.set(e,this.offset+a+b);this._length+=b-c;for(c=0;c<b;c++)this.buffer[this.offset+a+c]=d.asGetNumericProperty(f+c)};';
+var typedArrayVectorTemplate = 'var EXTRA_CAPACITY=4,INITIAL_CAPACITY=10;function vector(a,b){a|=0;this.fixed=!!b;this.buffer=new Int32Array(Math.max(INITIAL_CAPACITY,a+EXTRA_CAPACITY));this.offset=0;this._length=a;this.defaultValue=0}vector.callable=function(a){if(a instanceof vector)return a;var b=a.asGetProperty(void 0,"length");if(void 0!==b){for(var c=new vector(b,!1),d=0;d<b;d++)c.asSetNumericProperty(d,a.asGetPublicProperty(d));return c}unexpected()}; vector.prototype.internalToString=function(){for(var a="",b=this.offset,c=b+this._length,d=0;d<this.buffer.length;d++)d===b&&(a+="["),d===c&&(a+="]"),a+=this.buffer[d],d<this.buffer.length-1&&(a+=",");this.offset+this._length===this.buffer.length&&(a+="]");return a+": offset: "+this.offset+", length: "+this._length+", capacity: "+this.buffer.length};vector.prototype.toString=function(){for(var a="",b=0;b<this._length;b++)a+=this.buffer[this.offset+b],b<this._length-1&&(a+=",");return a}; vector.prototype._view=function(){return this.buffer.subarray(this.offset,this.offset+this._length)};vector.prototype._ensureCapacity=function(a){var b=this.offset+a;b<this.buffer.length||(a<=this.buffer.length?(b=this.buffer.length-a>>2,this.buffer.set(this._view(),b),this.offset=b):(a=3*this.buffer.length>>2,a<b&&(a=b),b=new Int32Array(a),b.set(this.buffer,0),this.buffer=b))};vector.prototype.concat=function(){notImplemented("TypedArrayVector.concat")}; vector.prototype.every=function(a,b){for(var c=0;c<this._length;c++)if(!a.call(b,this.asGetNumericProperty(c),c,this))return!1;return!0};vector.prototype.filter=function(a,b){for(var c=new vector,d=0;d<this._length;d++)a.call(b,this.asGetNumericProperty(d),d,this)&&c.push(this.asGetNumericProperty(d));return c};vector.prototype.forEach=function(a,b){for(var c=0;c<this._length;c++)a.call(b,this.asGetNumericProperty(c),c,this)};vector.prototype.join=function(a){notImplemented("TypedArrayVector.join")}; vector.prototype.indexOf=function(a,b){notImplemented("TypedArrayVector.indexOf")};vector.prototype.lastIndexOf=function(a,b){notImplemented("TypedArrayVector.lastIndexOf")};vector.prototype.map=function(a,b){notImplemented("TypedArrayVector.map")};vector.prototype.push=function(){this._ensureCapacity(this._length+arguments.length);for(var a=0;a<arguments.length;a++)this.buffer[this.offset+this._length++]=arguments[a]}; vector.prototype.pop=function(){this._checkFixed();if(0===this._length)return this.defaultValue;this._length--;return this.buffer[this.offset+this._length]};vector.prototype.reverse=function(){for(var a=this.offset,b=this.offset+this._length-1,c=this.buffer;a<b;){var d=c[a];c[a]=c[b];c[b]=d;a++;b--}};vector.CASEINSENSITIVE=1;vector.DESCENDING=2;vector.UNIQUESORT=4;vector.RETURNINDEXEDARRAY=8;vector.NUMERIC=16;function defaultCompareFunction(a,b){return String(a).localeCompare(String(b))} function compare(a,b,c,d){assertNotImplemented(!(c&vector.CASEINSENSITIVE),"CASEINSENSITIVE");assertNotImplemented(!(c&vector.UNIQUESORT),"UNIQUESORT");assertNotImplemented(!(c&vector.RETURNINDEXEDARRAY),"RETURNINDEXEDARRAY");var f=0;d||(d=defaultCompareFunction);c&vector.NUMERIC?(a=toNumber(a),b=toNumber(b),f=a<b?-1:a>b?1:0):f=d(a,b);c&vector.DESCENDING&&(f*=-1);return f} function _sort(a){for(var b=[],c=-1,d=0,f=a.length-1,e,g,h,k;;)if(100>=f-d){for(g=d+1;g<=f;g++){h=a[g];for(e=g-1;e>=d&&a[e]>h;)a[e+1]=a[e--];a[e+1]=h}if(-1==c)break;f=b[c--];d=b[c--]}else{k=d+f>>1;e=d+1;g=f;h=a[k];a[k]=a[e];a[e]=h;a[d]>a[f]&&(h=a[d],a[d]=a[f],a[f]=h);a[e]>a[f]&&(h=a[e],a[e]=a[f],a[f]=h);a[d]>a[e]&&(h=a[d],a[d]=a[e],a[e]=h);for(k=a[e];;){do e++;while(a[e]<k);do g--;while(a[g]>k);if(g<e)break;h=a[e];a[e]=a[g];a[g]=h}a[d+1]=a[g];a[g]=k;f-e+1>=g-d?(b[++c]=e,b[++c]=f,f=g-1):(b[++c]=d, b[++c]=g-1,d=e)}return a}vector.prototype._sortNumeric=function(a){_sort(this._view());a&&this.reverse()};vector.prototype.sort=function(){if(0===arguments.length)return Array.prototype.sort.call(this._view());var a,b=0;arguments[0]instanceof Function?a=arguments[0]:isNumber(arguments[0])&&(b=arguments[0]);isNumber(arguments[1])&&(b=arguments[1]);if(b&TypedArrayVector.NUMERIC)return this._sortNumeric(b&vector.DESCENDING);Array.prototype.sort.call(this._view(),function(c,d){return compare(c,d,b,a)})}; vector.prototype.asGetNumericProperty=function(a){return this.buffer[this.offset+a]};vector.prototype.asSetNumericProperty=function(a,b){a===this._length&&(this._ensureCapacity(this._length+1),this._length++);this.buffer[this.offset+a]=b};vector.prototype.shift=function(){this._checkFixed();if(0!==this._length)return this._length--,this.buffer[this.offset++]}; vector.prototype._checkFixed=function(){if(this.fixed){var a=Errors.VectorFixedError;throwErrorFromVM(AVM2.currentDomain(),"RangeError",getErrorMessage(a.code),a.code)}};vector.prototype._slide=function(a){this.buffer.set(this._view(),this.offset+a);this.offset+=a};vector.prototype.unshift=function(){this._checkFixed();this._slide(arguments.length);this.offset-=arguments.length;this.length+=arguments.length;for(var a=0;a<arguments.length;a++)this.buffer[this.offset+a]=arguments[a]}; vector.prototype.asGetEnumerableKeys=function(){if(vector.prototype===this)return Object.prototype.asGetEnumerableKeys.call(this);for(var a=[],b=0;b<this.length;b++)a.push(b);return a};vector.prototype.asHasProperty=function(a,b,c){if(vector.prototype===this||!isNumeric(b))return Object.prototype.asHasProperty.call(this,a,b,c);a=toNumber(b);return 0<=a&&a<this._length}; Object.defineProperty(vector.prototype,"length",{get:function(){return this._length},set:function(a){a>>>=0;if(a>this._length){this._ensureCapacity(a);for(var b=this.offset+this._length,c=this.offset+a;b<c;b++)this.buffer[b]=this.defaultValue}this._length=a}}); vector.prototype._spliceHelper=function(a,b,c,d,f){b=clamp(b,0,d.length-f);c=clamp(c,0,this._length-a);this._ensureCapacity(this._length-c+b);var e=this.offset+a+c,e=this.buffer.subarray(e,e+this._length-a-c);this.buffer.set(e,this.offset+a+b);this._length+=b-c;for(c=0;c<b;c++)this.buffer[this.offset+a+c]=d.asGetNumericProperty(f+c)}; vector.prototype.asGetEnumerableKeys=function(){if(vector.prototype===this)return Object.prototype.asGetEnumerableKeys.call(this);for(var a=[],b=0;b<this._length;b++)a.push(b);return a};';
 var Int32Vector = new Function(typedArrayVectorTemplate.replace(/Int32Array/g, 'Int32Array') + ' return vector;')();
 var Uint32Vector = new Function(typedArrayVectorTemplate.replace(/Int32Array/g, 'Uint32Array') + ' return vector;')();
 var Float64Vector = new Function(typedArrayVectorTemplate.replace(/Int32Array/g, 'Float64Array') + ' return vector;')();
 var GenericVector = function () {
     function vector(length, fixed, type) {
       length = length | 0;
       this.fixed = !(!fixed);
       this.buffer = new Array(length);
@@ -29969,17 +28224,17 @@ var GenericVector = function () {
       }
       this.buffer.unshift.apply(this.buffer, items);
     };
     Object.defineProperty(vector.prototype, 'length', {
       get: function () {
         return this.buffer.length;
       },
       set: function (length) {
-        length = toUint(length);
+        length = length >>> 0;
         if (length > this.buffer.length) {
           for (var i = this.buffer.length; i < length; i++) {
             this.buffer[i] = this.defaultValue;
           }
         } else {
           this.buffer.length = length;
         }
         true;
@@ -29992,25 +28247,87 @@ var GenericVector = function () {
       for (var i = 0; i < insertCount; i++) {
         items.push(this._coerce(args.asGetNumericProperty(offset + i)));
       }
       this.buffer.splice.apply(this.buffer, [
         index,
         deleteCount
       ].concat(items));
     };
-    vector.prototype.getEnumerationKeys = function () {
+    vector.prototype.asGetEnumerableKeys = function () {
+      if (vector.prototype === this) {
+        return Object.prototype.asGetEnumerableKeys.call(this);
+      }
       var keys = [];
       for (var i = 0; i < this.buffer.length; i++) {
         keys.push(i);
       }
       return keys;
     };
+    vector.prototype.asHasProperty = function (namespaces, name, flags) {
+      if (vector.prototype === this || !isNumeric(name)) {
+        return Object.prototype.asHasProperty.call(this, namespaces, name, flags);
+      }
+      var index = toNumber(name);
+      return index >= 0 && index < this.buffer.length;
+    };
     return vector;
   }();
+Int32Vector.prototype.asGetProperty = function (namespaces, name, flags) {
+  if (typeof name === 'number') {
+    return this.asGetNumericProperty(name);
+  }
+  return asGetProperty.call(this, namespaces, name, flags);
+};
+Int32Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
+  if (typeof name === 'number') {
+    this.asSetNumericProperty(name, value);
+    return;
+  }
+  return asSetProperty.call(this, namespaces, name, flags, value);
+};
+Uint32Vector.prototype.asGetProperty = function (namespaces, name, flags) {
+  if (typeof name === 'number') {
+    return this.asGetNumericProperty(name);
+  }
+  return asGetProperty.call(this, namespaces, name, flags);
+};
+Uint32Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
+  if (typeof name === 'number') {
+    this.asSetNumericProperty(name, value);
+    return;
+  }
+  return asSetProperty.call(this, namespaces, name, flags, value);
+};
+Float64Vector.prototype.asGetProperty = function (namespaces, name, flags) {
+  if (typeof name === 'number') {
+    return this.asGetNumericProperty(name);
+  }
+  return asGetProperty.call(this, namespaces, name, flags);
+};
+Float64Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
+  if (typeof name === 'number') {
+    this.asSetNumericProperty(name, value);
+    return;
+  }
+  return asSetProperty.call(this, namespaces, name, flags, value);
+};
+GenericVector.prototype.asGetProperty = function (namespaces, name, flags) {
+  if (typeof name === 'number') {
+    return this.asGetNumericProperty(name);
+  }
+  return asGetProperty.call(this, namespaces, name, flags);
+};
+GenericVector.prototype.asSetProperty = function (namespaces, name, flags, value) {
+  if (typeof name === 'number') {
+    this.asSetNumericProperty(name, value);
+    return;
+  }
+  return asSetProperty.call(this, namespaces, name, flags, value);
+};
 var XMLClass, XMLListClass, QNameClass, ASXML, XML, ASXMLList, XMLList;
 var isXMLType, isXMLName, XMLParser;
 (function () {
   function XMLEncoder(ancestorNamespaces, indentLevel, prettyPrinting) {
     var indent = '\n  ';
     function visit(node, encode) {
       if (node.isXML) {
         switch (node.kind) {
@@ -30669,17 +28986,20 @@ var isXMLType, isXMLName, XMLParser;
         this.children.forEach(function (v) {
           if (v.kind === 'element') {
             result = false;
           }
         });
       }
       return result;
     };
-    Xp.getEnumerationKeys = function getEnumerationKeys() {
+    Xp.asGetEnumerableKeys = function asGetEnumerableKeys() {
+      if (Xp === this) {
+        return Object.prototype.asGetEnumerableKeys.call(this);
+      }
       var keys = [];
       this.children.forEach(function (v, i) {
         keys.push(v.name);
       });
       return keys;
     };
     function setAttribute(node, name, value) {
       if (node.nodeType === Node.DOCUMENT_NODE) {
@@ -31526,17 +29846,20 @@ var isXMLType, isXMLName, XMLParser;
         if (base.isXMLList && base.length() > 1) {
           return null;
         }
         base.setProperty(targetProperty, '');
         target = base.getProperty(targetProperty);
       }
       return target;
     };
-    XLp.getEnumerationKeys = function getEnumerationKeys() {
+    XLp.asGetEnumerableKeys = function asGetEnumerableKeys() {
+      if (XLp === this) {
+        return Object.prototype.asGetEnumerableKeys.call(this);
+      }
       var keys = [];
       this.children.forEach(function (v, i) {
         keys.push(i);
       });
       return keys;
     };
     c.native = {
       instance: {
@@ -32610,17 +30933,20 @@ function DictionaryClass(domain, scope, 
     }
     this.map.delete(Object(name));
     var i;
     if (!this.weakKeys && (i = this.keys.indexOf(name)) >= 0) {
       this.keys.splice(i, 1);
     }
     return true;
   });
-  defineNonEnumerableProperty(prototype, 'getEnumerationKeys', function () {
+  defineNonEnumerableProperty(prototype, 'asGetEnumerableKeys', function () {
+    if (prototype === this) {
+      return Object.prototype.asGetEnumerableKeys.call(this);
+    }
     var primitiveMapKeys = [];
     for (var k in this.primitiveMap) {
       primitiveMapKeys.push(k);
     }
     return primitiveMapKeys.concat(this.keys);
   });
   c.native = {
     instance: {
@@ -33065,20 +31391,20 @@ var natives = function () {
         return Object(value) instanceof Number;
       };
       c.isInstance = function (value) {
         return Object(value) instanceof Number;
       };
       return c;
     }
     function Int(x) {
-      return toNumber(x) | 0;
+      return x | 0;
     }
     function boxedInt(x) {
-      return Object(Int(x));
+      return Object(x | 0);
     }
     function intClass(runtime, scope, instanceConstructor, baseClass) {
       var c = new Class('int', boxedInt, C(Int));
       c.extendBuiltin(baseClass);
       c.defaultValue = 0;
       c.coerce = Int;
       c.isInstanceOf = function (value) {
         return false;
@@ -33087,20 +31413,20 @@ var natives = function () {
         if (value instanceof Number) {
           value = value.valueOf();
         }
         return (value | 0) === value;
       };
       return c;
     }
     function Uint(x) {
-      return toNumber(x) >>> 0;
+      return x >>> 0;
     }
     function boxedUint(x) {
-      return Object(Uint(x));
+      return Object(x >>> 0);
     }
     function uintClass(runtime, scope, instanceConstructor, baseClass) {
       var c = new Class('uint', boxedUint, C(Uint));
       c.extend(baseClass);
       c.defaultValue = 0;
       c.isInstanceOf = function (value) {
         return false;
       };
@@ -33244,45 +31570,44 @@ var natives = function () {
           } else if (typeof uriValue === 'object') {
             prefix = uriValue.prefix;
             if (uriValue instanceof ShumwayNamespace) {
               uri = uriValue.originalURI;
             } else if (uriValue instanceof QName) {
               uri = uriValue.uri;
             }
           } else {
-            uri = toString(uriValue);
+            uri = uriValue + '';
             if (uri === '') {
               prefix = '';
             } else {
               prefix = undefined;
             }
           }
         } else {
           if (typeof uriValue === 'object' && uriValue instanceof QName && uriValue.uri !== null) {
             uri = uriValue.uri;
           } else {
-            uri = toString(uriValue);
+            uri = uriValue + '';
           }
           if (uri === '') {
-            if (prefixValue === undefined || toString(prefixValue) === '') {
+            if (prefixValue === undefined || prefixValue + '' === '') {
               prefix = '';
             } else {
               throw 'type error';
             }
           } else if (prefixValue === undefined || prefixValue === '') {
             prefix = undefined;
           } else if (false && !isXMLName(prefixValue)) {
             prefix = undefined;
           } else {
-            prefix = toString(prefixValue);
-          }
-        }
-        var ns = ShumwayNamespace.createNamespace(uri, prefix);
-        return ns;
+            prefix = prefixValue + '';
+          }
+        }
+        return ShumwayNamespace.createNamespace(uri, prefix);
       };
       var c = new Class('Namespace', ASNamespace, C(ASNamespace));
       c.extendNative(baseClass, ShumwayNamespace);
       var Np = ShumwayNamespace.prototype;
       c.native = {
         instance: {
           prefix: {
             get: Np.getPrefix
@@ -33290,27 +31615,54 @@ var natives = function () {
           uri: {
             get: Np.getURI
           }
         }
       };
       return c;
     }
     function JSONClass(runtime, scope, instanceConstructor, baseClass) {
+      function transformJSValueToAS(value) {
+        if (typeof value !== 'object') {
+          return value;
+        }
+        var keys = Object.keys(value);
+        var result = value instanceof Array ? [] : {};
+        for (var i = 0; i < keys.length; i++) {
+          result.asSetPublicProperty(keys[i], transformJSValueToAS(value[keys[i]]));
+        }
+        return result;
+      }
+      function transformASValueToJS(value) {
+        if (typeof value !== 'object') {
+          return value;
+        }
+        var keys = Object.keys(value);
+        var result = value instanceof Array ? [] : {};
+        for (var i = 0; i < keys.length; i++) {
+          var key = keys[i];
+          var jsKey = key;
+          if (!isNumeric(key)) {
+            jsKey = fromResolvedName(key);
+          }
+          result[jsKey] = transformASValueToJS(value[key]);
+        }
+        return result;
+      }
       function ASJSON() {
       }
       var c = new Class('JSON', ASJSON, C(ASJSON));
       c.extend(baseClass);
       c.native = {
         static: {
           parseCore: function parseCore(text) {
-            return JSON.parse(text);
+            return transformJSValueToAS(JSON.parse(text));
           },
           stringifySpecializedToString: function stringifySpecializedToString(value, replacerArray, replacerFunction, gap) {
-            return JSON.stringify(value, replacerFunction, gap);
+            return JSON.stringify(transformASValueToJS(value), replacerFunction, gap);
           }
         }
       };
       return c;
     }
     function CapabilitiesClass(runtime, scope, instanceConstructor, baseClass) {
       function Capabilities() {
       }
@@ -34782,19 +33134,16 @@ function traceStatistics(writer, abc) {
     definedProperties: definedProperties,
     libraryClasses: libraryClassCounter.counts,
     librarySuperClasses: librarySuperClassCounter.counts,
     libraryMethods: libraryMethodCounter.counts,
     libraryProperties: libraryProperties.counts,
     operations: opCounter.counts
   }, null, 2));
 }
-var interpreterOptions = systemOptions.register(new OptionSet('Interpreter Options'));
-var traceInterpreter = interpreterOptions.register(new Option('ti', 'traceInterpreter', 'number', 0, 'trace interpreter execution'));
-var interpretedBytecode = 0;
 var Interpreter = new (function () {
     function Interpreter() {
     }
     function popName(stack, mn) {
       if (Multiname.isRuntime(mn)) {
         var namespaces = mn.namespaces, name = mn.name;
         var flags = mn.flags & Multiname.ATTRIBUTE;
         if (Multiname.isRuntimeName(mn)) {
@@ -34835,17 +33184,16 @@ var Interpreter = new (function () {
         Counter.count('Interpret Method');
         var abc = method.abc;
         var ints = abc.constantPool.ints;
         var uints = abc.constantPool.uints;
         var doubles = abc.constantPool.doubles;
         var strings = abc.constantPool.strings;
         var methods = abc.methods;
         var multinames = abc.constantPool.multinames;
-        var runtime = abc.runtime;
         var domain = abc.domain;
         var exceptions = method.exceptions;
         var locals = [
             $this
           ];
         var stack = [], scopeStack = new ScopeStack(savedScope);
         var parameterCount = method.parameters.length;
         var argCount = methodArgs.length;
@@ -34862,30 +33210,30 @@ var Interpreter = new (function () {
           }
           locals.push(value);
         }
         if (method.needsRest()) {
           locals.push(sliceArguments(methodArgs, parameterCount));
         } else if (method.needsArguments()) {
           locals.push(sliceArguments(methodArgs, 0));
         }
-        var obj, type, index, multiname, res, a, b, args = [], name, tmpMultiname = Multiname.TEMPORARY, property;
+        var obj, index, multiname, res, a, b, args = [], name;
+        var tmpMultiname = Multiname.TEMPORARY;
         var bytecodes = method.analysis.bytecodes;
         interpret:
           for (var pc = 0, end = bytecodes.length; pc < end;) {
-            interpretedBytecode++;
             try {
               var bc = bytecodes[pc];
               var op = bc.op;
               switch (op | 0) {
               case 3:
                 throw stack.pop();
               case 4:
                 name = popName(stack, multinames[bc.index]);
-                stack.push(getSuper(savedScope, stack.pop(), name));
+                stack[stack.length - 1] = getSuper(savedScope, stack[stack.length - 1], name);
                 break;
               case 5:
                 value = stack.pop();
                 name = popName(stack, multinames[bc.index]);
                 setSuper(savedScope, stack.pop(), name, value);
                 break;
               case 8:
                 locals[bc.index] = undefined;
@@ -34969,26 +33317,24 @@ var Interpreter = new (function () {
               case 28:
                 scopeStack.push(boxValue(stack.pop()), true);
                 break;
               case 29:
                 scopeStack.pop();
                 break;
               case 30:
                 index = stack.pop();
-                obj = stack.pop();
-                stack.push(nextName(obj, index));
+                stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextName(index);
                 break;
               case 35:
                 index = stack.pop();
-                obj = stack.pop();
-                stack.push(nextValue(obj, index));
+                stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextValue(index);
                 break;
               case 50:
-                res = hasNext2(locals[bc.object], locals[bc.index]);
+                res = asHasNext2(locals[bc.object], locals[bc.index]);
                 locals[bc.object] = res.object;
                 locals[bc.index] = res.index;
                 stack.push(!(!res.index));
                 break;
               case 32:
                 stack.push(null);
                 break;
               case 33:
@@ -35018,58 +33364,62 @@ var Interpreter = new (function () {
                 break;
               case 40:
                 stack.push(NaN);
                 break;
               case 41:
                 stack.pop();
                 break;
               case 42:
-                stack.push(stack.top());
+                stack.push(stack[stack.length - 1]);
                 break;
               case 43:
-                stack.push(stack.pop(), stack.pop());
+                obj = stack[stack.length - 1];
+                stack[stack.length - 1] = stack[stack.length - 2];
+                stack[stack.length - 2] = obj;
                 break;
               case 48:
                 scopeStack.push(boxValue(stack.pop()));
                 break;
               case 64:
                 stack.push(createFunction(methods[bc.index], scopeStack.topScope(), true));
                 break;
               case 65:
                 popManyInto(stack, bc.argCount, args);
                 obj = stack.pop();
-                stack.push(stack.pop().apply(obj, args));
+                stack[stack.length - 1] = stack[stack.length - 1].apply(obj, args);
                 break;
               case 66:
                 popManyInto(stack, bc.argCount, args);
-                stack.push(construct(stack.pop(), args));
+                stack[stack.length - 1] = construct(stack[stack.length - 1], args);
                 break;
               case 69:
                 popManyInto(stack, bc.argCount, args);
                 name = popName(stack, multinames[bc.index]);
-                obj = stack.pop();
-                stack.push(getSuper(savedScope, obj, name).apply(obj, args));
+                obj = stack[stack.length - 1];
+                stack[stack.length - 1] = getSuper(savedScope, obj, name).apply(obj, args);
                 break;
               case 71:
                 return;
               case 72:
                 if (method.returnType) {
                   return asCoerceByMultiname(domain, method.returnType, stack.pop());
                 }
                 return stack.pop();
               case 73:
                 popManyInto(stack, bc.argCount, args);
                 obj = stack.pop();
                 savedScope.object.baseClass.instanceConstructorNoInitialize.apply(obj, args);
                 break;
               case 74:
                 popManyInto(stack, bc.argCount, args);
                 popNameInto(stack, multinames[bc.index], tmpMultiname);
-                stack.push(boxValue(stack.pop()).asConstructProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags, args));
+                obj = boxValue(stack[stack.length - 1]);
+                obj = obj.asConstructProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags, args);
+                stack[stack.length - 1] = obj;
                 break;
               case 75:
                 notImplemented();
                 break;
               case 76:
               case 70:
               case 79:
                 popManyInto(stack, bc.argCount, args);
@@ -35082,17 +33432,17 @@ var Interpreter = new (function () {
               case 78:
                 popManyInto(stack, bc.argCount, args);
                 name = popName(stack, multinames[bc.index]);
                 obj = stack.pop();
                 getSuper(savedScope, obj, name).apply(obj, args);
                 break;
               case 83:
                 popManyInto(stack, bc.argCount, args);
-                stack.push(applyType(domain, stack.pop(), args));
+                stack[stack.length - 1] = applyType(domain, stack[stack.length - 1], args);
                 break;
               case 85:
                 obj = {};
                 for (var i = 0; i < bc.argCount; i++) {
                   value = stack.pop();
                   obj[Multiname.getPublicQualifiedName(stack.pop())] = value;
                 }
                 stack.push(obj);
@@ -35103,17 +33453,17 @@ var Interpreter = new (function () {
                 obj.push.apply(obj, args);
                 stack.push(obj);
                 break;
               case 87:
                 true;
                 stack.push(createActivation(method));
                 break;
               case 88:
-                stack.push(createClass(abc.classes[bc.index], stack.pop(), scopeStack.topScope()));
+                stack[stack.length - 1] = createClass(abc.classes[bc.index], stack[stack.length - 1], scopeStack.topScope());
                 break;
               case 89:
                 name = popName(stack, multinames[bc.index]);
                 stack.push(getDescendants(stack.pop(), name));
                 break;
               case 90:
                 true;
                 stack.push(exceptions[bc.index].scopeObject);
@@ -35142,229 +33492,177 @@ var Interpreter = new (function () {
               case 100:
                 stack.push(savedScope.global.object);
                 break;
               case 101:
                 stack.push(scopeStack.get(bc.index));
                 break;
               case 102:
                 popNameInto(stack, multinames[bc.index], tmpMultiname);
-                stack.push(boxValue(stack.pop()).asGetProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags));
+                stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asGetProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags);
                 break;
               case 106:
                 popNameInto(stack, multinames[bc.index], tmpMultiname);
-                stack.push(boxValue(stack.pop()).asDeleteProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags));
+                stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asDeleteProperty(tmpMultiname.namespaces, tmpMultiname.name, tmpMultiname.flags);
                 break;
               case 108:
-                stack.push(getSlot(stack.pop(), bc.index));
+                stack[stack.length - 1] = asGetSlot(stack[stack.length - 1], bc.index);
                 break;
               case 109:
                 value = stack.pop();
                 obj = stack.pop();
-                setSlot(obj, bc.index, value);
+                asSetSlot(obj, bc.index, value);
                 break;
               case 112:
-                stack.push(String(stack.pop()));
+                stack[stack.length - 1] = stack[stack.length - 1] + '';
                 break;
               case 131:
               case 115:
-                stack.push(asCoerceInt(stack.pop()));
+                stack[stack.length - 1] |= 0;
                 break;
               case 136:
               case 116:
-                stack.push(asCoerceUint(stack.pop()));
+                stack[stack.length - 1] >>>= 0;
                 break;
               case 132:
               case 117:
-                stack.push(asCoerceNumber(stack.pop()));
+                stack[stack.length - 1] = +stack[stack.length - 1];
                 break;
               case 129:
               case 118:
-                stack.push(asCoerceBoolean(stack.pop()));
+                stack[stack.length - 1] = !(!stack[stack.length - 1]);
                 break;
               case 120:
-                stack.push(checkFilter(stack.pop()));
+                stack[stack.length - 1] = checkFilter(stack[stack.length - 1]);
                 break;
               case 128:
-                stack.push(asCoerce(domain.getType(multinames[bc.index]), stack.pop()));
+                stack[stack.length - 1] = asCoerce(domain.getType(multinames[bc.index]), stack[stack.length - 1]);
                 break;
               case 130:
                 break;
               case 133:
-                stack.push(asCoerceString(stack.pop()));
+                stack[stack.length - 1] = asCoerceString(stack[stack.length - 1]);
                 break;
               case 135:
-                stack.push(asAsType(stack.pop(), stack.pop()));
+                stack[stack.length - 2] = asAsType(stack.pop(), stack[stack.length - 1]);
                 break;
               case 137:
-                obj = stack.pop();
-                stack.push(obj == undefined ? null : obj);
+                obj = stack[stack.length - 1];
+                stack[stack.length - 1] = obj == undefined ? null : obj;
                 break;
               case 144:
-                stack.push(-stack.pop());
+                stack[stack.length - 1] = -stack[stack.length - 1];
                 break;
               case 145:
-                a = stack.pop();
-                stack.push(a + 1);
+                ++stack[stack.length - 1];
                 break;
               case 146:
                 ++locals[bc.index];
                 break;
               case 147:
-                stack.push(1);
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a - b);
+                --stack[stack.length - 1];
                 break;
               case 148:
                 --locals[bc.index];
                 break;
               case 149:
-                stack.push(asTypeOf(stack.pop()));
+                stack[stack.length - 1] = asTypeOf(stack[stack.length - 1]);
                 break;
               case 150:
-                stack.push(!stack.pop());
+                stack[stack.length - 1] = !stack[stack.length - 1];
                 break;
               case 151:
-                stack.push(~stack.pop());
+                stack[stack.length - 1] = ~stack[stack.length - 1];
                 break;
               case 160:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(asAdd(a, b));
+                stack[stack.length - 2] = asAdd(stack[stack.length - 2], stack.pop());
                 break;
               case 161:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a - b);
+                stack[stack.length - 2] -= stack.pop();
                 break;
               case 162:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a * b);
+                stack[stack.length - 2] *= stack.pop();
                 break;
               case 163:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a / b);
+                stack[stack.length - 2] /= stack.pop();
                 break;
               case 164:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a % b);
+                stack[stack.length - 2] %= stack.pop();
                 break;
               case 165:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a << b);
+                stack[stack.length - 2] <<= stack.pop();
                 break;
               case 166:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a >> b);
+                stack[stack.length - 2] >>= stack.pop();
                 break;
               case 167:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a >>> b);
+                stack[stack.length - 2] >>>= stack.pop();
                 break;
               case 168:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a & b);
+                stack[stack.length - 2] &= stack.pop();
                 break;
               case 169:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a | b);
+                stack[stack.length - 2] |= stack.pop();
                 break;
               case 170:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a ^ b);
+                stack[stack.length - 2] ^= stack.pop();
                 break;
               case 171:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a == b);
+                stack[stack.length - 2] = stack[stack.length - 2] == stack.pop();
                 break;
               case 172:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a === b);
+                stack[stack.length - 2] = stack[stack.length - 2] === stack.pop();
                 break;
               case 173:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a < b);
+                stack[stack.length - 2] = stack[stack.length - 2] < stack.pop();
                 break;
               case 174:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a <= b);
+                stack[stack.length - 2] = stack[stack.length - 2] <= stack.pop();
                 break;
               case 175:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a > b);
+                stack[stack.length - 2] = stack[stack.length - 2] > stack.pop();
                 break;
               case 176:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a >= b);
+                stack[stack.length - 2] = stack[stack.length - 2] >= stack.pop();
                 break;
               case 177:
-                stack.push(asIsInstanceOf(stack.pop(), stack.pop()));
+                stack[stack.length - 2] = asIsInstanceOf(stack.pop(), stack[stack.length - 1]);
                 break;
               case 178:
-                stack.push(asIsType(domain.getType(multinames[bc.index]), stack.pop()));
+                stack[stack.length - 1] = asIsType(domain.getType(multinames[bc.index]), stack[stack.length - 1]);
                 break;
               case 179:
-                stack.push(asIsType(stack.pop(), stack.pop()));
+                stack[stack.length - 2] = asIsType(stack.pop(), stack[stack.length - 1]);
                 break;
               case 180:
-                stack.push(boxValue(stack.pop()).asHasProperty(null, stack.pop()));
+                stack[stack.length - 2] = boxValue(stack.pop()).asHasProperty(null, stack[stack.length - 1]);
                 break;
               case 192:
-                stack.push(stack.pop() | 0);
-                stack.push(1);
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a + b);
+                stack[stack.length - 1] = (stack[stack.length - 1] | 0) + 1;
                 break;
               case 193:
-                stack.push(stack.pop() | 0);
-                stack.push(1);
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a - b);
+                stack[stack.length - 1] = (stack[stack.length - 1] | 0) - 1;
                 break;
               case 194:
                 locals[bc.index] = (locals[bc.index] | 0) + 1;
                 break;
               case 195:
                 locals[bc.index] = (locals[bc.index] | 0) - 1;
                 break;
               case 196:
-                stack.push(~(stack.pop() | 0));
+                stack[stack.length - 1] = ~stack[stack.length - 1];
                 break;
               case 197:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a + b | 0);
+                stack[stack.length - 2] = stack[stack.length - 2] + stack.pop() | 0;
                 break;
               case 198:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a - b | 0);
+                stack[stack.length - 2] = stack[stack.length - 2] - stack.pop() | 0;
                 break;
               case 199:
-                b = stack.pop();
-                a = stack.pop();
-                stack.push(a * b | 0);
+                stack[stack.length - 2] = stack[stack.length - 2] * stack.pop() | 0;
                 break;
               case 208:
               case 209:
               case 210:
               case 211:
                 stack.push(locals[op - OP_getlocal0]);
                 break;
               case 212:
@@ -38964,16 +37262,19 @@ var Promise = function PromiseClosure() 
         subpromises[i].fulfill(value);
       }
       delete subject.subpromises;
     }
     function propagateRejected(subject, reason) {
       subject.subpromisesReason = reason;
       var subpromises = subject.subpromises;
       if (!subpromises) {
+        if (!true) {
+          console.warn(reason);
+        }
         return;
       }
       for (var i = 0; i < subpromises.length; i++) {
         subpromises[i].reject(reason);
       }
       delete subject.subpromises;
     }
     function performCall(callback, arg, subject) {
@@ -39182,16 +37483,22 @@ QuadTree.prototype._subdivide = function
   this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, level);
 };
 var EXTERNAL_INTERFACE_FEATURE = 1;
 var CLIPBOARD_FEATURE = 2;
 var SHAREDOBJECT_FEATURE = 3;
 var VIDEO_FEATURE = 4;
 var SOUND_FEATURE = 5;
 var NETCONNECTION_FEATURE = 6;
+if (!this.performance) {
+  this.performance = {};
+}
+if (!this.performance.now) {
+  this.performance.now = Date.now;
+}
 {
   var BitmapDefinition = function () {
       function setBitmapData(value) {
         if (this._bitmapData) {
           this._bitmapData._changeNotificationTarget = null;
         }
         this._bitmapData = value;
         if (this._bitmapData) {
@@ -39218,37 +37525,52 @@ var NETCONNECTION_FEATURE = 6;
       return {
         __class__: 'flash.display.Bitmap',
         draw: function (ctx, ratio, colorTransform) {
           if (!this._bitmapData) {
             return;
           }
           ctx.save();
           if (this._pixelSnapping === 'auto' || this._pixelSnapping === 'always') {
-            var transform = ctx.currentTransform;
+            var transform = this._getConcatenatedTransform(true);
             var EPSILON = 0.001;
             if (Math.abs(Math.abs(transform.a) - 1) <= EPSILON && Math.abs(Math.abs(transform.d) - 1) <= EPSILON && Math.abs(transform.b) <= EPSILON && Math.abs(transform.c) <= EPSILON) {
-              ctx.setTransform(transform.a < 0 ? -1 : 1, 0, 0, transform.d < 0 ? -1 : 1, transform.e | 0, transform.f | 0);
+              ctx.setTransform(transform.a < 0 ? -1 : 1, 0, 0, transform.d < 0 ? -1 : 1, transform.tx / 20 | 0, transform.ty / 20 | 0);
             }
           }
           colorTransform.setAlpha(ctx, true);
+          ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = this._smoothing;
           ctx.drawImage(this._bitmapData._drawable, 0, 0);
+          ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false;
           ctx.restore();
           traceRenderer.value && frameWriter.writeLn('Bitmap.draw() snapping: ' + this._pixelSnapping + ', dimensions: ' + this._bitmapData._drawable.width + ' x ' + this._bitmapData._drawable.height);
           FrameCounter.count('Bitmap.draw()');
         },
         initialize: function () {
         },
         __glue__: {
           native: {
             static: {},
             instance: {
               ctor: function (bitmapData, pixelSnapping, smoothing) {
-                this._pixelSnapping = pixelSnapping;
-                this._smoothing = smoothing;
+                if (pixelSnapping === 'never' || pixelSnapping === 'always') {
+                  this._pixelSnapping = pixelSnapping;
+                } else {
+                  this._pixelSnapping = 'auto';
+                }
+                this._smoothing = !(!smoothing);
+                if (!bitmapData && this.symbol) {
+                  var symbol = this.symbol;
+                  bitmapData = new flash.display.BitmapData(symbol.width, symbol.height);
+                  bitmapData._ctx.imageSmoothingEnabled = this._smoothing;
+                  bitmapData._ctx.mozImageSmoothingEnabled = this._smoothing;
+                  bitmapData._ctx.drawImage(symbol.img, 0, 0);
+                  bitmapData._ctx.imageSmoothingEnabled = false;
+                  bitmapData._ctx.mozImageSmoothingEnabled = false;
+                }
                 setBitmapData.call(this, bitmapData || null);
               },
               pixelSnapping: {
                 get: function pixelSnapping() {
                   return this._pixelSnapping;
                 },
                 set: function pixelSnapping(value) {
                   this._pixelSnapping = value;
@@ -39297,28 +37619,28 @@ var BitmapDataDefinition = function () {
           if (this._drawable === null)
             throw ArgumentError();
         },
         ctor: function (width, height, transparent, backgroundColor) {
           if (this._img) {
             width = this._img.naturalWidth || this._img.width;
             height = this._img.naturalHeight || this._img.height;
           } else if (isNaN(width + height) || width <= 0 || height <= 0) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.ArgumentError);
           }
           this._transparent = transparent === undefined ? true : !(!transparent);
           this._backgroundColor = backgroundColor === undefined ? 4294967295 : backgroundColor;
           if (!this._transparent) {
             this._backgroundColor |= 4278190080;
           }
           if (this._skipCopyToCanvas) {
             this._drawable = this._img;
           } else {
             var canvas = document.createElement('canvas');
-            this._ctx = canvas.getContext('kanvas-2d');
+            this._ctx = canvas.getContext('2d');
             canvas.width = width | 0;
             canvas.height = height | 0;
             this._drawable = canvas;
             if (!this._transparent || !this._img && this._backgroundColor) {
               this.fillRect(new flash.geom.Rectangle(0, 0, width | 0, height | 0), this._backgroundColor);
             }
             if (this._img) {
               this._ctx.drawImage(this._img, 0, 0);
@@ -39328,32 +37650,35 @@ var BitmapDataDefinition = function () {
         dispose: function () {
           this._ctx = null;
           this._drawable.width = 0;
           this._drawable.height = 0;
           this._drawable = null;
         },
         draw: function (source, matrix, colorTransform, blendMode, clipRect, smoothing) {
           this._checkCanvas();
-          this._ctx.save();
-          this._ctx.beginPath();
+          var ctx = this._ctx;
+          ctx.save();
+          ctx.beginPath();
           if (clipRect && clipRect.width > 0 && clipRect.height > 0) {
-            this._ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-            this._ctx.clip();
+            ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
+            ctx.clip();
           }
           if (matrix) {
-            this._ctx.transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
-          }
-          this._ctx.globalCompositeOperation = getBlendModeName(blendMode);
+            ctx.transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
+          }
+          ctx.globalCompositeOperation = getBlendModeName(blendMode);
+          ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = !(!smoothing);
           if (flash.display.BitmapData.class.isInstanceOf(source)) {
-            this._ctx.drawImage(source._drawable, 0, 0);
-          } else {
-            new RenderVisitor(source, this._ctx, null, true).startFragment();
-          }
-          this._ctx.restore();
+            ctx.drawImage(source._drawable, 0, 0);
+          } else {
+            new RenderVisitor(source, ctx, null, true).startFragment();
+          }
+          ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false;
+          ctx.restore();
           this._invalidate();
         },
         fillRect: function (rect, color) {
           this._checkCanvas();
           if (!this._transparent) {
             color |= 4278190080;
           }
           var ctx = this._ctx;
@@ -39548,17 +37873,16 @@ var DisplayObjectDefinition = function (
             c: 0,
             d: 1,
             tx: 0,
             ty: 0,
             invalid: true
           };
           this._current3DTransform = null;
           this._cxform = null;
-          this._depth = null;
           this._graphics = null;
           this._filters = [];
           this._loader = null;
           this._mouseChildren = true;
           this._mouseOver = false;
           this._mouseX = 0;
           this._mouseY = 0;
           this._name = null;
@@ -39576,16 +37900,17 @@ var DisplayObjectDefinition = function (
           this._wasCachedAsBitmap = false;
           this._destroyed = false;
           this._maskedObject = null;
           this._scrollRect = null;
           this._invalid = false;
           this._region = null;
           this._level = -1;
           this._index = -1;
+          this._depth = -1;
           blendModes = [
             blendModeClass.NORMAL,
             blendModeClass.NORMAL,
             blendModeClass.LAYER,
             blendModeClass.MULTIPLY,
             blendModeClass.SCREEN,
             blendModeClass.LIGHTEN,
             blendModeClass.DARKEN,
@@ -39602,23 +37927,23 @@ var DisplayObjectDefinition = function (
           var s = this.symbol;
           if (s) {
             this._animated = s.animated || false;
             this._bbox = s.bbox || null;
             this._blendMode = this._resolveBlendMode(s.blendMode);
             this._children = s.children || [];
             this._clipDepth = s.clipDepth || null;
             this._cxform = s.cxform || null;
-            this._depth = s.depth || null;
             this._loader = s.loader || null;
             this._name = s.name || null;
             this._owned = s.owned || false;
             this._parent = s.parent || null;
             this._level = isNaN(s.level) ? -1 : s.level;
             this._index = isNaN(s.index) ? -1 : s.index;
+            this._depth = isNaN(s.depth) ? -1 : s.depth;
             this._root = s.root || null;
             this._stage = s.stage || null;
             var scale9Grid = s.scale9Grid;
             if (scale9Grid) {
               this._scale9Grid = new flash.geom.Rectangle(scale9Grid.left, scale9Grid.top, scale9Grid.right - scale9Grid.left, scale9Grid.bottom - scale9Grid.top);
             }
             var matrix = s.currentTransform;
             if (matrix) {
@@ -39678,52 +38003,81 @@ var DisplayObjectDefinition = function (
           this._removeEventListenerImpl(type, listener, useCapture);
           if (type in broadcastedEvents && !this._listeners[type]) {
             avm2.systemDomain.onMessage.unregister(type, this._onBroadcastMessage);
           }
         },
         _resolveBlendMode: function (blendModeNumeric) {
           return blendModes[blendModeNumeric] || flash.display.BlendMode.class.NORMAL;
         },
-        _getConcatenatedTransform: function () {
-          if (!this._concatenatedTransform.invalid) {
-            return this._concatenatedTransform;
-          }
-          var stack = [
-              this
-            ];
-          var m;
-          var currentNode = this._parent;
-          while (currentNode) {
-            if (currentNode._concatenatedTransform.invalid) {
-              stack.push(currentNode);
-            }
-            currentNode = currentNode._parent;
-          }
-          while (stack.length) {
-            var node = stack.pop();
-            m = node._concatenatedTransform;
-            var m2 = node._currentTransform;
-            if (node._parent) {
-              var m3 = node._parent._concatenatedTransform;
-              m.a = m2.a * m3.a + m2.b * m3.c;
-              m.b = m2.a * m3.b + m2.b * m3.d;
-              m.c = m2.c * m3.a + m2.d * m3.c;
-              m.d = m2.d * m3.d + m2.c * m3.b;
-              m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c;
-              m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b;
-            } else {
+        _getConcatenatedTransform: function (toDeviceSpace) {
+          var stage = this._stage;
+          if (this === this._stage) {
+            return toDeviceSpace ? this._concatenatedTransform : this._currentTransform;
+          }
+          var m, m2;
+          if (this._concatenatedTransform.invalid) {
+            if (this._parent === stage) {
+              m = this._concatenatedTransform;
+              m2 = this._currentTransform;
               m.a = m2.a;
               m.b = m2.b;
               m.c = m2.c;
               m.d = m2.d;
               m.tx = m2.tx;
               m.ty = m2.ty;
-            }
-            m.invalid = false;
+            } else {
+              var stack = [
+                  this
+                ];
+              var currentNode = this._parent;
+              while (currentNode !== stage) {
+                if (currentNode._concatenatedTransform.invalid) {
+                  stack.push(currentNode);
+                }
+                currentNode = currentNode._parent;
+              }
+              while (stack.length) {
+                var node = stack.pop();
+                m = node._concatenatedTransform;
+                m2 = node._currentTransform;
+                if (node._parent) {
+                  if (node._parent !== this._stage) {
+                    var m3 = node._parent._concatenatedTransform;
+                    m.a = m2.a * m3.a + m2.b * m3.c;
+                    m.b = m2.a * m3.b + m2.b * m3.d;
+                    m.c = m2.c * m3.a + m2.d * m3.c;
+                    m.d = m2.d * m3.d + m2.c * m3.b;
+                    m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c;
+                    m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b;
+                  }
+                } else {
+                  m.a = m2.a;
+                  m.b = m2.b;
+                  m.c = m2.c;
+                  m.d = m2.d;
+                  m.tx = m2.tx;
+                  m.ty = m2.ty;
+                }
+                m.invalid = false;
+              }
+            }
+          } else {
+            m = this._concatenatedTransform;
+          }
+          if (toDeviceSpace && stage) {
+            m2 = stage._concatenatedTransform;
+            return {
+              a: m.a * m2.a,
+              b: m.b * m2.d,
+              c: m.c * m2.a,
+              d: m.d * m2.d,
+              tx: m.tx * m2.a + m2.tx,
+              ty: m.ty * m2.d + m2.ty
+            };
           }
           return m;
         },
         _applyCurrentTransform: function (targetCoordSpace, point1, pointN) {
           var m;
           if (targetCoordSpace && targetCoordSpace !== this._parent) {
             m = this._getConcatenatedTransform();
           } else {
@@ -40385,24 +38739,24 @@ var DisplayObjectContainerDefinition = f
         get textSnapshot() {
           notImplemented();
         },
         addChild: function (child) {
           return this.addChildAt(child, this._children.length);
         },
         addChildAt: function (child, index) {
           if (child === this) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.CantAddSelfError);
           }
           if (child._parent === this) {
             return this.setChildIndex(child, index);
           }
           var children = this._children;
           if (index < 0 || index > children.length) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           if (child._index > -1) {
             var LoaderClass = avm2.systemDomain.getClass('flash.display.Loader');
             if (LoaderClass.isInstanceOf(child._parent)) {
               def.removeChild.call(child._parent, child);
             } else {
               child._parent.removeChild(child);
             }
@@ -40429,17 +38783,17 @@ var DisplayObjectContainerDefinition = f
           notImplemented();
         },
         contains: function (child) {
           return child._parent === this;
         },
         getChildAt: function (index) {
           var children = this._children;
           if (index < 0 || index > children.length) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           var child = children[index];
           if (!flash.display.DisplayObject.class.isInstanceOf(child)) {
             return null;
           }
           return child;
         },
         getChildByName: function (name) {
@@ -40449,33 +38803,33 @@ var DisplayObjectContainerDefinition = f
             if (child.name === name) {
               return this.getChildAt(i);
             }
           }
           return null;
         },
         getChildIndex: function (child) {
           if (child._parent !== this) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.NotAChildError);
           }
           return this._sparse ? this._children.indexOf(child) : child._index;
         },
         getObjectsUnderPoint: function (pt) {
           notImplemented();
         },
         removeChild: function (child) {
           if (child._parent !== this) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.NotAChildError);
           }
           return this.removeChildAt(this.getChildIndex(child));
         },
         removeChildAt: function (index) {
           var children = this._children;
           if (index < 0 || index >= children.length) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           var child = children[index];
           child._dispatchEvent('removed');
           if (this._stage) {
             this._stage._removeFromStage(child);
           }
           if (!this._sparse) {
             for (var i = children.length; i && i > index; i--) {
@@ -40487,25 +38841,25 @@ var DisplayObjectContainerDefinition = f
           child._parent = null;
           child._index = -1;
           child._invalidateTransform();
           this._invalidateBounds();
           return child;
         },
         setChildIndex: function (child, index) {
           if (child._parent !== this) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.NotAChildError);
           }
           var currentIndex = this.getChildIndex(child);
           if (currentIndex === index) {
             return;
           }
           var children = this._children;
           if (index < 0 || index > children.length) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           children.splice(currentIndex, 1);
           children.splice(index, 0, child);
           if (!this._sparse) {
             var i = currentIndex < index ? currentIndex : index;
             while (i < children.length) {
               children[i]._index = i++;
             }
@@ -40513,33 +38867,33 @@ var DisplayObjectContainerDefinition = f
           child._owned = false;
           child._invalidate();
           return child;
         },
         removeChildren: function (begin, end) {
           var children = this._children;
           var numChildren = children.length;
           if (begin < 0 || begin > numChildren || end < 0 || end < begin || end > numChildren) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           for (var i = begin; i < end; i++) {
             this.removeChildAt(i);
           }
         },
         swapChildren: function (child1, child2) {
           if (child1._parent !== this || child2._parent !== this) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.NotAChildError);
           }
           this.swapChildrenAt(this.getChildIndex(child1), this.getChildIndex(child2));
         },
         swapChildrenAt: function (index1, index2) {
           var children = this._children;
           var numChildren = children.length;
           if (index1 < 0 || index1 > numChildren || index2 < 0 || index2 > numChildren) {
-            throw RangeError();
+            throwError('RangeError', Errors.ParamRangeError);
           }
           var child1 = children[index1];
           var child2 = children[index2];
           children[index1] = child2;
           children[index2] = child1;
           child1._index = index2;
           child2._index = index1;
           child1._owned = false;
@@ -40664,22 +39018,24 @@ var GraphicsDefinition = function () {
           if (alpha === undefined)
             alpha = 1;
           this.beginPath();
           this._currentPath.fillStyle = alpha ? {
             style: rgbIntAlphaToStr(color, alpha)
           } : null;
         },
         beginGradientFill: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
+          var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
           this.beginPath();
-          this._currentPath.fillStyle = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
+          this._currentPath.fillStyle = style;
         },
         beginBitmapFill: function (bitmap, matrix, repeat, smooth) {
           this.beginPath();
-          this._currentPath.fillStyle = createPatternStyle(bitmap, matrix, repeat, smooth);
+          repeat = repeat !== false;
+          this._currentPath.fillStyle = createPatternStyle(bitmap, matrix, repeat, !(!smooth));
         },
         clear: function () {
           this._invalidate();
           this._paths = [];
           this._currentPath = null;
           this.beginPath();
         },
         copyFrom: function (sourceGraphics) {
@@ -40707,85 +39063,114 @@ var GraphicsDefinition = function () {
           this._invalidate();
           this.beginPath();
           this._currentPath.fillRule = winding || GRAPHICS_PATH_WINDING_EVEN_ODD;
           this._currentPath.commands = commands;
           this._currentPath.data = data;
         },
         drawRect: function (x, y, w, h) {
           if (isNaN(w + h))
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.InvalidParamError);
           this._invalidate();
           this._currentPath.rect(x * 20 | 0, y * 20 | 0, w * 20 | 0, h * 20 | 0);
         },
         drawRoundRect: function (x, y, w, h, ellipseWidth, ellipseHeight) {
           if (isNaN(w + h + ellipseWidth) || ellipseHeight !== undefined && isNaN(ellipseHeight)) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.InvalidParamError);
           }
           this._invalidate();
-          var x2 = (x + w) * 20 | 0;
-          var y2 = (y + h) * 20 | 0;
+          if (ellipseHeight === undefined) {
+            ellipseHeight = ellipseWidth;
+          }
           x = x * 20 | 0;
           y = y * 20 | 0;
+          w = w * 20 | 0;
+          h = h * 20 | 0;
+          if (!ellipseHeight || !ellipseWidth) {
+            this._currentPath.rect(x, y, w, h);
+            return;
+          }
           var radiusX = ellipseWidth / 2 * 20 | 0;
           var radiusY = ellipseHeight / 2 * 20 | 0;
-          if (w === ellipseWidth && h === ellipseHeight) {
-            if (ellipseWidth === ellipseHeight)
+          var hw = w / 2 | 0;
+          var hh = h / 2 | 0;
+          if (radiusX > hw) {
+            radiusX = hw;
+          }
+          if (radiusY > hh) {
+            radiusY = hh;
+          }
+          if (hw === radiusX && hh === radiusY) {
+            if (radiusX === radiusY)
               this._currentPath.circle(x + radiusX, y + radiusY, radiusX);
             else
-              this._currentPath.ellipse(x + radiusX, y + radiusY, radiusX, radiusY, 0, Math.PI * 2);
-            return;
-          }
-          this._currentPath.moveTo(x2, y2 - radiusY);
-          this._currentPath.drawRoundCorner(x2, y2, x2 - radiusX, y2, radiusX, radiusY);
-          this._currentPath.lineTo(x + radiusX, y2);
-          this._currentPath.drawRoundCorner(x, y2, x, y2 - radiusY, radiusX, radiusY);
-          this._currentPath.lineTo(x, y + radiusY);
-          this._currentPath.drawRoundCorner(x, y, x + radiusX, y, radiusX, radiusY);
-          this._currentPath.lineTo(x2 - radiusX, y);
-          this._currentPath.drawRoundCorner(x2, y, x2, y + radiusY, radiusX, radiusY);
-          this._currentPath.lineTo(x2, y2 - radiusY);
+              this._currentPath.ellipse(x + radiusX, y + radiusY, radiusX, radiusY);
+            return;
+          }
+          var right = x + w;
+          var bottom = y + h;
+          var xlw = x + radiusX;
+          var xrw = right - radiusX;
+          var ytw = y + radiusY;
+          var ybw = bottom - radiusY;
+          this._currentPath.moveTo(right, ybw);
+          this._currentPath.curveTo(right, bottom, xrw, bottom);
+          this._currentPath.lineTo(xlw, bottom);
+          this._currentPath.curveTo(x, bottom, x, ybw);
+          this._currentPath.lineTo(x, ytw);
+          this._currentPath.curveTo(x, y, xlw, y);
+          this._currentPath.lineTo(xrw, y);
+          this._currentPath.curveTo(right, y, right, ytw);
+          this._currentPath.lineTo(right, ybw);
         },
         drawRoundRectComplex: function (x, y, w, h, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius) {
           if (isNaN(w + h + topLeftRadius + topRightRadius + bottomLeftRadius + bottomRightRadius)) {
-            throw ArgumentError();
+            throwError('ArgumentError', Errors.InvalidParamError);
           }
           this._invalidate();
-          var x2 = (x + w) * 20 | 0;
-          var y2 = (y + h) * 20 | 0;
           x = x * 20 | 0;
           y = y * 20 | 0;
+          w = w * 20 | 0;
+          h = h * 20 | 0;
+          if (!topLeftRadius && !topRightRadius && !bottomLeftRadius && !bottomRightRadius) {
+            this._currentPath.rect(x, y, w, h);
+            return;
+          }
           topLeftRadius = topLeftRadius * 20 | 0;
           topRightRadius = topRightRadius * 20 | 0;
           bottomLeftRadius = bottomLeftRadius * 20 | 0;
           bottomRightRadius = bottomRightRadius * 20 | 0;
-          this._currentPath.moveTo(x2, y2 - bottomRightRadius);
-          this._currentPath.drawRoundCorner(x2, y2, x2 - bottomRightRadius, y2, bottomRightRadius);
-          this._currentPath.lineTo(x + bottomLeftRadius, y2);
-          this._currentPath.drawRoundCorner(x, y2, x, y2 - bottomLeftRadius, bottomLeftRadius);
+          var right = x + w;
+          var bottom = y + h;
+          var xtl = x + topLeftRadius;
+          this._currentPath.moveTo(right, bottom - bottomRightRadius);
+          this._currentPath.curveTo(right, bottom, right - bottomRightRadius, bottom);
+          this._currentPath.lineTo(x + bottomLeftRadius, bottom);
+          this._currentPath.curveTo(x, bottom, x, bottom - bottomLeftRadius);
           this._currentPath.lineTo(x, y + topLeftRadius);
-          this._currentPath.drawRoundCorner(x, y, x + topLeftRadius, y, topLeftRadius);
-          this._currentPath.lineTo(x2 - topRightRadius, y);
-          this._currentPath.drawRoundCorner(x2, y, x2, y + topRightRadius, topRightRadius);
-          this._currentPath.lineTo(x2, y2 - bottomRightRadius);
+          this._currentPath.curveTo(x, y, xtl, y);
+          this._currentPath.lineTo(right - topRightRadius, y);
+          this._currentPath.curveTo(right, y, right, y + topRightRadius);
+          this._currentPath.lineTo(right, bottom - bottomRightRadius);
         },
         drawTriangles: function (vertices, indices, uvtData, culling) {
           notImplemented('Graphics#drawTriangles');
         },
         endFill: function () {
           this.beginPath();
           this._currentPath.fillStyle = null;
         },
         lineBitmapStyle: function (bitmap, matrix, repeat, smooth) {
           this.beginPath();
           this._currentPath.lineStyle = createPatternStyle(bitmap, matrix, repeat, smooth);
         },
         lineGradientStyle: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
+          var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
           this.beginPath();
-          this._currentPath.lineStyle = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
+          this._currentPath.lineStyle = style;
         },
         lineStyle: function (width, color, alpha, pxHinting, scale, cap, joint, mlimit) {
           this.beginPath();
           if (width) {
             if (alpha === undefined)
               alpha = 1;
             if (mlimit === undefined)
               mlimit = 3;
@@ -40819,22 +39204,24 @@ var GraphicsDefinition = function () {
           }
           if (this.bbox) {
             return this.bbox;
           }
           var subpaths = this._paths;
           var xMins = [], yMins = [], xMaxs = [], yMaxs = [];
           for (var i = 0, n = subpaths.length; i < n; i++) {
             var path = subpaths[i];
-            var b = path.getBounds(true);
-            if (b) {
-              xMins.push(b.xMin);
-              yMins.push(b.yMin);
-              xMaxs.push(b.xMax);
-              yMaxs.push(b.yMax);
+            if (path.commands.length) {
+              var b = path.getBounds(true);
+              if (b) {
+                xMins.push(b.xMin);
+                yMins.push(b.yMin);
+                xMaxs.push(b.xMax);
+                yMaxs.push(b.yMax);
+              }
             }
           }
           if (xMins.length === 0) {
             return 0;
           }
           var xMin = Math.min.apply(Math, xMins);
           var yMin = Math.min.apply(Math, yMins);
           var xMax = Math.max.apply(Math, xMaxs);
@@ -40892,34 +39279,38 @@ function createPatternStyle(bitmap, matr
       b: 0,
       c: 0,
       d: 1,
       e: 0,
       f: 0
     };
   return {
     style: pattern,
-    transform: transform
+    transform: transform,
+    smooth: smooth
   };
 }
 function createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
+  type === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'type');
+  colors === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'colors');
+  if (!(type === 'linear' || type === 'radial')) {
+    throwError('ArgumentError', Errors.InvalidEnumError, 'type');
+  }
   var colorStops = [];
   for (var i = 0, n = colors.length; i < n; i++) {
     colorStops.push({
       ratio: ratios[i] / 255,
       color: rgbIntAlphaToStr(colors[i], alphas[i])
     });
   }
   var gradientConstructor;
   if (type === 'linear') {
     gradientConstructor = buildLinearGradientFactory(colorStops);
-  } else if (type == 'radial') {
+  } else {
     gradientConstructor = buildRadialGradientFactory(focalPos || 0, colorStops);
-  } else {
-    throw ArgumentError();
   }
   var scale = 819.2;
   var transform = matrix ? {
       a: scale * matrix.a,
       b: scale * matrix.b,
       c: scale * matrix.c,
       d: scale * matrix.d,
       e: matrix.tx,
@@ -41882,16 +40273,18 @@ var LoaderDefinition = function () {
                 }, 200);
                 promiseQueue.push(fontPromise);
               }
             }
             className = 'flash.text.Font';
             props.name = symbol.name;
             props.uniqueName = symbol.uniqueName;
             props.charset = symbol.charset;
+            props.bold = symbol.bold;
+            props.italic = symbol.italic;
             props.metrics = symbol.metrics;
             this._registerFont(className, props);
             break;
           case 'image':
             var img = new Image();
             var imgPromise = new Promise();
             img.onload = function () {
               if (symbol.mask) {
@@ -42054,16 +40447,19 @@ var LoaderDefinition = function () {
           });
           loader._dictionary[0] = documentPromise;
           loader._lastPromise = documentPromise;
           loader._vmPromise = vmPromise;
           loader._isAvm2Enabled = info.fileAttributes.doAbc;
           this._setup();
         },
         _load: function (request, checkPolicyFile, applicationDomain, securityDomain, deblockingFilter) {
+          if (!isWorker && flash.net.URLRequest.class.isInstanceOf(request)) {
+            this._contentLoaderInfo._url = request._url;
+          }
           if (!isWorker && WORKERS_ENABLED) {
             var loader = this;
             var worker = loader._worker = new Worker(SHUMWAY_ROOT + LOADER_PATH);
             worker.onmessage = function (evt) {
               loader._commitData(evt.data);
             };
             if (flash.net.URLRequest.class.isInstanceOf(request)) {
               var session = FileLoadingService.createSession();
@@ -42141,17 +40537,17 @@ var LoaderDefinition = function () {
           _getJPEGLoaderContextdeblockingfilter: function (context) {
             return 0;
           },
           _load: def._load,
           _loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) {
             def._load(bytes.a);
           },
           _unload: function _unload(halt, gc) {
-            notImplemented('Loader._unload');
+            somewhatImplemented('Loader._unload, do we even need to do anything here?');
           },
           _close: function _close() {
             somewhatImplemented('Loader._close');
           },
           _getUncaughtErrorEvents: function _getUncaughtErrorEvents() {
             somewhatImplemented('Loader._getUncaughtErrorEvents');
             return this._uncaughtErrorEvents;
           },
@@ -42235,19 +40631,16 @@ var LoaderInfoDefinition = function () {
             },
             applicationDomain: {
               get: function applicationDomain() {
                 return new flash.system.ApplicationDomain(avm2.applicationDomain);
               }
             },
             swfVersion: {
               get: function swfVersion() {
-                if (!this._swfVersion) {
-                  throw Error();
-                }
                 return this._swfVersion;
               }
             },
             actionScriptVersion: {
               get: function actionScriptVersion() {
                 return this._actionScriptVersion;
               }
             },
@@ -42409,16 +40802,17 @@ var MovieClipDefinition = function () {
           this._onExecuteFrame = function onExecuteFrame() {
             self._removeEventListener('executeFrame', onExecuteFrame);
             self._allowFrameNavigation = false;
             self._callFrame(self._currentFrame);
             self._allowFrameNavigation = true;
             if (self._playHead !== self._currentFrame) {
               self._gotoFrame(self._playHead, true);
             }
+            self._postConstructChildren();
           };
           this._addEventListener('executeFrame', this._onExecuteFrame);
           if (this._totalFrames <= 1) {
             return this;
           }
           this._onAdvanceFrame = function onAdvanceFrame() {
             var frameNum = self._playHead + 1;
             if (frameNum > self._totalFrames) {
@@ -42444,34 +40838,41 @@ var MovieClipDefinition = function () {
           this.play();
         },
         _declareChildren: function declareChildren(nextFrameNum) {
           var currentFrame = this._currentFrame;
           if (nextFrameNum === currentFrame) {
             return;
           }
           var timeline = this._timeline;
-          var currentDisplayList = timeline[currentFrame - 1];
           var nextDisplayList = timeline[nextFrameNum - 1];
-          if (nextDisplayList === currentDisplayList) {
-            return;
-          }
+          if (nextDisplayList === timeline[currentFrame - 1]) {
+            return;
+          }
+          var prevDisplayListItem = null;
+          var currentDisplayListItem = this._currentDisplayList;
           var children = this._children;
-          var depths = nextFrameNum > currentFrame ? nextDisplayList.depths : currentDisplayList.depths;
-          var depthMap = this._depthMap;
+          var depths = nextDisplayList.depths;
           var index = children.length;
           var i = depths.length;
           while (i--) {
-            var depth = depths[i];
-            var currentCmd = currentDisplayList[depth];
+            var depth = depths[i], depthInt = depth | 0;
+            while (currentDisplayListItem && currentDisplayListItem.depth > depthInt) {
+              prevDisplayListItem = currentDisplayListItem;
+              currentDisplayListItem = currentDisplayListItem.next;
+            }
+            var currentChild = null;
+            if (currentDisplayListItem && currentDisplayListItem.depth === depthInt) {
+              currentChild = currentDisplayListItem.obj;
+              if (currentChild && currentChild._owned) {
+                index = this.getChildIndex(currentChild);
+              }
+            }
+            var currentCmd = currentDisplayListItem && currentDisplayListItem.depth === depthInt ? currentDisplayListItem.cmd : null;
             var nextCmd = nextDisplayList[depth];
-            var currentChild = depthMap[depth];
-            if (currentChild && currentChild._owned) {
-              index = this.getChildIndex(currentChild);
-            }
             if (!nextCmd || nextCmd === currentCmd) {
               continue;
             }
             if (currentCmd && currentChild && currentChild._animated && nextCmd.symbolId === currentCmd.symbolId && nextCmd.ratio === currentCmd.ratio) {
               currentChild._invalidate();
               currentChild._invalidateBounds();
               if (nextCmd.hasMatrix) {
                 var m = nextCmd.matrix;
@@ -42502,38 +40903,69 @@ var MovieClipDefinition = function () {
               if (nextCmd.hasName) {
                 currentChild.name = nextCmd.name;
               }
               if (nextCmd.blend) {
                 currentChild.blendMode = this._resolveBlendMode(nextCmd.blendMode);
               }
               continue;
             }
-            this._addTimelineChild(nextCmd, index);
+            var newDisplayListItem = this._addTimelineChild(nextCmd, index);
+            newDisplayListItem.next = currentDisplayListItem;
+            if (prevDisplayListItem) {
+              prevDisplayListItem.next = newDisplayListItem;
+            } else {
+              this._currentDisplayList = newDisplayListItem;
+            }
+            prevDisplayListItem = newDisplayListItem;
           }
         },
         _destructChildren: function destructChildren(nextFrameNum) {
           var currentFrame = this._currentFrame;
           if (nextFrameNum === currentFrame) {
             return;
           }
           var timeline = this._timeline;
-          var currentDisplayList = timeline[currentFrame - 1];
           var nextDisplayList = timeline[nextFrameNum - 1];
-          if (nextDisplayList === currentDisplayList) {
-            return;
-          }
-          var depths = nextFrameNum > currentFrame ? currentDisplayList.depths : nextDisplayList.depths;
-          for (var i = 0; i < depths.length; i++) {
-            var depth = depths[i];
-            var currentCmd = currentDisplayList[depth];
+          if (nextDisplayList === timeline[currentFrame - 1]) {
+            return;
+          }
+          var prevDisplayListItem = null;
+          var currentDisplayListItem = this._currentDisplayList;
+          var toRemove = null;
+          while (currentDisplayListItem) {
+            var depth = currentDisplayListItem.depth;
+            var currentCmd = currentDisplayListItem.cmd;
             var nextCmd = nextDisplayList[depth];
-            if (currentCmd && (!nextCmd || nextCmd.symbolId !== currentCmd.symbolId || nextCmd.ratio !== currentCmd.ratio)) {
-              this._removeTimelineChild(currentCmd);
-            }
+            if (!nextCmd || nextCmd.symbolId !== currentCmd.symbolId || nextCmd.ratio !== currentCmd.ratio) {
+              var nextDisplayListItem = currentDisplayListItem.next;
+              if (prevDisplayListItem) {
+                prevDisplayListItem.next = nextDisplayListItem;
+              } else {
+                this._currentDisplayList = nextDisplayListItem;
+              }
+              currentDisplayListItem.next = toRemove;
+              toRemove = currentDisplayListItem;
+              currentDisplayListItem = nextDisplayListItem;
+            } else {
+              prevDisplayListItem = currentDisplayListItem;
+              currentDisplayListItem = currentDisplayListItem.next;
+            }
+          }
+          while (toRemove) {
+            var child = toRemove.obj;
+            if (child) {
+              this._sparse = true;
+              this.removeChild(child);
+              child.destroy();
+              if (child._isPlaying) {
+                child.stop();
+              }
+            }
+            toRemove = toRemove.next;
           }
         },
         _gotoFrame: function gotoFrame(frameNum, execute) {
           var enterFrame = frameNum !== this._currentFrame;
           if (this._allowFrameNavigation || !this._loader._isAvm2Enabled) {
             if (enterFrame) {
               this._destructChildren(frameNum);
               this._declareChildren(frameNum);
@@ -42548,16 +40980,17 @@ var MovieClipDefinition = function () {
               domain.broadcastMessage('frameConstructed');
               domain.broadcastMessage('executeFrame');
               domain.broadcastMessage('exitFrame');
               return;
             }
             if (enterFrame && (execute || !this._loader._isAvm2Enabled)) {
               this._callFrame(frameNum);
             }
+            this._postConstructChildren();
             return;
           }
           if (enterFrame) {
             this._playHead = frameNum;
           }
         },
         _enterFrame: function navigate(frameNum) {
           if (frameNum === this._currentFrame) {
@@ -42927,22 +41360,17 @@ var MovieClipDefinition = function () {
           play: def.play,
           stop: def.stop,
           nextFrame: def.nextFrame,
           prevFrame: def.prevFrame,
           gotoAndPlay: def.gotoAndPlay,
           gotoAndStop: def.gotoAndStop,
           addFrameScript: def.addFrameScript,
           prevScene: def.prevScene,
-          nextScene: def.nextScene,
-          _depth: {
-            get: function () {
-              return this._depth;
-            }
-          }
+          nextScene: def.nextScene
         }
       }
     };
     return def;
   }.call(this);
 var NativeMenuDefinition = function () {
     return {
       __class__: 'flash.display.NativeMenu',
@@ -43343,43 +41771,45 @@ var SimpleButtonDefinition = function ()
 var SpriteDefinition = function () {
     var def = {
         __class__: 'flash.display.Sprite',
         initialize: function () {
           this._buttonMode = false;
           this._hitArea = null;
           this._useHandCursor = true;
           this._hitTarget = null;
-          this._depthMap = {};
+          this._currentDisplayList = null;
           var s = this.symbol;
           if (s) {
             this._graphics = s.graphics || new flash.display.Graphics();
             if (s.timeline) {
               var displayList = s.timeline[0];
               if (displayList) {
                 var depths = displayList.depths;
                 for (var i = 0; i < depths.length; i++) {
                   var cmd = displayList[depths[i]];
                   if (cmd) {
-                    this._addTimelineChild(cmd);
+                    var displayListItem = this._addTimelineChild(cmd);
+                    displayListItem.next = this._currentDisplayList;
+                    this._currentDisplayList = displayListItem;
                   }
                 }
               }
             }
           } else {
             this._graphics = new flash.display.Graphics();
           }
           this._graphics._parent = this;
         },
         _addTimelineChild: function addTimelineChild(cmd, index) {
           var symbolPromise = cmd.promise;
           var symbolInfo = symbolPromise.value;
           var props = Object.create(symbolInfo.props);
+          props.symbolId = cmd.symbolId;
           props.depth = cmd.depth;
-          props.symbolId = cmd.symbolId;
           if (cmd.clip) {
             props.clipDepth = cmd.clipDepth;
           }
           if (cmd.hasCxform) {
             props.cxform = cmd.cxform;
           }
           if (cmd.hasMatrix) {
             props.currentTransform = cmd.matrix;
@@ -43388,58 +41818,45 @@ var SpriteDefinition = function () {
             props.name = cmd.name;
           }
           if (cmd.hasRatio) {
             props.ratio = cmd.ratio / 65535;
           }
           if (cmd.blend) {
             props.blendMode = cmd.blendMode;
           }
-          var child = {
+          var displayListItem = {
+              cmd: cmd,
+              depth: cmd.depth,
               className: symbolInfo.className,
+              props: props,
               events: cmd.events,
-              props: props
+              obj: null
             };
           if (index !== undefined) {
-            this._children.splice(index, 0, child);
-          } else {
-            this._children.push(child);
+            this._children.splice(index, 0, displayListItem);
+          } else {
+            this._children.push(displayListItem);
           }
           this._sparse = true;
-        },
-        _removeTimelineChild: function removeTimelineChild(cmd) {
-          var child = this._depthMap[cmd.depth];
-          if (!child) {
-            return;
-          }
-          this._depthMap[child._depth] = null;
-          child._depth = null;
-          if (!child._owned) {
-            return;
-          }
-          this._sparse = true;
-          this.removeChild(child);
-          child.destroy();
-          if (child._isPlaying) {
-            child.stop();
-          }
+          return displayListItem;
         },
         _constructChildren: function () {
           if (!this._sparse) {
             return;
           }
           var loader = this._loader;
           var children = this._children;
           for (var i = 0; i < children.length; i++) {
-            var symbolInfo = children[i];
-            if (flash.display.DisplayObject.class.isInstanceOf(symbolInfo)) {
-              symbolInfo._index = i;
-            } else {
-              var symbolClass = avm2.systemDomain.findClass(symbolInfo.className) ? avm2.systemDomain.getClass(symbolInfo.className) : avm2.applicationDomain.getClass(symbolInfo.className);
-              var props = Object.create(symbolInfo.props);
+            var displayListItem = children[i];
+            if (flash.display.DisplayObject.class.isInstanceOf(displayListItem)) {
+              displayListItem._index = i;
+            } else {
+              var symbolClass = avm2.systemDomain.findClass(displayListItem.className) ? avm2.systemDomain.getClass(displayListItem.className) : avm2.applicationDomain.getClass(displayListItem.className);
+              var props = Object.create(displayListItem.props);
               var name = props.name;
               props.animated = true;
               props.owned = true;
               props.parent = this;
               props.stage = this._stage;
               if (this._level > -1) {
                 props.level = this._level + 1;
               }
@@ -43450,56 +41867,74 @@ var SpriteDefinition = function () {
               }
               symbolClass.instanceConstructor.call(instance);
               if (flash.display.BitmapData.class.isInstanceOf(instance)) {
                 var bitmapData = instance;
                 instance = flash.display.Bitmap.class.createAsSymbol(props);
                 flash.display.Bitmap.class.instanceConstructor.call(instance, bitmapData);
               }
               if (!loader._isAvm2Enabled) {
-                this._initAvm1Bindings(instance, name, symbolInfo.events);
+                this._initAvm1Bindings(instance, name, displayListItem.events);
                 instance._dispatchEvent('init');
                 instance._dispatchEvent('construct');
-              }
-              instance._dispatchEvent('load');
+                instance._needLoadEvent = true;
+              } else {
+                instance._dispatchEvent('load');
+              }
               instance._dispatchEvent('added');
               if (this._stage) {
                 this._stage._addToStage(instance);
               }
               children[i] = instance;
-              this._depthMap[instance._depth] = instance;
+              displayListItem.obj = instance;
             }
           }
           this._sparse = false;
         },
+        _postConstructChildren: function () {
+          var loader = this._loader;
+          if (!loader || loader._isAvm2Enabled) {
+            return;
+          }
+          var children = this._children;
+          for (var i = 0; i < children.length; i++) {
+            var instance = children[i];
+            if (instance._needLoadEvent) {
+              delete instance._needLoadEvent;
+              instance._dispatchEvent('load');
+            }
+          }
+        },
         _duplicate: function (name, depth, initObject) {
           var loader = this._loader;
           var parent = this._parent;
           var children = parent._children;
           var symbolClass = this.class;
           var symbolInfo = this.symbol;
           var props = Object.create(symbolInfo);
           props.name = name;
+          props.parent = parent;
           props.depth = depth;
-          props.parent = parent;
           var instance = symbolClass.createAsSymbol(props);
-          if (name)
-            parent[Multiname.getPublicQualifiedName(name)] = instance;
+          if (name && loader && !loader._isAvm2Enabled && !parent.asHasProperty(undefined, name, 0, false)) {
+            parent.asSetPublicProperty(name, instance);
+          }
           symbolClass.instanceConstructor.call(instance);
+          instance._index = children.length;
+          children.push(instance);
           if (!loader._isAvm2Enabled) {
             parent._initAvm1Bindings(instance, name, symbolInfo && symbolInfo.events);
             instance._dispatchEvent('init');
             instance._dispatchEvent('construct');
           }
           instance._dispatchEvent('load');
           instance._dispatchEvent('added');
           if (this._stage) {
             instance._invalidate();
           }
-          children.push(instance);
           return instance;
         },
         _insertChildAtDepth: function (child, depth) {
           this.addChild(child);
           var name = child._name;
           var loader = this._loader;
           if (name && loader && !loader._isAvm2Enabled && !this._getAS2Object().asHasProperty(undefined, name, 0, true)) {
             this._getAS2Object().asSetPublicProperty(name, child._getAS2Object());
@@ -43518,32 +41953,33 @@ var SpriteDefinition = function () {
               variableName = targetPath.pop();
               if (targetPath[0] == '_root' || targetPath[0] === '') {
                 clip = this.root._getAS2Object();
                 targetPath.shift();
                 if (targetPath[0] === '') {
                   targetPath.shift();
                 }
               } else {
-                clip = instance._getAS2Object();
+                clip = this._getAS2Object();
               }
               while (targetPath.length > 0) {
                 var childName = targetPath.shift();
                 clip = clip.asGetPublicProperty(childName) || clip[childName];
                 if (!clip) {
                   throw new Error('Cannot find ' + childName + ' variable');
                 }
               }
-            } else
-              clip = instance._getAS2Object();
+            } else {
+              clip = this._getAS2Object();
+            }
             if (!clip.asHasProperty(undefined, variableName, 0)) {
               clip.asSetPublicProperty(variableName, instance.text);
             }
             instance._addEventListener('advanceFrame', function () {
-              instance.text = clip.asGetPublicProperty(variableName);
+              instance.text = '' + clip.asGetPublicProperty(variableName);
             });
           }
           if (events) {
             var eventsBound = [];
             for (var i = 0; i < events.length; i++) {
               var event = events[i];
               if (event.eoe) {
                 break;
@@ -43553,27 +41989,32 @@ var SpriteDefinition = function () {
                 }.bind(instance, event.actionsData);
               for (var eventName in event) {
                 if (eventName.indexOf('on') !== 0 || !event[eventName])
                   continue;
                 var avm2EventName = eventName[2].toLowerCase() + eventName.substring(3);
                 if (avm2EventName === 'enterFrame') {
                   avm2EventName = 'frameConstructed';
                 }
-                instance._addEventListener(avm2EventName, fn, false);
+                var avm2EventTarget = instance;
+                if (avm2EventName === 'mouseDown' || avm2EventName === 'mouseUp' || avm2EventName === 'mouseMove') {
+                  avm2EventTarget = this._stage;
+                }
+                avm2EventTarget._addEventListener(avm2EventName, fn, false);
                 eventsBound.push({
                   name: avm2EventName,
-                  fn: fn
+                  fn: fn,
+                  target: avm2EventTarget
                 });
               }
             }
             if (eventsBound.length > 0) {
               instance._addEventListener('removed', function (eventsBound) {
                 for (var i = 0; i < eventsBound.length; i++) {
-                  instance._removeEventListener(eventsBound[i].name, eventsBound[i].fn, false);
+                  eventsBound[i].target._removeEventListener(eventsBound[i].name, eventsBound[i].fn, false);
                 }
               }.bind(instance, eventsBound), false);
             }
           }
           if (name) {
             this._getAS2Object().asSetPublicProperty(name, instance._getAS2Object());
           }
         },
@@ -43670,17 +42111,17 @@ var StageDefinition = function () {
         this._colorCorrection = 'default';
         this._stageFocusRect = true;
         this._fullScreenSourceRect = null;
         this._wmodeGPU = false;
         this._root = null;
         this._qtree = null;
         this._invalidObjects = [];
         this._mouseMoved = false;
-        this._clickTarget = this;
+        this._mouseTarget = this;
         this._cursor = 'auto';
         this._concatenatedTransform.invalid = false;
       },
       _setup: function setup(ctx, options) {
         this._qtree = new QuadTree(0, 0, this._stageWidth, this._stageHeight, 0);
         this._invalid = true;
       },
       _addToStage: function addToStage(displayObject) {
@@ -43712,17 +42153,17 @@ var StageDefinition = function () {
       },
       _invalidateOnStage: function invalidateOnStage(displayObject) {
         if (displayObject._invalid) {
           return;
         }
         displayObject._invalid = true;
         this._invalidObjects.push(displayObject);
       },
-      _processInvalidRegions: function processInvalidRegions() {
+      _processInvalidRegions: function processInvalidRegions(createInvalidPath) {
         var objects = this._invalidObjects;
         var regions = [];
         while (objects.length) {
           var displayObject = objects.shift();
           if (displayObject._children.length) {
             var children = displayObject._children;
             for (var i = 0; i < children.length; i++) {
               var child = children[i];
@@ -43760,16 +42201,19 @@ var StageDefinition = function () {
               currentRegion.obj = displayObject;
               displayObject._region = currentRegion;
             }
             regions.push(currentRegion);
           } else {
             displayObject._invalid = false;
           }
         }
+        if (!createInvalidPath) {
+          return;
+        }
         var invalidPath = new ShapePath();
         for (var i = 0; i < regions.length; i++) {
           var region = regions[i];
           var xMin = region.xMin - region.xMin % 20 - 40;
           var yMin = region.yMin - region.yMin % 20 - 40;
           var xMax = region.xMax - region.xMax % 20 + 80;
           var yMax = region.yMax - region.yMax % 20 + 80;
           var neighbours = this._qtree.retrieve(xMin, yMin, xMax, yMax);
@@ -43842,63 +42286,58 @@ var StageDefinition = function () {
               break;
             }
         }
         if (!target) {
           target = this;
         } else if (target._hitTarget) {
           target = target._hitTarget;
         }
-        if (target === this._clickTarget) {
-          target._dispatchEvent(new flash.events.MouseEvent('mouseMove'));
-        } else {
-          if (this._clickTarget._buttonMode) {
-            this._clickTarget._gotoButtonState('up');
-          }
-          this._clickTarget._dispatchEvent(new flash.events.MouseEvent('mouseOut'));
-          var nodeLeft = this._clickTarget;
+        if (target === this._mouseTarget) {
+          target._dispatchEvent('mouseMove');
+        } else {
+          if (this._mouseTarget._buttonMode) {
+            this._mouseTarget._gotoButtonState('up');
+          }
+          this._mouseTarget._dispatchEvent('mouseOut');
+          var nodeLeft = this._mouseTarget;
           var containerLeft = nodeLeft._parent;
           var nodeEntered = target;
           var containerEntered = nodeEntered._parent;
           var cursor = 'auto';
           while (nodeLeft._level >= 0 && nodeLeft !== containerEntered) {
             if (nodeLeft._hasEventListener('rollOut')) {
-              nodeLeft._dispatchEvent(new flash.events.MouseEvent('rollOut', false));
+              nodeLeft._dispatchEvent('rollOut');
             }
             nodeLeft = nodeLeft._parent;
           }
           while (nodeEntered._level >= 0 && nodeEntered !== containerLeft) {
             if (nodeEntered._hasEventListener('rollOver')) {
-              nodeEntered._dispatchEvent(new flash.events.MouseEvent('rollOver', false));
+              nodeEntered._dispatchEvent('rollOver');
             }
             if (nodeEntered._buttonMode && nodeEntered._useHandCursor) {
               cursor = 'pointer';
             }
             nodeEntered = nodeEntered._parent;
           }
           if (target._buttonMode) {
             target._gotoButtonState('over');
           }
-          target._dispatchEvent(new flash.events.MouseEvent('mouseOver'));
-          this._clickTarget = target;
+          target._dispatchEvent('mouseOver');
+          this._mouseTarget = target;
           this._cursor = cursor;
         }
       },
       _as2SetLevel: function (level, loader) {
         somewhatImplemented('Stage._as2SetLevel');
         this.addChild(loader);
       },
       __glue__: {
         native: {
           instance: {
-            $canvasState: {
-              get: function () {
-                return this._canvasState;
-              }
-            },
             invalidate: function invalidate() {
               this._invalid = true;
               this._deferRenderEvent = true;
             },
             isFocusInaccessible: function isFocusInaccessible() {
               notImplemented('Stage.isFocusInaccessible');
             },
             set_displayState: function set_displayState(value) {
@@ -44181,21 +42620,41 @@ var StageDefinition = function () {
               clone: 'open public clone'
             }
           }
         }
       };
     }.call(this);
 }
 var EventDispatcherDefinition = function () {
+    var mouseEvents = {
+        click: true,
+        contextMenu: true,
+        doubleClick: true,
+        middleClick: true,
+        middleMouseDown: true,
+        middleMouseUp: true,
+        mouseDown: true,
+        mouseMove: true,
+        mouseOut: true,
+        mouseOver: true,
+        mouseUp: true,
+        mouseWheel: true,
+        releaseOutside: true,
+        rightClick: true,
+        rightMouseDown: true,
+        rightMouseUp: true,
+        rollOut: false,
+        rollOver: false
+      };
     function doDispatchEvent(dispatcher, event, eventClass) {
       var target = dispatcher._target;
       var type = event._type || event;
       var listeners = dispatcher._listeners[type];
-      if (event._bubbles) {
+      if (typeof event === 'string' && mouseEvents[event] || event._bubbles) {
         var ancestors = [];
         var currentNode = target._parent;
         while (currentNode) {
           if (currentNode._hasEventListener(type)) {
             ancestors.push(currentNode);
           }
           currentNode = currentNode._parent;
         }
@@ -44234,17 +42693,29 @@ var EventDispatcherDefinition = function
               if (!methodInfo.parameters[0].isUsed) {
                 item.handleEvent();
                 continue;
               }
             }
           }
           if (needsInit) {
             if (typeof event === 'string') {
-              event = eventClass ? new eventClass(event) : new flash.events.Event(event);
+              if (eventClass) {
+                event = new eventClass(event);
+              } else {
+                if (event in mouseEvents) {
+                  event = new flash.events.MouseEvent(event, mouseEvents[event]);
+                  if (target._stage) {
+                    event._localX = target.mouseX;
+                    event._localY = target.mouseY;
+                  }
+                } else {
+                  event = new flash.events.Event(event);
+                }
+              }
             } else if (event._target) {
               event = event.clone();
             }
             event._target = target;
             event._currentTarget = currentTarget || target;
             event._eventPhase = eventPhase || 2;
             needsInit = false;
           }
@@ -44260,17 +42731,17 @@ var EventDispatcherDefinition = function
       __class__: 'flash.events.EventDispatcher',
       initialize: function () {
         this._target = this;
         this._listeners = {};
         this._captureListeners = {};
       },
       _addEventListenerImpl: function addEventListenerImpl(type, listener, useCapture, priority) {
         if (typeof listener !== 'function') {
-          throw new ArgumentError();
+          throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function');
         }
         var listeners = useCapture ? this._captureListeners : this._listeners;
         var queue = listeners[type];
         var listenerObj = {
             handleEvent: listener,
             priority: priority || 0
           };
         if (queue) {
@@ -44292,17 +42763,17 @@ var EventDispatcherDefinition = function
           ];
         }
       },
       _addEventListener: function addEventListener(type, listener, useCapture, priority) {
         this._addEventListenerImpl(type, listener, useCapture, priority);
       },
       _removeEventListenerImpl: function removeEventListenerImpl(type, listener, useCapture) {
         if (typeof listener !== 'function') {
-          return;
+          throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function');
         }
         var listeners = useCapture ? this._captureListeners : this._listeners;
         var queue = listeners[type];
         if (queue) {
           for (var i = 0; i < queue.length; i++) {
             var item = queue[i];
             if (item.handleEvent === listener) {
               queue.splice(i, 1);
@@ -44405,43 +42876,55 @@ var KeyboardEventDefinition = function (
           }
         }
       }
     };
   }.call(this);
 var MouseEventDefinition = function () {
     return {
       __class__: 'flash.events.MouseEvent',
+      initialize: function () {
+        this._localX = NaN;
+        this._localY = NaN;
+      },
       __glue__: {
         native: {
           instance: {
             updateAfterEvent: function updateAfterEvent() {
             },
             getStageX: function getStageX() {
-              return this._target.stage._mouseX / 20;
+              if (this._target) {
+                var m = this._target._getConcatenatedTransform();
+                var x = m.a * this._localX + m.c * this._localY + m.tx;
+                return x / 20;
+              }
+              return this._localX / 20;
             },
             getStageY: function getStageY() {
-              return this._target.stage._mouseY / 20;
+              if (this._target) {
+                var m = this._target._getConcatenatedTransform();
+                var y = m.d * this._localY + m.b * this._localX + m.ty;
+                return y / 20;
+              }
+              return this._localY / 20;
             },
             localX: {
               get: function localX() {
-                var x = isNaN(this._localX) ? this._target.mouseX : this._localX;
-                return x / 20;
+                return this._localX / 20;
               },
               set: function localX(value) {
                 this._localX = value * 20 | 0;
               }
             },
             localY: {
               get: function localY() {
-                var y = isNaN(this._localY) ? this._target.mouseY : this._localY;
-                return y / 20;
+                return this._localY / 20;
               },
               set: function localY(value) {
-                this._localY = value * 20 / 0;
+                this._localY = value * 20 | 0;
               }
             }
           }
         },
         script: {
           static: Glue.ALL
         }
       }
@@ -45315,18 +43798,19 @@ var TransformDefinition = function () {
           if (cxform) {
             return new flash.geom.ColorTransform(cxform.redMultiplier / 256, cxform.greenMultiplier / 256, cxform.blueMultiplier / 256, cxform.alphaMultiplier / 256, cxform.redOffset, cxform.greenOffset, cxform.blueOffset, cxform.alphaOffset);
           } else {
             return new flash.geom.ColorTransform();
           }
         },
         set colorTransform(val) {
           var CTClass = avm2.systemDomain.getClass('flash.geom.ColorTransform');
-          if (!CTClass.isInstanceOf(val))
-            throw TypeError();
+          if (!CTClass.isInstanceOf(val)) {
+            throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.ColorTransform');
+          }
           this._target._cxform = {
             redMultiplier: val.redMultiplier * 256,
             greenMultiplier: val.greenMultiplier * 256,
             blueMultiplier: val.blueMultiplier * 256,
             alphaMultiplier: val.alphaMultiplier * 256,
             redOffset: val.redOffset,
             greenOffset: val.greenOffset,
             blueOffset: val.blueOffset,
@@ -45349,18 +43833,19 @@ var TransformDefinition = function () {
         get matrix() {
           if (this._target._current3DTransform) {
             return null;
           }
           var m = this._target._currentTransform;
           return new flash.geom.Matrix(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20);
         },
         set matrix(val) {
-          if (!flash.geom.Matrix.class.isInstanceOf(val))
-            throw TypeError();
+          if (!flash.geom.Matrix.class.isInstanceOf(val)) {
+            throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix');
+          }
           var target = this._target;
           target._invalidate();
           var a = val.a;
           var b = val.b;
           var c = val.c;
           var d = val.d;
           var tx = val.tx * 20 | 0;
           var ty = val.ty * 20 | 0;
@@ -45381,18 +43866,19 @@ var TransformDefinition = function () {
           target._current3DTransform = null;
         },
         get matrix3D() {
           var m = this._target._current3DTransform;
           return m && m.clone();
         },
         set matrix3D(val) {
           var Matrix3DClass = avm2.systemDomain.getClass('flash.geom.Matrix3D');
-          if (!Matrix3DClass.isInstanceOf(val))
-            throw TypeError();
+          if (!Matrix3DClass.isInstanceOf(val)) {
+            throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix3D');
+          }
           var raw = val.rawData;
           this.matrix = new flash.geom.Matrix(raw.asGetPublicProperty(0), raw.asGetPublicProperty(1), raw.asGetPublicProperty(4), raw.asGetPublicProperty(5), raw.asGetPublicProperty(12), raw.asGetPublicProperty(13));
           this._target._current3DTransform = val;
         },
         ctor: function (target) {
           this._target = target;
           target._transform = this;
         }
@@ -45557,20 +44043,20 @@ var SoundDefinition = function () {
             }
             if (mp3DecodingSession) {
               mp3DecodingSession.close();
             }
           });
           stream.load(request);
         },
         loadCompressedDataFromByteArray: function loadCompressedDataFromByteArray(bytes, bytesLength) {
-          throw 'Not implemented: loadCompressedDataFromByteArray';
+          notImplemented('Sound#loadCompressedDataFromByteArray');
         },
         loadPCMFromByteArray: function loadPCMFromByteArray(bytes, samples, format, stereo, sampleRate) {
-          throw 'Not implemented: loadPCMFromByteArray';
+          notImplemented('Sound#loadPCMFromByteArray');
         },
         play: function play(startTime, loops, soundTransform) {
           startTime = startTime || 0;
           loops = loops || 0;
           var channel = new flash.media.SoundChannel();
           channel._sound = this;
           channel._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform;
           this._playQueue.push({
@@ -45590,20 +44076,20 @@ var SoundDefinition = function () {
         },
         get bytesTotal() {
           return this._bytesTotal;
         },
         get id3() {
           return this._id3;
         },
         get isBuffering() {
-          throw 'Not implemented: isBuffering';
+          notImplemented('Sound#isBuffering');
         },
         get isURLInaccessible() {
-          throw 'Not implemented: isURLInaccessible';
+          notImplemented('Sound#isURLInaccessible');
         },
         get length() {
           return this._length;
         },
         get url() {
           return this._url;
         }
       };
@@ -46301,26 +44787,26 @@ var VideoDefinition = function () {
           if (width > 0 && height > 0) {
             ctx.save();
             ctx.beginPath();
             ctx.rect(0, 0, width, height);
             ctx.clip();
             ctx.clearRect(0, 0, width, height);
             ctx.restore();
           }
-          var matrix = ctx.currentTransform;
+          var matrix = this._getConcatenatedTransform(true);
           var sx = width / this._videoWidth;
           var sy = height / this._videoHeight;
           var scaleFactor = this.stage && this.stage._contentsScaleFactor || 1;
           var a = sx * matrix.a / scaleFactor;
           var b = sx * matrix.b / scaleFactor;
           var c = sy * matrix.c / scaleFactor;
           var d = sy * matrix.d / scaleFactor;
-          var e = matrix.e / scaleFactor;
-          var f = matrix.f / scaleFactor;
+          var e = matrix.tx / 20 / scaleFactor;
+          var f = matrix.ty / 20 / scaleFactor;
           var cssTransform = 'transform: matrix(' + a + ',' + b + ',' + c + ',' + d + ',' + e + ',' + f + ');';
           if (this._currentCssTransform !== cssTransform) {
             this._currentCssTransform = cssTransform;
             this._element.setAttribute('style', 'position: absolute; top:0; left:0; z-index: -100;transform-origin: 0px 0px 0;' + cssTransform + '-webkit-transform-origin: 0px 0px 0; -webkit-' + cssTransform);
           }
         }
       };
     def.__glue__ = {
@@ -47299,17 +45785,17 @@ var URLStreamDefinition = function () {
               self._stream = new Stream(new ArrayBuffer(0), 0, 0, 0);
             }
             self._dispatchEvent(new flash.events.Event('complete', false, false));
           };
           session.open(request._toFileRequest());
           this._session = session;
         },
         readBoolean: function readBoolean() {
-          throw 'Not implemented: URLStream.readBoolean';
+          notImplemented('URLStream.readBoolean');
         },
         readByte: function readByte() {
           var stream = this._stream;
           stream.ensure(1);
           return stream.bytes[stream.pos++];
         },
         readBytes: function readBytes(bytes, offset, length) {
           if (length < 0)
@@ -47318,50 +45804,50 @@ var URLStreamDefinition = function () {
           if (!length)
             length = stream.remaining();
           else
             stream.ensure(length);
           bytes.writeRawBytes(stream.bytes.subarray(stream.pos, stream.pos + length), offset, length);
           stream.pos += length;
         },
         readDouble: function readDouble() {
-          throw 'Not implemented: URLStream.readDouble';
+          notImplemented('URLStream.readDouble');
         },
         readFloat: function readFloat() {
-          throw 'Not implemented: URLStream.readFloat';
+          notImplemented('URLStream.readFloat');
         },
         readInt: function readInt() {
-          throw 'Not implemented: URLStream.readInt';
+          notImplemented('URLStream.readInt');
         },
         readMultiByte: function readMultiByte(length, charSet) {
-          throw 'Not implemented: URLStream.readMultiByte';
+          notImplemented('URLStream.readMultiByte');
         },
         readObject: function readObject() {
-          throw 'Not implemented: URLStream.readObject';
+          notImplemented('URLStream.readObject');
         },
         readShort: function readShort() {
-          throw 'Not implemented: URLStream.readShort';
+          notImplemented('URLStream.readShort');
         },
         readUTF: function readUTF() {
           return this.readUTFBytes(this.readUnsignedShort());
         },
         readUTFBytes: function readUTFBytes(length) {
           if (length < 0)
             throw 'Invalid length argument';
           var stream = this._stream;
           stream.ensure(length);
           var str = utf8encode(stream.bytes.subarray(stream.pos, stream.pos + length));
           stream.pos += length;
           return str;
         },
         readUnsignedByte: function readUnsignedByte() {
-          throw 'Not implemented: URLStream.readUnsignedByte';
+          notImplemented('URLStream.readUnsignedByte');
         },
         readUnsignedInt: function readUnsignedInt() {
-          throw 'Not implemented: URLStream.readUnsignedInt';
+          notImplemented('URLStream.readUnsignedInt');
         },
         readUnsignedShort: function readUnsignedShort() {
           var stream = this._stream;
           stream.ensure(2);
           var result = stream.getUint16(stream.pos, this._littleEndian);
           stream.pos += 2;
           return result;
         },
@@ -47373,20 +45859,20 @@ var URLStreamDefinition = function () {
         },
         get endian() {
           return this._littleEndian ? 'littleEndian' : 'bigEndian';
         },
         set endian(val) {
           this._littleEndian = val == 'littleEndian';
         },
         get objectEncoding() {
-          throw 'Not implemented: URLStream.objectEncoding$get';
+          notImplemented('URLStream.objectEncoding');
         },
         set objectEncoding(val) {
-          throw 'Not implemented: URLStream.objectEncoding$set';
+          notImplemented('URLStream.objectEncoding');
         }
       };
     var desc = Object.getOwnPropertyDescriptor;
     def.__glue__ = {
       native: {
         instance: {
           close: def.close,
           load: def.load,
@@ -47748,71 +46234,3147 @@ var SystemDefinition = function () {
           instance: {}
         }
       }
     };
   }.call(this);
 {
   var FontDefinition = function () {
       var fonts = [];
+      var fontsByUniqueName = Object.create(null);
+      var fontsByNameStyleType = Object.create(null);
+      var _deviceFontMetrics;
       var def = {
           __class__: 'flash.text.Font',
           initialize: function () {
             var s = this.symbol;
             if (s) {
               this._fontName = s.name || null;
               this._uniqueName = s.uniqueName;
-              this._metrics = s.metrics;
+              if (s.bold) {
+                if (s.italic) {
+                  this._fontStyle = 'boldItalic';
+                } else {
+                  this._fontStyle = 'bold';
+                }
+              } else if (s.italic) {
+                this._fontStyle = 'italic';
+              } else {
+                this._fontStyle = 'regular';
+              }
+              var metrics = s.metrics;
+              metrics.height = metrics.ascent + metrics.descent + metrics.leading;
+              this._metrics = metrics;
+              this._fontType = 'embedded';
               fonts.push(this);
+              fontsByUniqueName[this._uniqueName] = this;
+              var ident = this._fontName.toLowerCase() + '_' + this._fontStyle + '_embedded';
+              fontsByNameStyleType[ident] = this;
             }
           },
           get fontName() {
             return this._fontName;
           },
           get fontStyle() {
             return this._fontStyle;
           },
           get fontType() {
             return this._fontType;
           },
           hasGlyphs: function hasGlyphs(str) {
             return true;
+          },
+          getFont: function (name, style, embedded) {
+            var ident = name.toLowerCase() + '_' + style + (embedded ? '_embedded' : '_device');
+            var font = fontsByNameStyleType[ident];
+            if (font) {
+              return font;
+            }
+            font = new flash.text.Font();
+            font._fontName = font._uniqueName = name;
+            font._fontStyle = style;
+            font._fontType = 'device';
+            var metrics = deviceFontMetrics()[name];
+            if (!metrics) {
+              metrics = deviceFontMetrics().serif;
+              font._fontName = font._uniqueName = 'serif';
+            }
+            font._metrics = {
+              ascent: metrics[0],
+              descent: metrics[1],
+              leading: metrics[2]
+            };
+            font._metrics.height = metrics[0] + metrics[1] + metrics[2];
+            fontsByNameStyleType[ident] = font;
+            return font;
+          },
+          getFontByUniqueName: function (name) {
+            return fontsByUniqueName[name];
           }
         };
       function enumerateFonts(device) {
         return fonts.slice();
       }
       function registerFont(font) {
-        throw 'Not implemented: registerFont';
-      }
-      function findFont(fn) {
-        var font;
-        fonts.some(function (f) {
-          return fn(f) && (font = f, true);
-        });
-        return font;
+        somewhatImplemented('Font.registerFont');
+      }
+      function deviceFontMetrics() {
+        if (_deviceFontMetrics) {
+          return _deviceFontMetrics;
+        }
+        var userAgent = window.navigator.userAgent;
+        if (userAgent.indexOf('Windows') > -1) {
+          _deviceFontMetrics = DEVICE_FONT_METRICS_WIN;
+        } else if (/(Macintosh|iPad|iPhone|iPod|Android)/.test(userAgent)) {
+          _deviceFontMetrics = DEVICE_FONT_METRICS_MAC;
+        } else {
+          _deviceFontMetrics = DEVICE_FONT_METRICS_LINUX;
+        }
+        return _deviceFontMetrics;
       }
       var desc = Object.getOwnPropertyDescriptor;
       def.__glue__ = {
         native: {
           instance: {
             fontName: desc(def, 'fontName'),
             fontStyle: desc(def, 'fontStyle'),
             fontType: desc(def, 'fontType'),
             hasGlyphs: def.hasGlyphs
           },
           static: {
             enumerateFonts: enumerateFonts,
-            registerFont: registerFont,
-            _findFont: findFont
+            registerFont: registerFont
           }
         }
       };
       return def;
     }.call(this);
+  var DEVICE_FONT_METRICS_WIN = {
+      'serif': [
+        1,
+        0.25,
+        0
+      ],
+      'sans-serif': [
+        1,
+        0.25,
+        0
+      ],
+      'monospace': [
+        1,
+        0.25,
+        0
+      ],
+      'birch std': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'blackoak std': [
+        1,
+        0.3333,
+        0
+      ],
+      'chaparral pro': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'chaparral pro light': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'charlemagne std': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cooper std black': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'giddyup std': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'hobo std': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pro b': [
+        1,
+        0.4167,
+        0
+      ],
+      'kozuka gothic pro el': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'kozuka gothic pro h': [
+        1,
+        0.4167,
+        0
+      ],
+      'kozuka gothic pro l': [
+        1,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pro m': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pro r': [
+        1,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pro b': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'kozuka mincho pro el': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'kozuka mincho pro h': [
+        1.1667,
+        0.25,
+        0
+      ],
+      'kozuka mincho pro l': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'kozuka mincho pro m': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'kozuka mincho pro r': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'mesquite std': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'minion pro cond': [
+        1,
+        0.3333,
+        0
+      ],
+      'minion pro med': [
+        1,
+        0.3333,
+        0
+      ],
+      'minion pro smbd': [
+        1,
+        0.3333,
+        0
+      ],
+      'myriad arabic': [
+        1,
+        0.4167,
+        0
+      ],
+      'nueva std': [
+        0.75,
+        0.25,
+        0
+      ],
+      'nueva std cond': [
+        0.75,
+        0.25,
+        0
+      ],
+      'ocr a std': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'orator std': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'poplar std': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'prestige elite std': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'rosewood std regular': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'stencil std': [
+        1,
+        0.3333,
+        0
+      ],
+      'trajan pro': [
+        1,
+        0.25,
+        0
+      ],
+      'kozuka gothic pr6n b': [
+        1.4167,
+        0.4167,
+        0
+      ],
+      'kozuka gothic pr6n el': [
+        1.4167,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pr6n h': [
+        1.4167,
+        0.4167,
+        0
+      ],
+      'kozuka gothic pr6n l': [
+        1.4167,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pr6n m': [
+        1.5,
+        0.3333,
+        0
+      ],
+      'kozuka gothic pr6n r': [
+        1.4167,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n b': [
+        1.3333,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n el': [
+        1.3333,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n h': [
+        1.4167,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n l': [
+        1.3333,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n m': [
+        1.3333,
+        0.3333,
+        0
+      ],
+      'kozuka mincho pr6n r': [
+        1.3333,
+        0.3333,
+        0
+      ],
+      'letter gothic std': [
+        1,
+        0.25,
+        0
+      ],
+      'minion pro': [
+        1,
+        0.3333,
+        0
+      ],
+      'myriad hebrew': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'myriad pro': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'myriad pro cond': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'myriad pro light': [
+        1,
+        0.25,
+        0
+      ],
+      'marlett': [
+        1,
+        0,
+        0
+      ],
+      'arial': [
+        1,
+        0.25,
+        0
+      ],
+      'arabic transparent': [
+        1,
+        0.25,
+        0
+      ],
+      'arial baltic': [
+        1,
+        0.25,
+        0
+      ],
+      'arial ce': [
+        1,
+        0.25,
+        0
+      ],
+      'arial cyr': [
+        1,
+        0.25,
+        0
+      ],
+      'arial greek': [
+        1,
+        0.25,
+        0
+      ],
+      'arial tur': [
+        1,
+        0.25,
+        0
+      ],
+      'batang': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'batangche': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'gungsuh': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'gungsuhche': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'courier new': [
+        1,
+        0.25,
+        0
+      ],
+      'courier new baltic': [
+        1,
+        0.25,
+        0
+      ],
+      'courier new ce': [
+        1,
+        0.25,
+        0
+      ],
+      'courier new cyr': [
+        1,
+        0.25,
+        0
+      ],
+      'courier new greek': [
+        1,
+        0.25,
+        0
+      ],
+      'courier new tur': [
+        1,
+        0.25,
+        0
+      ],
+      'daunpenh': [
+        0.6667,
+        0.6667,
+        0
+      ],
+      'dokchampa': [
+        1.4167,
+        0.5833,
+        0
+      ],
+      'estrangelo edessa': [
+        0.75,
+        0.3333,
+        0
+      ],
+      'euphemia': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'gautami': [
+        1.1667,
+        0.8333,
+        0
+      ],
+      'vani': [
+        1.0833,
+        0.75,
+        0
+      ],
+      'gulim': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'gulimche': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'dotum': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'dotumche': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'impact': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'iskoola pota': [
+        1,
+        0.3333,
+        0
+      ],
+      'kalinga': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'kartika': [
+        1,
+        0.4167,
+        0
+      ],
+      'khmer ui': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'lao ui': [
+        1,
+        0.25,
+        0
+      ],
+      'latha': [
+        1.0833,
+        0.4167,
+        0
+      ],
+      'lucida console': [
+        0.75,
+        0.25,
+        0
+      ],
+      'malgun gothic': [
+        1,
+        0.25,
+        0
+      ],
+      'mangal': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'meiryo': [
+        1.0833,
+        0.4167,
+        0
+      ],
+      'meiryo ui': [
+        1,
+        0.25,
+        0
+      ],
+      'microsoft himalaya': [
+        0.5833,
+        0.4167,
+        0
+      ],
+      'microsoft jhenghei': [
+        1,
+        0.3333,
+        0
+      ],
+      'microsoft yahei': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'mingliu': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'pmingliu': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'mingliu_hkscs': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'mingliu-extb': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'pmingliu-extb': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'mingliu_hkscs-extb': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'mongolian baiti': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'ms gothic': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'ms pgothic': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'ms ui gothic': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'ms mincho': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'ms pmincho': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'mv boli': [
+        1.1667,
+        0.25,
+        0
+      ],
+      'microsoft new tai lue': [
+        1,
+        0.4167,
+        0
+      ],
+      'nyala': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'microsoft phagspa': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'plantagenet cherokee': [
+        1,
+        0.4167,
+        0
+      ],
+      'raavi': [
+        1.0833,
+        0.6667,
+        0
+      ],
+      'segoe script': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'segoe ui': [
+        1,
+        0.25,
+        0
+      ],
+      'segoe ui semibold': [
+        1,
+        0.25,
+        0
+      ],
+      'segoe ui light': [
+        1,
+        0.25,
+        0
+      ],
+      'segoe ui symbol': [
+        1,
+        0.25,
+        0
+      ],
+      'shruti': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'simsun': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'nsimsun': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'simsun-extb': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'sylfaen': [
+        1,
+        0.3333,
+        0
+      ],
+      'microsoft tai le': [
+        1,
+        0.3333,
+        0
+      ],
+      'times new roman': [
+        1,
+        0.25,
+        0
+      ],
+      'times new roman baltic': [
+        1,
+        0.25,
+        0
+      ],
+      'times new roman ce': [
+        1,
+        0.25,
+        0
+      ],
+      'times new roman cyr': [
+        1,
+        0.25,
+        0
+      ],
+      'times new roman greek': [
+        1,
+        0.25,
+        0
+      ],
+      'times new roman tur': [
+        1,
+        0.25,
+        0
+      ],
+      'tunga': [
+        1.0833,
+        0.75,
+        0
+      ],
+      'vrinda': [
+        1,
+        0.4167,
+        0
+      ],
+      'shonar bangla': [
+        0.8333,
+        0.5,
+        0
+      ],
+      'microsoft yi baiti': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'tahoma': [
+        1,
+        0.1667,
+        0
+      ],
+      'microsoft sans serif': [
+        1.0833,
+        0.1667,
+        0
+      ],
+      'angsana new': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'aparajita': [
+        0.75,
+        0.4167,
+        0
+      ],
+      'cordia new': [
+        0.9167,
+        0.5,
+        0
+      ],
+      'ebrima': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'gisha': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'kokila': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'leelawadee': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'microsoft uighur': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'moolboran': [
+        0.6667,
+        0.6667,
+        0
+      ],
+      'symbol': [
+        1,
+        0.25,
+        0
+      ],
+      'utsaah': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'vijaya': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'wingdings': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'andalus': [
+        1.3333,
+        0.4167,
+        0
+      ],
+      'arabic typesetting': [
+        0.8333,
+        0.5,
+        0
+      ],
+      'simplified arabic': [
+        1.3333,
+        0.5,
+        0
+      ],
+      'simplified arabic fixed': [
+        1,
+        0.4167,
+        0
+      ],
+      'sakkal majalla': [
+        0.9167,
+        0.5,
+        0
+      ],
+      'traditional arabic': [
+        1.3333,
+        0.5,
+        0
+      ],
+      'aharoni': [
+        0.75,
+        0.25,
+        0
+      ],
+      'david': [
+        0.75,
+        0.25,
+        0
+      ],
+      'frankruehl': [
+        0.75,
+        0.25,
+        0
+      ],
+      'fangsong': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'simhei': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'kaiti': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'browallia new': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'lucida sans unicode': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'arial black': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'calibri': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cambria': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cambria math': [
+        3.0833,
+        2.5,
+        0
+      ],
+      'candara': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'comic sans ms': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'consolas': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'constantia': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'corbel': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'franklin gothic medium': [
+        1,
+        0.3333,
+        0
+      ],
+      'gabriola': [
+        1.1667,
+        0.6667,
+        0
+      ],
+      'georgia': [
+        1,
+        0.25,
+        0
+      ],
+      'palatino linotype': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'segoe print': [
+        1.25,
+        0.5,
+        0
+      ],
+      'trebuchet ms': [
+        1.0833,
+        0.4167,
+        0
+      ],
+      'verdana': [
+        1,
+        0.1667,
+        0
+      ],
+      'webdings': [
+        1.0833,
+        0.5,
+        0
+      ],
+      'lucida bright': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'lucida sans': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'lucida sans typewriter': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gentium basic': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'dejavu serif condensed': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arimo': [
+        1,
+        0.25,
+        0
+      ],
+      'dejavu sans condensed': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'dejavu sans': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'dejavu sans light': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'opensymbol': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'gentium book basic': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'dejavu sans mono': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'dejavu serif': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'calibri light': [
+        0.9167,
+        0.25,
+        0
+      ]
+    };
+  var DEVICE_FONT_METRICS_MAC = {
+      'al bayan plain': [
+        1,
+        0.5,
+        0
+      ],
+      'al bayan bold': [
+        1,
+        0.5833,
+        0
+      ],
+      'american typewriter': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'american typewriter bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'american typewriter condensed': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'american typewriter condensed bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'american typewriter condensed light': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'american typewriter light': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'andale mono': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'apple symbols': [
+        0.6667,
+        0.25,
+        0
+      ],
+      'arial bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial hebrew': [
+        0.75,
+        0.3333,
+        0
+      ],
+      'arial hebrew bold': [
+        0.75,
+        0.3333,
+        0
+      ],
+      'arial': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial narrow': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial narrow bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial narrow bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial narrow italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial rounded mt bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'arial unicode ms': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'avenir black': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir black oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir book': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir book oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir heavy': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir heavy oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir light': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir light oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir medium': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir medium oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir oblique': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir roman': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next bold': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next bold italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next demi bold': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next demi bold italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next heavy': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next heavy italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next medium': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next medium italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next regular': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next ultra light': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next ultra light italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed bold': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed bold italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed demi bold': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed demi bold italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed heavy': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed heavy italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed medium': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed medium italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed regular': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed ultra light': [
+        1,
+        0.3333,
+        0
+      ],
+      'avenir next condensed ultra light italic': [
+        1,
+        0.3333,
+        0
+      ],
+      'ayuthaya': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'baghdad': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'bangla mn': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'bangla mn bold': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'bangla sangam mn': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'bangla sangam mn bold': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'baskerville': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'baskerville bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'baskerville bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'baskerville italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'baskerville semibold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'baskerville semibold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'big caslon medium': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'brush script mt italic': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'chalkboard': [
+        1,
+        0.25,
+        0
+      ],
+      'chalkboard bold': [
+        1,
+        0.25,
+        0
+      ],
+      'chalkboard se bold': [
+        1.1667,
+        0.25,
+        0
+      ],
+      'chalkboard se light': [
+        1.1667,
+        0.25,
+        0
+      ],
+      'chalkboard se regular': [
+        1.1667,
+        0.25,
+        0
+      ],
+      'chalkduster': [
+        1,
+        0.25,
+        0
+      ],
+      'charcoal cy': [
+        1,
+        0.25,
+        0
+      ],
+      'cochin': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cochin bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cochin bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'cochin italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'comic sans ms': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'comic sans ms bold': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'copperplate': [
+        0.75,
+        0.25,
+        0
+      ],
+      'copperplate bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'copperplate light': [
+        0.75,
+        0.25,
+        0
+      ],
+      'corsiva hebrew': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'corsiva hebrew bold': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'courier': [
+        0.75,
+        0.25,
+        0
+      ],
+      'courier bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'courier bold oblique': [
+        0.75,
+        0.25,
+        0
+      ],
+      'courier oblique': [
+        0.75,
+        0.25,
+        0
+      ],
+      'courier new bold italic': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'courier new bold': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'courier new italic': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'courier new': [
+        0.8333,
+        0.3333,
+        0
+      ],
+      'biaukai': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'damascus': [
+        0.5833,
+        0.4167,
+        0
+      ],
+      'damascus bold': [
+        0.5833,
+        0.4167,
+        0
+      ],
+      'decotype naskh': [
+        1.1667,
+        0.6667,
+        0
+      ],
+      'devanagari mt': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'devanagari mt bold': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'devanagari sangam mn': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'devanagari sangam mn bold': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'didot': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'didot bold': [
+        1,
+        0.3333,
+        0
+      ],
+      'didot italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'euphemia ucas': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'euphemia ucas bold': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'euphemia ucas italic': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'futura condensed extrabold': [
+        1,
+        0.25,
+        0
+      ],
+      'futura condensed medium': [
+        1,
+        0.25,
+        0
+      ],
+      'futura medium': [
+        1,
+        0.25,
+        0
+      ],
+      'futura medium italic': [
+        1,
+        0.25,
+        0
+      ],
+      'gb18030 bitmap': [
+        1,
+        0.6667,
+        0
+      ],
+      'geeza pro': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'geeza pro bold': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'geneva': [
+        1,
+        0.25,
+        0
+      ],
+      'geneva cy': [
+        1,
+        0.25,
+        0
+      ],
+      'georgia': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'georgia bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'georgia bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'georgia italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans light': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gill sans light italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gujarati mt': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'gujarati mt bold': [
+        0.9167,
+        0.6667,
+        0
+      ],
+      'gujarati sangam mn': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'gujarati sangam mn bold': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'gurmukhi mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gurmukhi mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'gurmukhi sangam mn': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'gurmukhi sangam mn bold': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'helvetica': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica bold oblique': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica light': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica light oblique': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica oblique': [
+        0.75,
+        0.25,
+        0
+      ],
+      'helvetica neue': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'helvetica neue bold': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue bold italic': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue condensed black': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue condensed bold': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'helvetica neue light': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue light italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'helvetica neue medium': [
+        1,
+        0.25,
+        0
+      ],
+      'helvetica neue ultralight': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'helvetica neue ultralight italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'herculanum': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'hiragino kaku gothic pro w3': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino kaku gothic pro w6': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino kaku gothic pron w3': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino kaku gothic pron w6': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino kaku gothic std w8': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino kaku gothic stdn w8': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino maru gothic pro w4': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino maru gothic pron w4': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino mincho pro w3': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino mincho pro w6': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino mincho pron w3': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino mincho pron w6': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino sans gb w3': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hiragino sans gb w6': [
+        0.9167,
+        0.0833,
+        0
+      ],
+      'hoefler text black': [
+        0.75,
+        0.25,
+        0
+      ],
+      'hoefler text black italic': [
+        0.75,
+        0.25,
+        0
+      ],
+      'hoefler text italic': [
+        0.75,
+        0.25,
+        0
+      ],
+      'hoefler text ornaments': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'hoefler text': [
+        0.75,
+        0.25,
+        0
+      ],
+      'impact': [
+        1,
+        0.25,
+        0
+      ],
+      'inaimathi': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'headlinea regular': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'pilgi regular': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'gungseo regular': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'pcmyungjo regular': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'kailasa regular': [
+        1.0833,
+        0.5833,
+        0
+      ],
+      'kannada mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'kannada mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'kannada sangam mn': [
+        1,
+        0.5833,
+        0
+      ],
+      'kannada sangam mn bold': [
+        1,
+        0.5833,
+        0
+      ],
+      'kefa bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'kefa regular': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'khmer mn': [
+        1,
+        0.6667,
+        0
+      ],
+      'khmer mn bold': [
+        1,
+        0.6667,
+        0
+      ],
+      'khmer sangam mn': [
+        1.0833,
+        0.6667,
+        0
+      ],
+      'kokonor regular': [
+        1.0833,
+        0.5833,
+        0
+      ],
+      'krungthep': [
+        1,
+        0.25,
+        0
+      ],
+      'kufistandardgk': [
+        0.9167,
+        0.5,
+        0
+      ],
+      'lao mn': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'lao mn bold': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'lao sangam mn': [
+        1,
+        0.3333,
+        0
+      ],
+      'apple ligothic medium': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'lihei pro': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'lisong pro': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'lucida grande': [
+        1,
+        0.25,
+        0
+      ],
+      'lucida grande bold': [
+        1,
+        0.25,
+        0
+      ],
+      'malayalam mn': [
+        1,
+        0.4167,
+        0
+      ],
+      'malayalam mn bold': [
+        1,
+        0.4167,
+        0
+      ],
+      'malayalam sangam mn': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'malayalam sangam mn bold': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'marion bold': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'marion italic': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'marion regular': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'marker felt thin': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'marker felt wide': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'menlo bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'menlo bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'menlo italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'menlo regular': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'microsoft sans serif': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'monaco': [
+        1,
+        0.25,
+        0
+      ],
+      'gurmukhi mt': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'mshtakan': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'mshtakan bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'mshtakan boldoblique': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'mshtakan oblique': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'myanmar mn': [
+        1,
+        0.4167,
+        0
+      ],
+      'myanmar mn bold': [
+        1,
+        0.4167,
+        0
+      ],
+      'myanmar sangam mn': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'nadeem': [
+        0.9167,
+        0.4167,
+        0
+      ],
+      'nanum brush script': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanumgothic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanumgothic bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanumgothic extrabold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanummyeongjo': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanummyeongjo bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanummyeongjo extrabold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'nanum pen script': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'optima bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'optima bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'optima extrablack': [
+        1,
+        0.25,
+        0
+      ],
+      'optima italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'optima regular': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'oriya mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'oriya mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'oriya sangam mn': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'oriya sangam mn bold': [
+        0.8333,
+        0.4167,
+        0
+      ],
+      'osaka': [
+        1,
+        0.25,
+        0
+      ],
+      'osaka-mono': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'palatino bold': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'palatino bold italic': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'palatino italic': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'palatino': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'papyrus': [
+        0.9167,
+        0.5833,
+        0
+      ],
+      'papyrus condensed': [
+        0.9167,
+        0.5833,
+        0
+      ],
+      'plantagenet cherokee': [
+        0.6667,
+        0.25,
+        0
+      ],
+      'raanana': [
+        0.75,
+        0.25,
+        0
+      ],
+      'raanana bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'hei regular': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'kai regular': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'stfangsong': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'stheiti': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'heiti sc light': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'heiti sc medium': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'heiti tc light': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'heiti tc medium': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'stkaiti': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'kaiti sc black': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'kaiti sc bold': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'kaiti sc regular': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'stsong': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'songti sc black': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'songti sc bold': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'songti sc light': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'songti sc regular': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'stxihei': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'sathu': [
+        0.9167,
+        0.3333,
+        0
+      ],
+      'silom': [
+        1,
+        0.3333,
+        0
+      ],
+      'sinhala mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'sinhala mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'sinhala sangam mn': [
+        1.1667,
+        0.3333,
+        0
+      ],
+      'sinhala sangam mn bold': [
+        1.1667,
+        0.3333,
+        0
+      ],
+      'skia regular': [
+        0.75,
+        0.25,
+        0
+      ],
+      'symbol': [
+        0.6667,
+        0.3333,
+        0
+      ],
+      'tahoma negreta': [
+        1,
+        0.1667,
+        0
+      ],
+      'tamil mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'tamil mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'tamil sangam mn': [
+        0.75,
+        0.25,
+        0
+      ],
+      'tamil sangam mn bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'telugu mn': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'telugu mn bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'telugu sangam mn': [
+        1,
+        0.5833,
+        0
+      ],
+      'telugu sangam mn bold': [
+        1,
+        0.5833,
+        0
+      ],
+      'thonburi': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'thonburi bold': [
+        1.0833,
+        0.25,
+        0
+      ],
+      'times bold': [
+        0.75,
+        0.25,
+        0
+      ],
+      'times bold italic': [
+        0.75,
+        0.25,
+        0
+      ],
+      'times italic': [
+        0.75,
+        0.25,
+        0
+      ],
+      'times roman': [
+        0.75,
+        0.25,
+        0
+      ],
+      'times new roman bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'times new roman bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'times new roman italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'times new roman': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'trebuchet ms bold italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'trebuchet ms': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'trebuchet ms bold': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'trebuchet ms italic': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'verdana': [
+        1,
+        0.25,
+        0
+      ],
+      'verdana bold': [
+        1,
+        0.25,
+        0
+      ],
+      'verdana bold italic': [
+        1,
+        0.25,
+        0
+      ],
+      'verdana italic': [
+        1,
+        0.25,
+        0
+      ],
+      'webdings': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'wingdings 2': [
+        0.8333,
+        0.25,
+        0
+      ],
+      'wingdings 3': [
+        0.9167,
+        0.25,
+        0
+      ],
+      'yuppy sc regular': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'yuppy tc regular': [
+        1.0833,
+        0.3333,
+        0
+      ],
+      'zapf dingbats': [
+        0.8333,
+        0.1667,
+        0
+      ],
+      'zapfino': [
+        1.9167,
+        1.5,
+        0
+      ]
+    };
+  var DEVICE_FONT_METRICS_LINUX = {
+      'kacstfarsi': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'meera': [
+        0.682,
+        0.4413,
+        0
+      ],
+      'freemono': [
+        0.8023,
+        0.2006,
+        0
+      ],
+      'undotum': [
+        1.0029,
+        0.2808,
+        0
+      ],
+      'loma': [
+        1.1634,
+        0.4814,
+        0
+      ],
+      'century schoolbook l': [
+        1.0029,
+        0.3209,
+        0
+      ],
+      'kacsttitlel': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'undinaru': [
+        1.0029,
+        0.2407,
+        0
+      ],
+      'ungungseo': [
+        1.0029,
+        0.2808,
+        0
+      ],
+      'garuda': [
+        1.3238,
+        0.6017,
+        0
+      ],
+      'rekha': [
+        1.1232,
+        0.2808,
+        0
+      ],
+      'purisa': [
+        1.1232,
+        0.5215,
+        0
+      ],
+      'dejavu sans mono': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'vemana2000': [
+        0.8825,
+        0.8424,
+        0
+      ],
+      'kacstoffice': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'umpush': [
+        1.2837,
+        0.682,
+        0
+      ],
+      'opensymbol': [
+        0.8023,
+        0.2006,
+        0
+      ],
+      'sawasdee': [
+        1.1232,
+        0.4413,
+        0
+      ],
+      'urw palladio l': [
+        1.0029,
+        0.3209,
+        0
+      ],
+      'freeserif': [
+        0.9227,
+        0.3209,
+        0
+      ],
+      'kacstdigital': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'ubuntu condensed': [
+        0.9628,
+        0.2006,
+        0
+      ],
+      'unpilgi': [
+        1.0029,
+        0.4413,
+        0
+      ],
+      'mry_kacstqurn': [
+        1.4442,
+        0.7221,
+        0
+      ],
+      'urw gothic l': [
+        1.0029,
+        0.2407,
+        0
+      ],
+      'dingbats': [
+        0.8424,
+        0.1605,
+        0
+      ],
+      'urw chancery l': [
+        1.0029,
+        0.3209,
+        0
+      ],
+      'phetsarath ot': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'tlwg typist': [
+        0.8825,
+        0.4012,
+        0
+      ],
+      'kacstletter': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'utkal': [
+        1.2035,
+        0.6418,
+        0
+      ],
+      'dejavu sans light': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'norasi': [
+        1.2436,
+        0.5215,
+        0
+      ],
+      'dejavu serif condensed': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'kacstone': [
+        1.2436,
+        0.6418,
+        0
+      ],
+      'liberation sans narrow': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'symbol': [
+        1.043,
+        0.3209,
+        0
+      ],
+      'nanummyeongjo': [
+        0.9227,
+        0.2407,
+        0
+      ],
+      'untitled1': [
+        0.682,
+        0.5616,
+        0
+      ],
+      'lohit gujarati': [
+        0.9628,
+        0.4012,
+        0
+      ],
+      'liberation mono': [
+        0.8424,
+        0.3209,
+        0
+      ],
+      'kacstart': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'mallige': [
+        1.0029,
+        0.682,
+        0
+      ],
+      'bitstream charter': [
+        1.0029,
+        0.2407,
+        0
+      ],
+      'nanumgothic': [
+        0.9227,
+        0.2407,
+        0
+      ],
+      'liberation serif': [
+        0.9227,
+        0.2407,
+        0
+      ],
+      'dejavu sans condensed': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'ubuntu': [
+        0.9628,
+        0.2006,
+        0
+      ],
+      'courier 10 pitch': [
+        0.8825,
+        0.3209,
+        0
+      ],
+      'nimbus sans l': [
+        0.9628,
+        0.3209,
+        0
+      ],
+      'takaopgothic': [
+        0.8825,
+        0.2006,
+        0
+      ],
+      'wenquanyi micro hei mono': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'dejavu sans': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'kedage': [
+        1.0029,
+        0.682,
+        0
+      ],
+      'kinnari': [
+        1.3238,
+        0.5215,
+        0
+      ],
+      'tlwgmono': [
+        0.8825,
+        0.4012,
+        0
+      ],
+      'standard symbols l': [
+        1.043,
+        0.3209,
+        0
+      ],
+      'lohit punjabi': [
+        1.2035,
+        0.682,
+        0
+      ],
+      'nimbus mono l': [
+        0.8424,
+        0.2808,
+        0
+      ],
+      'rachana': [
+        0.682,
+        0.5616,
+        0
+      ],
+      'waree': [
+        1.2436,
+        0.4413,
+        0
+      ],
+      'kacstposter': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'khmer os': [
+        1.2837,
+        0.7622,
+        0
+      ],
+      'freesans': [
+        1.0029,
+        0.3209,
+        0
+      ],
+      'gargi': [
+        0.9628,
+        0.2808,
+        0
+      ],
+      'nimbus roman no9 l': [
+        0.9628,
+        0.3209,
+        0
+      ],
+      'dejavu serif': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'wenquanyi micro hei': [
+        0.9628,
+        0.2407,
+        0
+      ],
+      'ubuntu light': [
+        0.9628,
+        0.2006,
+        0
+      ],
+      'tlwgtypewriter': [
+        0.9227,
+        0.4012,
+        0
+      ],
+      'kacstpen': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'tlwg typo': [
+        0.8825,
+        0.4012,
+        0
+      ],
+      'mukti narrow': [
+        1.2837,
+        0.4413,
+        0
+      ],
+      'ubuntu mono': [
+        0.8424,
+        0.2006,
+        0
+      ],
+      'lohit bengali': [
+        1.0029,
+        0.4413,
+        0
+      ],
+      'liberation sans': [
+        0.9227,
+        0.2407,
+        0
+      ],
+      'unbatang': [
+        1.0029,
+        0.2808,
+        0
+      ],
+      'kacstdecorative': [
+        1.1232,
+        0.5215,
+        0
+      ],
+      'khmer os system': [
+        1.2436,
+        0.6017,
+        0
+      ],
+      'saab': [
+        1.0029,
+        0.682,
+        0
+      ],
+      'kacsttitle': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'mukti narrow bold': [
+        1.2837,
+        0.4413,
+        0
+      ],
+      'lohit hindi': [
+        1.0029,
+        0.5215,
+        0
+      ],
+      'kacstqurn': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'urw bookman l': [
+        0.9628,
+        0.2808,
+        0
+      ],
+      'kacstnaskh': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'kacstscreen': [
+        1.0831,
+        0.5215,
+        0
+      ],
+      'pothana2000': [
+        0.8825,
+        0.8424,
+        0
+      ],
+      'ungraphic': [
+        1.0029,
+        0.2808,
+        0
+      ],
+      'lohit tamil': [
+        0.8825,
+        0.361,
+        0
+      ],
+      'kacstbook': [
+        1.0831,
+        0.5215,
+        0
+      ]
+    };
+  DEVICE_FONT_METRICS_MAC.__proto__ = DEVICE_FONT_METRICS_WIN;
+  DEVICE_FONT_METRICS_LINUX.__proto__ = DEVICE_FONT_METRICS_MAC;
 }
 var StaticTextDefinition = function () {
     var def = {
         __class__: 'flash.text.StaticText',
         initialize: function () {
           var s = this.symbol;
           if (s) {
             this.draw = s.draw;
@@ -47832,27 +49394,36 @@ var StaticTextDefinition = function () {
           text: desc(def, 'text')
         }
       }
     };
     return def;
   }.call(this);
 var TextFieldDefinition = function () {
     var htmlParser = document.createElement('p');
-    var measureCtx = document.createElement('canvas').getContext('kanvas-2d');
-    function parseHtml(val, initialFormat) {
+    var measureCtx = document.createElement('canvas').getContext('2d');
+    function TextLine(y) {
+      this.x = 0;
+      this.width = 0;
+      this.y = y;
+      this.height = 0;
+      this.leading = 0;
+      this.runs = [];
+      this.largestFormat = null;
+    }
+    function parseHtml(val, initialFormat, multiline) {
       htmlParser.innerHTML = val;
       var rootElement = htmlParser.childNodes.length !== 1 ? htmlParser : htmlParser.childNodes[0];
       var content = {
           text: '',
           htmlText: val,
           tree: createTrunk(initialFormat)
         };
       if (rootElement.nodeType === 3) {
-        convertNode(rootElement, content.tree.children[0].children, content);
+        convertNode(rootElement, content.tree.children[0].children, content, multiline);
         return content;
       }
       var initialNodeList = [
           rootElement
         ];
       var attributes;
       var format;
       var key;
@@ -47868,17 +49439,17 @@ var TextFieldDefinition = function () {
       if (initialNodeList.length == 1 && rootElement.localName.toUpperCase() == 'FONT') {
         attributes = extractAttributes(rootElement);
         format = content.tree.children[0].format;
         for (key in attributes) {
           format[key] = attributes[key];
         }
         initialNodeList = rootElement.childNodes;
       }
-      convertNodeList(initialNodeList, content.tree.children[0].children, content);
+      convertNodeList(initialNodeList, content.tree.children[0].children, content, multiline);
       return content;
     }
     function createTrunk(initialFormat) {
       var trunk = {
           type: 'P',
           format: {
             ALIGN: initialFormat.align
           },
@@ -47906,17 +49477,17 @@ var TextFieldDefinition = function () {
         'I': true,
         'FONT': true,
         'TEXTFORMAT': true,
         'U': true,
         'A': true,
         'IMG': true,
         'SPAN': true
       };
-    function convertNode(input, destinationList, content) {
+    function convertNode(input, destinationList, content, multiline) {
       if (!(input.nodeType === 1 || input.nodeType === 3) || input.prefix) {
         return;
       }
       var node;
       if (input.nodeType === 3) {
         var text = input.textContent;
         node = {
           type: 'text',
@@ -47924,33 +49495,33 @@ var TextFieldDefinition = function () {
           format: null,
           children: null
         };
         content.text += text;
         destinationList.push(node);
         return;
       }
       var nodeType = input.localName.toUpperCase();
-      if (!knownNodeTypes[nodeType]) {
-        convertNodeList(input.childNodes, destinationList, content);
+      if (!knownNodeTypes[nodeType] || multiline === false && (nodeType === 'P' || nodeType === 'BR')) {
+        convertNodeList(input.childNodes, destinationList, content, multiline);
         return;
       }
       node = {
         type: nodeType,
         text: null,
         format: extractAttributes(input),
         children: []
       };
-      convertNodeList(input.childNodes, node.children, content);
+      convertNodeList(input.childNodes, node.children, content, multiline);
       destinationList.push(node);
     }
-    function convertNodeList(from, to, content) {
+    function convertNodeList(from, to, content, multiline) {
       var childCount = from.length;
       for (var i = 0; i < childCount; i++) {
-        convertNode(from[i], to, content);
+        convertNode(from[i], to, content, multiline);
       }
     }
     function extractAttributes(node) {
       var attributesList = node.attributes;
       var attributesMap = {};
       for (var i = 0; i < attributesList.length; i++) {
         var attr = attributesList[i];
         if (attr.prefix) {
@@ -47959,29 +49530,31 @@ var TextFieldDefinition = function () {
         attributesMap[attr.localName.toUpperCase()] = attr.value;
       }
       return attributesMap;
     }
     function collectRuns(node, state) {
       var formatNode = false;
       var blockNode = false;
       switch (node.type) {
+      case 'plain-text':
+        for (var i = 0; i < node.lines.length; i++) {
+          addRunsForText(state, node.lines[i]);
+          finishLine(state);
+        }
+        return;
       case 'text':
         addRunsForText(state, node.text);
         return;
       case 'BR':
-        if (state.multiline) {
-          finishLine(state);
-        }
+        finishLine(state);
         return;
       case 'LI':
       case 'P':
-        if (state.multiline) {
-          finishLine(state);
-        }
+        finishLine(state);
         pushFormat(state, node);
         blockNode = true;
         break;
       case 'B':
       case 'I':
       case 'FONT':
       case 'TEXTFORMAT':
         pushFormat(state, node);
@@ -47995,40 +49568,40 @@ var TextFieldDefinition = function () {
       }
       for (var i = 0; i < node.children.length; i++) {
         var child = node.children[i];
         collectRuns(child, state);
       }
       if (formatNode) {
         popFormat(state);
       }
-      if (blockNode && state.multiline) {
+      if (blockNode) {
         finishLine(state);
       }
     }
     var WRAP_OPPORTUNITIES = {
         ' ': true,
         '.': true,
         '-': true,
         '\t': true
       };
     function addRunsForText(state, text) {
       if (!text) {
         return;
       }
-      if (!(state.wordWrap && state.multiline)) {
+      if (!state.wordWrap) {
         addTextRun(state, text, state.ctx.measureText(text).width);
         return;
       }
       while (text.length) {
         var width = state.ctx.measureText(text).width;
-        var availableWidth = state.w - state.x;
+        var availableWidth = state.w - state.line.width;
         if (availableWidth <= 0) {
           finishLine(state);
-          availableWidth = state.w - state.x;
+          availableWidth = state.w - state.line.width;
         }
         if (width <= availableWidth) {
           addTextRun(state, text, width);
           break;
         } else {
           var offset = text.length / width * availableWidth | 0;
           while (state.ctx.measureText(text.substr(0, offset)).width < availableWidth && offset < text.length) {
             offset++;
@@ -48037,17 +49610,17 @@ var TextFieldDefinition = function () {
           while (wrapOffset > -1) {
             if (WRAP_OPPORTUNITIES[text[wrapOffset]]) {
               wrapOffset++;
               break;
             }
             wrapOffset--;
           }
           if (wrapOffset === -1) {
-            if (state.x > 0) {
+            if (state.line.width > 0) {
               finishLine(state);
               continue;
             }
             while (state.ctx.measureText(text.substr(0, offset)).width > availableWidth) {
               offset--;
             }
             if (offset === 0) {
               offset = 1;
@@ -48060,119 +49633,124 @@ var TextFieldDefinition = function () {
           if (state.wordWrap) {
             finishLine(state);
           }
           text = text.substr(wrapOffset);
         }
       }
     }
     function addTextRun(state, text, width) {
-      var size = state.currentFormat.size;
+      if (text.length === 0) {
+        return;
+      }
+      var line = state.line;
+      var format = state.currentFormat;
+      var size = format.size;
       var run = {
           type: 't',
           text: text,
-          x: state.x,
-          y: 0,
-          size: size
+          x: line.width
         };
       state.runs.push(run);
-      state.line.push(run);
-      state.x += width;
-      if (size > state.lineHeight) {
-        state.lineHeight = size;
+      state.line.runs.push(run);
+      line.width += width | 0;
+      if (line.leading === 0 && format.leading > line.leading) {
+        line.leading = format.leading;
+      }
+      if (!line.largestFormat || size > line.largestFormat.size) {
+        line.largestFormat = format;
       }
     }
     function finishLine(state) {
-      if (state.lineHeight === 0) {
+      var line = state.line;
+      if (line.runs.length === 0) {
         return;
       }
-      var fontLeading = state.currentFormat.metrics ? state.currentFormat.metrics.leading : 0;
-      state.y += state.lineHeight - fontLeading;
-      var y = state.y;
-      var runs = state.line;
-      var run, i;
-      for (i = runs.length; i--;) {
-        run = runs[i];
-        run.y = y;
+      var runs = line.runs;
+      var format = line.largestFormat;
+      var baselinePos = line.y + format.font._metrics.ascent * format.size;
+      for (var i = runs.length; i--;) {
+        runs[i].y = baselinePos;
       }
       var align = (state.currentFormat.align || '').toLowerCase();
       if (state.combinedAlign === null) {
         state.combinedAlign = align;
       } else if (state.combinedAlign !== align) {
         state.combinedAlign = 'mixed';
       }
       if (align === 'center' || align === 'right') {
-        var offset = Math.max(state.w - state.x, 0);
+        var offset = Math.max(state.w - line.width, 0);
         if (align === 'center') {
           offset >>= 1;
         }
         for (i = runs.length; i--;) {
           runs[i].x += offset;
         }
       }
-      runs.length = 0;
-      state.maxLineWidth = Math.max(state.maxLineWidth, state.x);
-      state.x = 0;
-      state.y += state.currentFormat.leading + 2;
-      state.lineHeight = 0;
+      line.height = format.font._metrics.height * format.size + line.leading | 0;
+      state.maxLineWidth = Math.max(state.maxLineWidth, line.width);
+      state.lines.push(line);
+      state.line = new TextLine(line.y + line.height);
     }
     function pushFormat(state, node) {
       var attributes = node.format;
       var format = Object.create(state.formats[state.formats.length - 1]);
-      var metricsChanged = false;
+      var fontChanged = false;
       switch (node.type) {
       case 'P':
         if (attributes.ALIGN === format.align) {
           return;
         }
         format.align = attributes.ALIGN;
         break;
       case 'B':
         format.bold = true;
+        fontChanged = true;
         break;
       case 'I':
         format.italic = true;
+        fontChanged = true;
         break;
       case 'FONT':
         if (attributes.COLOR !== undefined) {
           format.color = attributes.COLOR;
         }
         if (attributes.FACE !== undefined) {
-          format.face = convertFontFamily(attributes.FACE, true);
-          metricsChanged = true;
+          format.face = attributes.FACE;
+          fontChanged = true;
         }
         if (attributes.SIZE !== undefined) {
           format.size = parseFloat(attributes.SIZE);
-          metricsChanged = true;
         }
         if (attributes.LETTERSPACING !== undefined) {
           format.letterspacing = parseFloat(attributes.LETTERSPACING);
         }
         if (attributes.KERNING !== undefined) {
           format.kerning = attributes.KERNING && true;
         }
+      case 'TEXTFORMAT':
         if (attributes.LEADING !== undefined) {
           format.leading = parseFloat(attributes.LEADING);
         }
-      case 'TEXTFORMAT':
         if (attributes.INDENT !== undefined) {
-          state.x += attributes.INDENT;
+          state.line.x = attributes.INDENT;
+          state.line.width += attributes.INDENT | 0;
         }
         break;
       default:
         warning('Unknown format node encountered: ' + node.type);
         return;
       }
       if (state.textColor !== null) {
         format.color = rgbIntAlphaToStr(state.textColor, 1);
       }
+      if (fontChanged) {
+        resolveFont(format, state.embedFonts);
+      }
       format.str = makeFormatString(format);
-      if (metricsChanged) {
-        updateFontMetrics(format);
-      }
       state.formats.push(format);
       state.runs.push({
         type: 'f',
         format: format
       });
       state.currentFormat = format;
       state.ctx.font = format.str;
     }
@@ -48188,52 +49766,41 @@ var TextFieldDefinition = function () {
     function makeFormatString(format) {
       var boldItalic = '';
       if (format.italic) {
         boldItalic += 'italic';
       }
       if (format.bold) {
         boldItalic += ' bold';
       }
-      return boldItalic + format.size + 'px ' + format.face;
-    }
-    function convertFontFamily(face, translateToUnique) {
-      var family;
-      if (face.indexOf('_') === 0) {
-        if (face.indexOf('_sans') === 0) {
-          family = 'sans-serif';
-        } else if (face.indexOf('_serif') === 0) {
-          family = 'serif';
-        } else if (face.indexOf('_typewriter') === 0) {
-          family = 'monospace';
-        }
-      } else if (translateToUnique) {
-        var font = flash.text.Font.class.native.static._findFont(function (f) {
-            return f._fontName === face;
-          });
-        if (font) {
-          family = font._uniqueName;
-        }
-      }
-      return family || face;
-    }
-    function updateFontMetrics(format) {
-      var font = flash.text.Font.class.native.static._findFont(function (f) {
-          return f._uniqueName === format.face;
-        });
-      var metrics = font && font._metrics;
-      if (!metrics) {
-        format.metrics = null;
-        return;
-      }
-      format.metrics = {
-        leading: format.size * metrics.leading,
-        ascent: format.size * metrics.ascent,
-        descent: format.size * metrics.descent
-      };
+      return boldItalic + ' ' + format.size + 'px ' + (format.font._uniqueName || format.font._fontName);
+    }
+    function resolveFont(format, embedded) {
+      var face = format.face.toLowerCase();
+      if (face === '_sans') {
+        face = 'sans-serif';
+      } else if (face === '_serif') {
+        face = 'serif';
+      } else if (face === '_typewriter') {
+        face = 'monospace';
+      }
+      var style;
+      if (format.bold) {
+        if (format.italic) {
+          style = 'boldItalic';
+        } else {
+          style = 'bold';
+        }
+      } else if (format.italic) {
+        style = 'italic';
+      } else {
+        style = 'regular';
+      }
+      var font = FontDefinition.getFont(face, style, embedded);
+      format.font = font;
     }
     var def = {
         __class__: 'flash.text.TextField',
         initialize: function () {
           var initialFormat = this._defaultTextFormat = {
               align: 'LEFT',
               face: 'serif',
               size: 12,
@@ -48241,16 +49808,20 @@ var TextFieldDefinition = function () {
               kerning: 0,
               color: 0,
               leading: 0
             };
           this._type = 'dynamic';
           this._selectable = true;
           this._textWidth = 0;
           this._textHeight = 0;
+          this._scrollV = 1;
+          this._maxScrollV = 1;
+          this._bottomScrollV = 1;
+          this._lines = [];
           this._embedFonts = false;
           this._autoSize = 'none';
           this._wordWrap = false;
           this._multiline = false;
           this._condenseWhite = false;
           this._background = false;
           this._border = false;
           this._backgroundColor = 16777215;
@@ -48264,16 +49835,17 @@ var TextFieldDefinition = function () {
             yMin: 0,
             xMax: 2000,
             yMax: 2000
           };
           var s = this.symbol;
           if (!s) {
             this._currentTransform.tx -= 40;
             this._currentTransform.ty -= 40;
+            resolveFont(initialFormat, false);
             this.text = '';
             return;
           }
           var tag = s.tag;
           var bbox = tag.bbox;
           this._currentTransform.tx += bbox.xMin;
           this._currentTransform.ty += bbox.yMin;
           this._bbox.xMax = bbox.xMax - bbox.xMin;
@@ -48283,36 +49855,40 @@ var TextFieldDefinition = function () {
             if (typeof initialFormat.leading === 'number') {
               initialFormat.leading = tag.leading / 20;
             }
           }
           if (tag.hasColor) {
             initialFormat.color = rgbaObjToStr(tag.color);
           }
           if (tag.hasFont) {
-            initialFormat.face = convertFontFamily(tag.font);
-          }
-          initialFormat.str = makeFormatString(initialFormat);
+            var font = FontDefinition.getFontByUniqueName(tag.font);
+            initialFormat.font = font;
+            initialFormat.face = font._fontName;
+            initialFormat.bold = font.symbol.bold;
+            initialFormat.italic = font.symbol.italic;
+            initialFormat.str = makeFormatString(initialFormat);
+          }
+          this._embedFonts = !(!tag.useOutlines);
           switch (tag.align) {
           case 1:
             initialFormat.align = 'right';
             break;
           case 2:
             initialFormat.align = 'center';
             break;
           case 3:
             initialFormat.align = 'justified';
             break;
           default:
           }
           this._selectable = !tag.noSelect;
           this._multiline = !(!tag.multiline);
           this._wordWrap = !(!tag.wordWrap);
           this._border = !(!tag.border);
-          updateFontMetrics(initialFormat);
           if (tag.initialText) {
             if (tag.html) {
               this.htmlText = tag.initialText;
             } else {
               this.text = tag.initialText;
             }
           } else {
             this.text = '';
@@ -48333,43 +49909,51 @@ var TextFieldDefinition = function () {
           var bounds = this._bbox;
           var width = bounds.xMax / 20;
           var height = bounds.yMax / 20;
           if (width <= 0 || height <= 0) {
             return;
           }
           ctx.save();
           ctx.beginPath();
-          ctx.rect(0, 0, width, height);
+          ctx.rect(0, 0, width + 1, height + 1);
           ctx.clip();
           if (this._background) {
             colorTransform.setFillStyle(ctx, this._backgroundColorStr);
             ctx.fill();
           }
           if (this._border) {
             colorTransform.setStrokeStyle(ctx, this._borderColorStr);
             ctx.lineCap = 'square';
             ctx.lineWidth = 1;
-            ctx.strokeRect(0.5, 0.5, width - 1 | 0, height - 1 | 0);
+            ctx.strokeRect(0.5, 0.5, width | 0, height | 0);
           }
           ctx.closePath();
+          if (this._lines.length === 0) {
+            ctx.restore();
+            return;
+          }
           ctx.translate(2, 2);
           ctx.save();
           colorTransform.setAlpha(ctx);
           var runs = this._content.textruns;
+          var offsetY = this._lines[this._scrollV - 1].y;
           for (var i = 0; i < runs.length; i++) {
             var run = runs[i];
             if (run.type === 'f') {
               ctx.restore();
               ctx.font = run.format.str;
               colorTransform.setFillStyle(ctx, run.format.color);
               ctx.save();
               colorTransform.setAlpha(ctx);
             } else {
-              ctx.fillText(run.text, run.x - this._drawingOffsetH, run.y);
+              if (run.y < offsetY) {
+                continue;
+              }
+              ctx.fillText(run.text, run.x - this._drawingOffsetH, run.y - offsetY);
             }
           }
           ctx.restore();
           ctx.restore();
         },
         invalidateDimensions: function () {
           this._invalidate();
           this._invalidateBounds();
@@ -48380,50 +49964,64 @@ var TextFieldDefinition = function () {
           return this._getTransformedRect(this._getContentBounds(), targetCoordSpace);
         },
         ensureDimensions: function () {
           if (this._dimensionsValid) {
             return;
           }
           var bounds = this._bbox;
           var initialFormat = this._defaultTextFormat;
+          resolveFont(initialFormat, this._embedFonts);
           var firstRun = {
               type: 'f',
               format: initialFormat
             };
           var width = Math.max(bounds.xMax / 20 - 4, 1);
+          var height = Math.max(bounds.yMax / 20 - 4, 1);
           var state = {
               ctx: measureCtx,
-              y: 0,
-              x: 0,
               w: width,
-              line: [],
-              lineHeight: 0,
+              h: height,
               maxLineWidth: 0,
               formats: [
                 initialFormat
               ],
               currentFormat: initialFormat,
+              line: new TextLine(0),
+              lines: [],
               runs: [
                 firstRun
               ],
-              multiline: this._multiline,
               wordWrap: this._wordWrap,
               combinedAlign: null,
-              textColor: this._textColor
+              textColor: this._textColor,
+              embedFonts: this._embedFonts
             };
           collectRuns(this._content.tree, state);
-          if (!state.multiline) {
-            finishLine(state);