browser/extensions/shumway/content/shumway-worker.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright 2013 Mozilla Foundation
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 // This file is automatically generated
michael@0 18
michael@0 19 (function (global) {
michael@0 20 if (global.DataView)
michael@0 21 return;
michael@0 22 if (!global.ArrayBuffer)
michael@0 23 fail('ArrayBuffer not supported');
michael@0 24 if (!Object.defineProperties)
michael@0 25 fail('This module requires ECMAScript 5');
michael@0 26 var nativele = new Int8Array(new Int32Array([
michael@0 27 1
michael@0 28 ]).buffer)[0] === 1;
michael@0 29 var temp = new Uint8Array(8);
michael@0 30 global.DataView = function DataView(buffer, offset, length) {
michael@0 31 if (!(buffer instanceof ArrayBuffer))
michael@0 32 fail('Bad ArrayBuffer');
michael@0 33 offset = offset || 0;
michael@0 34 length = length || buffer.byteLength - offset;
michael@0 35 if (offset < 0 || length < 0 || offset + length > buffer.byteLength)
michael@0 36 fail('Illegal offset and/or length');
michael@0 37 Object.defineProperties(this, {
michael@0 38 buffer: {
michael@0 39 value: buffer,
michael@0 40 enumerable: false,
michael@0 41 writable: false,
michael@0 42 configurable: false
michael@0 43 },
michael@0 44 byteOffset: {
michael@0 45 value: offset,
michael@0 46 enumerable: false,
michael@0 47 writable: false,
michael@0 48 configurable: false
michael@0 49 },
michael@0 50 byteLength: {
michael@0 51 value: length,
michael@0 52 enumerable: false,
michael@0 53 writable: false,
michael@0 54 configurable: false
michael@0 55 },
michael@0 56 _bytes: {
michael@0 57 value: new Uint8Array(buffer, offset, length),
michael@0 58 enumerable: false,
michael@0 59 writable: false,
michael@0 60 configurable: false
michael@0 61 }
michael@0 62 });
michael@0 63 };
michael@0 64 global.DataView.prototype = {
michael@0 65 constructor: DataView,
michael@0 66 getInt8: function getInt8(offset) {
michael@0 67 return get(this, Int8Array, 1, offset);
michael@0 68 },
michael@0 69 getUint8: function getUint8(offset) {
michael@0 70 return get(this, Uint8Array, 1, offset);
michael@0 71 },
michael@0 72 getInt16: function getInt16(offset, le) {
michael@0 73 return get(this, Int16Array, 2, offset, le);
michael@0 74 },
michael@0 75 getUint16: function getUint16(offset, le) {
michael@0 76 return get(this, Uint16Array, 2, offset, le);
michael@0 77 },
michael@0 78 getInt32: function getInt32(offset, le) {
michael@0 79 return get(this, Int32Array, 4, offset, le);
michael@0 80 },
michael@0 81 getUint32: function getUint32(offset, le) {
michael@0 82 return get(this, Uint32Array, 4, offset, le);
michael@0 83 },
michael@0 84 getFloat32: function getFloat32(offset, le) {
michael@0 85 return get(this, Float32Array, 4, offset, le);
michael@0 86 },
michael@0 87 getFloat64: function getFloat32(offset, le) {
michael@0 88 return get(this, Float64Array, 8, offset, le);
michael@0 89 },
michael@0 90 setInt8: function setInt8(offset, value) {
michael@0 91 set(this, Int8Array, 1, offset, value);
michael@0 92 },
michael@0 93 setUint8: function setUint8(offset, value) {
michael@0 94 set(this, Uint8Array, 1, offset, value);
michael@0 95 },
michael@0 96 setInt16: function setInt16(offset, value, le) {
michael@0 97 set(this, Int16Array, 2, offset, value, le);
michael@0 98 },
michael@0 99 setUint16: function setUint16(offset, value, le) {
michael@0 100 set(this, Uint16Array, 2, offset, value, le);
michael@0 101 },
michael@0 102 setInt32: function setInt32(offset, value, le) {
michael@0 103 set(this, Int32Array, 4, offset, value, le);
michael@0 104 },
michael@0 105 setUint32: function setUint32(offset, value, le) {
michael@0 106 set(this, Uint32Array, 4, offset, value, le);
michael@0 107 },
michael@0 108 setFloat32: function setFloat32(offset, value, le) {
michael@0 109 set(this, Float32Array, 4, offset, value, le);
michael@0 110 },
michael@0 111 setFloat64: function setFloat64(offset, value, le) {
michael@0 112 set(this, Float64Array, 8, offset, value, le);
michael@0 113 }
michael@0 114 };
michael@0 115 function get(view, type, size, offset, le) {
michael@0 116 if (offset === undefined)
michael@0 117 fail('Missing required offset argument');
michael@0 118 if (offset < 0 || offset + size > view.byteLength)
michael@0 119 fail('Invalid index: ' + offset);
michael@0 120 if (size === 1 || !(!le) === nativele) {
michael@0 121 if ((view.byteOffset + offset) % size === 0)
michael@0 122 return new type(view.buffer, view.byteOffset + offset, 1)[0];
michael@0 123 else {
michael@0 124 for (var i = 0; i < size; i++)
michael@0 125 temp[i] = view._bytes[offset + i];
michael@0 126 return new type(temp.buffer)[0];
michael@0 127 }
michael@0 128 } else {
michael@0 129 for (var i = 0; i < size; i++)
michael@0 130 temp[size - i - 1] = view._bytes[offset + i];
michael@0 131 return new type(temp.buffer)[0];
michael@0 132 }
michael@0 133 }
michael@0 134 function set(view, type, size, offset, value, le) {
michael@0 135 if (offset === undefined)
michael@0 136 fail('Missing required offset argument');
michael@0 137 if (value === undefined)
michael@0 138 fail('Missing required value argument');
michael@0 139 if (offset < 0 || offset + size > view.byteLength)
michael@0 140 fail('Invalid index: ' + offset);
michael@0 141 if (size === 1 || !(!le) === nativele) {
michael@0 142 if ((view.byteOffset + offset) % size === 0) {
michael@0 143 new type(view.buffer, view.byteOffset + offset, 1)[0] = value;
michael@0 144 } else {
michael@0 145 new type(temp.buffer)[0] = value;
michael@0 146 for (var i = 0; i < size; i++)
michael@0 147 view._bytes[i + offset] = temp[i];
michael@0 148 }
michael@0 149 } else {
michael@0 150 new type(temp.buffer)[0] = value;
michael@0 151 for (var i = 0; i < size; i++)
michael@0 152 view._bytes[offset + i] = temp[size - 1 - i];
michael@0 153 }
michael@0 154 }
michael@0 155 function fail(msg) {
michael@0 156 throw new Error(msg);
michael@0 157 }
michael@0 158 }(this));
michael@0 159 var create = Object.create;
michael@0 160 var defineProperty = Object.defineProperty;
michael@0 161 var keys = Object.keys;
michael@0 162 var isArray = Array.isArray;
michael@0 163 var fromCharCode = String.fromCharCode;
michael@0 164 var logE = Math.log;
michael@0 165 var max = Math.max;
michael@0 166 var min = Math.min;
michael@0 167 var pow = Math.pow;
michael@0 168 var push = Array.prototype.push;
michael@0 169 var slice = Array.prototype.slice;
michael@0 170 var splice = Array.prototype.splice;
michael@0 171 function fail(msg, context) {
michael@0 172 throw new Error((context ? context + ': ' : '') + msg);
michael@0 173 }
michael@0 174 function assert(cond, msg, context) {
michael@0 175 if (!cond)
michael@0 176 fail(msg, context);
michael@0 177 }
michael@0 178 function scriptProperties(namespace, props) {
michael@0 179 return props.reduce(function (o, p) {
michael@0 180 o[p] = namespace + ' ' + p;
michael@0 181 return o;
michael@0 182 }, {});
michael@0 183 }
michael@0 184 function cloneObject(obj) {
michael@0 185 var clone = Object.create(null);
michael@0 186 for (var prop in obj)
michael@0 187 clone[prop] = obj[prop];
michael@0 188 return clone;
michael@0 189 }
michael@0 190 function sortNumeric(a, b) {
michael@0 191 return a - b;
michael@0 192 }
michael@0 193 function sortByZindex(a, b) {
michael@0 194 return a._zindex - b._zindex;
michael@0 195 }
michael@0 196 function rgbaObjToStr(color) {
michael@0 197 return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
michael@0 198 }
michael@0 199 function rgbIntAlphaToStr(color, alpha) {
michael@0 200 color |= 0;
michael@0 201 if (alpha >= 1) {
michael@0 202 var colorStr = color.toString(16);
michael@0 203 while (colorStr.length < 6) {
michael@0 204 colorStr = '0' + colorStr;
michael@0 205 }
michael@0 206 return '#' + colorStr;
michael@0 207 }
michael@0 208 var red = color >> 16 & 255;
michael@0 209 var green = color >> 8 & 255;
michael@0 210 var blue = color & 255;
michael@0 211 return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')';
michael@0 212 }
michael@0 213 function argbUintToStr(argb) {
michael@0 214 return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')';
michael@0 215 }
michael@0 216 (function functionNameSupport() {
michael@0 217 if (eval('function t() {} t.name === \'t\'')) {
michael@0 218 return;
michael@0 219 }
michael@0 220 Object.defineProperty(Function.prototype, 'name', {
michael@0 221 get: function () {
michael@0 222 if (this.__name) {
michael@0 223 return this.__name;
michael@0 224 }
michael@0 225 var m = /function\s([^\(]+)/.exec(this.toString());
michael@0 226 var name = m && m[1] !== 'anonymous' ? m[1] : null;
michael@0 227 this.__name = name;
michael@0 228 return name;
michael@0 229 },
michael@0 230 configurable: true,
michael@0 231 enumerable: false
michael@0 232 });
michael@0 233 }());
michael@0 234 var randomStyleCache;
michael@0 235 var nextStyle = 0;
michael@0 236 function randomStyle() {
michael@0 237 if (!randomStyleCache) {
michael@0 238 randomStyleCache = [
michael@0 239 '#ff5e3a',
michael@0 240 '#ff9500',
michael@0 241 '#ffdb4c',
michael@0 242 '#87fc70',
michael@0 243 '#52edc7',
michael@0 244 '#1ad6fd',
michael@0 245 '#c644fc',
michael@0 246 '#ef4db6',
michael@0 247 '#4a4a4a',
michael@0 248 '#dbddde',
michael@0 249 '#ff3b30',
michael@0 250 '#ff9500',
michael@0 251 '#ffcc00',
michael@0 252 '#4cd964',
michael@0 253 '#34aadc',
michael@0 254 '#007aff',
michael@0 255 '#5856d6',
michael@0 256 '#ff2d55',
michael@0 257 '#8e8e93',
michael@0 258 '#c7c7cc',
michael@0 259 '#5ad427',
michael@0 260 '#c86edf',
michael@0 261 '#d1eefc',
michael@0 262 '#e0f8d8',
michael@0 263 '#fb2b69',
michael@0 264 '#f7f7f7',
michael@0 265 '#1d77ef',
michael@0 266 '#d6cec3',
michael@0 267 '#55efcb',
michael@0 268 '#ff4981',
michael@0 269 '#ffd3e0',
michael@0 270 '#f7f7f7',
michael@0 271 '#ff1300',
michael@0 272 '#1f1f21',
michael@0 273 '#bdbec2',
michael@0 274 '#ff3a2d'
michael@0 275 ];
michael@0 276 }
michael@0 277 return randomStyleCache[nextStyle++ % randomStyleCache.length];
michael@0 278 }
michael@0 279 (function PromiseClosure() {
michael@0 280 var global = Function('return this')();
michael@0 281 if (global.Promise) {
michael@0 282 if (typeof global.Promise.all !== 'function') {
michael@0 283 global.Promise.all = function (iterable) {
michael@0 284 var count = 0, results = [], resolve, reject;
michael@0 285 var promise = new global.Promise(function (resolve_, reject_) {
michael@0 286 resolve = resolve_;
michael@0 287 reject = reject_;
michael@0 288 });
michael@0 289 iterable.forEach(function (p, i) {
michael@0 290 count++;
michael@0 291 p.then(function (result) {
michael@0 292 results[i] = result;
michael@0 293 count--;
michael@0 294 if (count === 0) {
michael@0 295 resolve(results);
michael@0 296 }
michael@0 297 }, reject);
michael@0 298 });
michael@0 299 if (count === 0) {
michael@0 300 resolve(results);
michael@0 301 }
michael@0 302 return promise;
michael@0 303 };
michael@0 304 }
michael@0 305 if (typeof global.Promise.resolve !== 'function') {
michael@0 306 global.Promise.resolve = function (x) {
michael@0 307 return new global.Promise(function (resolve) {
michael@0 308 resolve(x);
michael@0 309 });
michael@0 310 };
michael@0 311 }
michael@0 312 return;
michael@0 313 }
michael@0 314 function getDeferred(C) {
michael@0 315 if (typeof C !== 'function') {
michael@0 316 throw new TypeError('Invalid deferred constructor');
michael@0 317 }
michael@0 318 var resolver = createDeferredConstructionFunctions();
michael@0 319 var promise = new C(resolver);
michael@0 320 var resolve = resolver.resolve;
michael@0 321 if (typeof resolve !== 'function') {
michael@0 322 throw new TypeError('Invalid resolve construction function');
michael@0 323 }
michael@0 324 var reject = resolver.reject;
michael@0 325 if (typeof reject !== 'function') {
michael@0 326 throw new TypeError('Invalid reject construction function');
michael@0 327 }
michael@0 328 return {
michael@0 329 promise: promise,
michael@0 330 resolve: resolve,
michael@0 331 reject: reject
michael@0 332 };
michael@0 333 }
michael@0 334 function updateDeferredFromPotentialThenable(x, deferred) {
michael@0 335 if (typeof x !== 'object' || x === null) {
michael@0 336 return false;
michael@0 337 }
michael@0 338 try {
michael@0 339 var then = x.then;
michael@0 340 if (typeof then !== 'function') {
michael@0 341 return false;
michael@0 342 }
michael@0 343 var thenCallResult = then.call(x, deferred.resolve, deferred.reject);
michael@0 344 } catch (e) {
michael@0 345 var reject = deferred.reject;
michael@0 346 reject(e);
michael@0 347 }
michael@0 348 return true;
michael@0 349 }
michael@0 350 function isPromise(x) {
michael@0 351 return typeof x === 'object' && x !== null && typeof x.promiseStatus !== 'undefined';
michael@0 352 }
michael@0 353 function rejectPromise(promise, reason) {
michael@0 354 if (promise.promiseStatus !== 'unresolved') {
michael@0 355 return;
michael@0 356 }
michael@0 357 var reactions = promise.rejectReactions;
michael@0 358 promise.result = reason;
michael@0 359 promise.resolveReactions = undefined;
michael@0 360 promise.rejectReactions = undefined;
michael@0 361 promise.promiseStatus = 'has-rejection';
michael@0 362 triggerPromiseReactions(reactions, reason);
michael@0 363 }
michael@0 364 function resolvePromise(promise, resolution) {
michael@0 365 if (promise.promiseStatus !== 'unresolved') {
michael@0 366 return;
michael@0 367 }
michael@0 368 var reactions = promise.resolveReactions;
michael@0 369 promise.result = resolution;
michael@0 370 promise.resolveReactions = undefined;
michael@0 371 promise.rejectReactions = undefined;
michael@0 372 promise.promiseStatus = 'has-resolution';
michael@0 373 triggerPromiseReactions(reactions, resolution);
michael@0 374 }
michael@0 375 function triggerPromiseReactions(reactions, argument) {
michael@0 376 for (var i = 0; i < reactions.length; i++) {
michael@0 377 queueMicrotask({
michael@0 378 reaction: reactions[i],
michael@0 379 argument: argument
michael@0 380 });
michael@0 381 }
michael@0 382 }
michael@0 383 function queueMicrotask(task) {
michael@0 384 if (microtasksQueue.length === 0) {
michael@0 385 setTimeout(handleMicrotasksQueue, 0);
michael@0 386 }
michael@0 387 microtasksQueue.push(task);
michael@0 388 }
michael@0 389 function executePromiseReaction(reaction, argument) {
michael@0 390 var deferred = reaction.deferred;
michael@0 391 var handler = reaction.handler;
michael@0 392 var handlerResult, updateResult;
michael@0 393 try {
michael@0 394 handlerResult = handler(argument);
michael@0 395 } catch (e) {
michael@0 396 var reject = deferred.reject;
michael@0 397 return reject(e);
michael@0 398 }
michael@0 399 if (handlerResult === deferred.promise) {
michael@0 400 var reject = deferred.reject;
michael@0 401 return reject(new TypeError('Self resolution'));
michael@0 402 }
michael@0 403 try {
michael@0 404 updateResult = updateDeferredFromPotentialThenable(handlerResult, deferred);
michael@0 405 if (!updateResult) {
michael@0 406 var resolve = deferred.resolve;
michael@0 407 return resolve(handlerResult);
michael@0 408 }
michael@0 409 } catch (e) {
michael@0 410 var reject = deferred.reject;
michael@0 411 return reject(e);
michael@0 412 }
michael@0 413 }
michael@0 414 var microtasksQueue = [];
michael@0 415 function handleMicrotasksQueue() {
michael@0 416 while (microtasksQueue.length > 0) {
michael@0 417 var task = microtasksQueue[0];
michael@0 418 try {
michael@0 419 executePromiseReaction(task.reaction, task.argument);
michael@0 420 } catch (e) {
michael@0 421 if (typeof Promise.onerror === 'function') {
michael@0 422 Promise.onerror(e);
michael@0 423 }
michael@0 424 }
michael@0 425 microtasksQueue.shift();
michael@0 426 }
michael@0 427 }
michael@0 428 function throwerFunction(e) {
michael@0 429 throw e;
michael@0 430 }
michael@0 431 function identityFunction(x) {
michael@0 432 return x;
michael@0 433 }
michael@0 434 function createRejectPromiseFunction(promise) {
michael@0 435 return function (reason) {
michael@0 436 rejectPromise(promise, reason);
michael@0 437 };
michael@0 438 }
michael@0 439 function createResolvePromiseFunction(promise) {
michael@0 440 return function (resolution) {
michael@0 441 resolvePromise(promise, resolution);
michael@0 442 };
michael@0 443 }
michael@0 444 function createDeferredConstructionFunctions() {
michael@0 445 var fn = function (resolve, reject) {
michael@0 446 fn.resolve = resolve;
michael@0 447 fn.reject = reject;
michael@0 448 };
michael@0 449 return fn;
michael@0 450 }
michael@0 451 function createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler) {
michael@0 452 return function (x) {
michael@0 453 if (x === promise) {
michael@0 454 return rejectionHandler(new TypeError('Self resolution'));
michael@0 455 }
michael@0 456 var cstr = promise.promiseConstructor;
michael@0 457 if (isPromise(x)) {
michael@0 458 var xConstructor = x.promiseConstructor;
michael@0 459 if (xConstructor === cstr) {
michael@0 460 return x.then(fulfillmentHandler, rejectionHandler);
michael@0 461 }
michael@0 462 }
michael@0 463 var deferred = getDeferred(cstr);
michael@0 464 var updateResult = updateDeferredFromPotentialThenable(x, deferred);
michael@0 465 if (updateResult) {
michael@0 466 var deferredPromise = deferred.promise;
michael@0 467 return deferredPromise.then(fulfillmentHandler, rejectionHandler);
michael@0 468 }
michael@0 469 return fulfillmentHandler(x);
michael@0 470 };
michael@0 471 }
michael@0 472 function createPromiseAllCountdownFunction(index, values, deferred, countdownHolder) {
michael@0 473 return function (x) {
michael@0 474 values[index] = x;
michael@0 475 countdownHolder.countdown--;
michael@0 476 if (countdownHolder.countdown === 0) {
michael@0 477 deferred.resolve(values);
michael@0 478 }
michael@0 479 };
michael@0 480 }
michael@0 481 function Promise(resolver) {
michael@0 482 if (typeof resolver !== 'function') {
michael@0 483 throw new TypeError('resolver is not a function');
michael@0 484 }
michael@0 485 var promise = this;
michael@0 486 if (typeof promise !== 'object') {
michael@0 487 throw new TypeError('Promise to initialize is not an object');
michael@0 488 }
michael@0 489 promise.promiseStatus = 'unresolved';
michael@0 490 promise.resolveReactions = [];
michael@0 491 promise.rejectReactions = [];
michael@0 492 promise.result = undefined;
michael@0 493 var resolve = createResolvePromiseFunction(promise);
michael@0 494 var reject = createRejectPromiseFunction(promise);
michael@0 495 try {
michael@0 496 var result = resolver(resolve, reject);
michael@0 497 } catch (e) {
michael@0 498 rejectPromise(promise, e);
michael@0 499 }
michael@0 500 promise.promiseConstructor = Promise;
michael@0 501 return promise;
michael@0 502 }
michael@0 503 Promise.all = function (iterable) {
michael@0 504 var deferred = getDeferred(this);
michael@0 505 var values = [];
michael@0 506 var countdownHolder = {
michael@0 507 countdown: 0
michael@0 508 };
michael@0 509 var index = 0;
michael@0 510 iterable.forEach(function (nextValue) {
michael@0 511 var nextPromise = this.cast(nextValue);
michael@0 512 var fn = createPromiseAllCountdownFunction(index, values, deferred, countdownHolder);
michael@0 513 nextPromise.then(fn, deferred.reject);
michael@0 514 index++;
michael@0 515 countdownHolder.countdown++;
michael@0 516 }, this);
michael@0 517 if (index === 0) {
michael@0 518 deferred.resolve(values);
michael@0 519 }
michael@0 520 return deferred.promise;
michael@0 521 };
michael@0 522 Promise.cast = function (x) {
michael@0 523 if (isPromise(x)) {
michael@0 524 return x;
michael@0 525 }
michael@0 526 var deferred = getDeferred(this);
michael@0 527 deferred.resolve(x);
michael@0 528 return deferred.promise;
michael@0 529 };
michael@0 530 Promise.reject = function (r) {
michael@0 531 var deferred = getDeferred(this);
michael@0 532 var rejectResult = deferred.reject(r);
michael@0 533 return deferred.promise;
michael@0 534 };
michael@0 535 Promise.resolve = function (x) {
michael@0 536 var deferred = getDeferred(this);
michael@0 537 var rejectResult = deferred.resolve(x);
michael@0 538 return deferred.promise;
michael@0 539 };
michael@0 540 Promise.prototype = {
michael@0 541 'catch': function (onRejected) {
michael@0 542 this.then(undefined, onRejected);
michael@0 543 },
michael@0 544 then: function (onFulfilled, onRejected) {
michael@0 545 var promise = this;
michael@0 546 if (!isPromise(promise)) {
michael@0 547 throw new TypeError('this is not a Promises');
michael@0 548 }
michael@0 549 var cstr = promise.promiseConstructor;
michael@0 550 var deferred = getDeferred(cstr);
michael@0 551 var rejectionHandler = typeof onRejected === 'function' ? onRejected : throwerFunction;
michael@0 552 var fulfillmentHandler = typeof onFulfilled === 'function' ? onFulfilled : identityFunction;
michael@0 553 var resolutionHandler = createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler);
michael@0 554 var resolveReaction = {
michael@0 555 deferred: deferred,
michael@0 556 handler: resolutionHandler
michael@0 557 };
michael@0 558 var rejectReaction = {
michael@0 559 deferred: deferred,
michael@0 560 handler: rejectionHandler
michael@0 561 };
michael@0 562 switch (promise.promiseStatus) {
michael@0 563 case 'unresolved':
michael@0 564 promise.resolveReactions.push(resolveReaction);
michael@0 565 promise.rejectReactions.push(rejectReaction);
michael@0 566 break;
michael@0 567 case 'has-resolution':
michael@0 568 var resolution = promise.result;
michael@0 569 queueMicrotask({
michael@0 570 reaction: resolveReaction,
michael@0 571 argument: resolution
michael@0 572 });
michael@0 573 break;
michael@0 574 case 'has-rejection':
michael@0 575 var rejection = promise.result;
michael@0 576 queueMicrotask({
michael@0 577 reaction: rejectReaction,
michael@0 578 argument: rejection
michael@0 579 });
michael@0 580 break;
michael@0 581 }
michael@0 582 return deferred.promise;
michael@0 583 }
michael@0 584 };
michael@0 585 global.Promise = Promise;
michael@0 586 }());
michael@0 587 var QuadTree = function (x, y, width, height, parent) {
michael@0 588 this.x = x | 0;
michael@0 589 this.y = y | 0;
michael@0 590 this.width = width | 0;
michael@0 591 this.height = height | 0;
michael@0 592 if (parent) {
michael@0 593 this.root = parent.root;
michael@0 594 this.parent = parent;
michael@0 595 this.level = parent.level + 1;
michael@0 596 } else {
michael@0 597 this.root = this;
michael@0 598 this.parent = null;
michael@0 599 this.level = 0;
michael@0 600 }
michael@0 601 this.reset();
michael@0 602 };
michael@0 603 QuadTree.prototype.reset = function () {
michael@0 604 this.stuckObjects = null;
michael@0 605 this.objects = null;
michael@0 606 this.nodes = [];
michael@0 607 };
michael@0 608 QuadTree.prototype._findIndex = function (xMin, xMax, yMin, yMax) {
michael@0 609 var midX = this.x + (this.width / 2 | 0);
michael@0 610 var midY = this.y + (this.height / 2 | 0);
michael@0 611 var top = yMin < midY && yMax < midY;
michael@0 612 var bottom = yMin > midY;
michael@0 613 if (xMin < midX && xMax < midX) {
michael@0 614 if (top) {
michael@0 615 return 1;
michael@0 616 } else if (bottom) {
michael@0 617 return 2;
michael@0 618 }
michael@0 619 } else if (xMin > midX) {
michael@0 620 if (top) {
michael@0 621 return 0;
michael@0 622 } else if (bottom) {
michael@0 623 return 3;
michael@0 624 }
michael@0 625 }
michael@0 626 return -1;
michael@0 627 };
michael@0 628 QuadTree.prototype.insert = function (obj) {
michael@0 629 var nodes = this.nodes;
michael@0 630 if (nodes.length) {
michael@0 631 var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax);
michael@0 632 if (index > -1) {
michael@0 633 nodes[index].insert(obj);
michael@0 634 } else {
michael@0 635 obj.prev = null;
michael@0 636 if (this.stuckObjects) {
michael@0 637 obj.next = this.stuckObjects;
michael@0 638 this.stuckObjects.prev = obj;
michael@0 639 } else {
michael@0 640 obj.next = null;
michael@0 641 }
michael@0 642 this.stuckObjects = obj;
michael@0 643 obj.parent = this;
michael@0 644 }
michael@0 645 return;
michael@0 646 }
michael@0 647 var numChildren = 1;
michael@0 648 var item = this.objects;
michael@0 649 if (!item) {
michael@0 650 obj.prev = null;
michael@0 651 obj.next = null;
michael@0 652 this.objects = obj;
michael@0 653 } else {
michael@0 654 while (item.next) {
michael@0 655 numChildren++;
michael@0 656 item = item.next;
michael@0 657 }
michael@0 658 obj.prev = item;
michael@0 659 obj.next = null;
michael@0 660 item.next = obj;
michael@0 661 }
michael@0 662 if (numChildren > 4 && this.level < 10) {
michael@0 663 this._subdivide();
michael@0 664 item = this.objects;
michael@0 665 while (item) {
michael@0 666 var next = item.next;
michael@0 667 this.insert(item);
michael@0 668 item = next;
michael@0 669 }
michael@0 670 this.objects = null;
michael@0 671 return;
michael@0 672 }
michael@0 673 obj.parent = this;
michael@0 674 };
michael@0 675 QuadTree.prototype.update = function (obj) {
michael@0 676 var node = obj.parent;
michael@0 677 if (node) {
michael@0 678 if (obj.xMin >= node.x && obj.xMax <= node.x + node.width && obj.yMin >= node.y && obj.yMax <= node.y + node.height) {
michael@0 679 if (node.nodes.length) {
michael@0 680 var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax);
michael@0 681 if (index > -1) {
michael@0 682 node.remove(obj);
michael@0 683 node = this.nodes[index];
michael@0 684 node.insert(obj);
michael@0 685 }
michael@0 686 } else {
michael@0 687 node.remove(obj);
michael@0 688 node.insert(obj);
michael@0 689 }
michael@0 690 return;
michael@0 691 }
michael@0 692 node.remove(obj);
michael@0 693 }
michael@0 694 this.root.insert(obj);
michael@0 695 };
michael@0 696 QuadTree.prototype.remove = function (obj) {
michael@0 697 var prev = obj.prev;
michael@0 698 var next = obj.next;
michael@0 699 if (prev) {
michael@0 700 prev.next = next;
michael@0 701 obj.prev = null;
michael@0 702 } else {
michael@0 703 var node = obj.parent;
michael@0 704 if (node.objects === obj) {
michael@0 705 node.objects = next;
michael@0 706 } else if (node.stuckObjects === obj) {
michael@0 707 node.stuckObjects = next;
michael@0 708 }
michael@0 709 }
michael@0 710 if (next) {
michael@0 711 next.prev = prev;
michael@0 712 obj.next = null;
michael@0 713 }
michael@0 714 obj.parent = null;
michael@0 715 };
michael@0 716 QuadTree.prototype.retrieve = function (xMin, xMax, yMin, yMax) {
michael@0 717 var stack = [];
michael@0 718 var out = [];
michael@0 719 var node = this;
michael@0 720 do {
michael@0 721 if (node.nodes.length) {
michael@0 722 var index = node._findIndex(xMin, xMax, yMin, yMax);
michael@0 723 if (index > -1) {
michael@0 724 stack.push(node.nodes[index]);
michael@0 725 } else {
michael@0 726 stack.push.apply(stack, node.nodes);
michael@0 727 }
michael@0 728 }
michael@0 729 var item = node.objects;
michael@0 730 for (var i = 0; i < 2; i++) {
michael@0 731 while (item) {
michael@0 732 if (!(item.xMin > xMax || item.xMax < xMin || item.yMin > yMax || item.yMax < yMin)) {
michael@0 733 out.push(item);
michael@0 734 }
michael@0 735 item = item.next;
michael@0 736 }
michael@0 737 item = node.stuckObjects;
michael@0 738 }
michael@0 739 node = stack.pop();
michael@0 740 } while (node);
michael@0 741 return out;
michael@0 742 };
michael@0 743 QuadTree.prototype._subdivide = function () {
michael@0 744 var halfWidth = this.width / 2 | 0;
michael@0 745 var halfHeight = this.height / 2 | 0;
michael@0 746 var midX = this.x + halfWidth;
michael@0 747 var midY = this.y + halfHeight;
michael@0 748 this.nodes[0] = new QuadTree(midX, this.y, halfWidth, halfHeight, this);
michael@0 749 this.nodes[1] = new QuadTree(this.x, this.y, halfWidth, halfHeight, this);
michael@0 750 this.nodes[2] = new QuadTree(this.x, midY, halfWidth, halfHeight, this);
michael@0 751 this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, this);
michael@0 752 };
michael@0 753 var RegionCluster = function () {
michael@0 754 this.regions = [];
michael@0 755 };
michael@0 756 RegionCluster.prototype.reset = function () {
michael@0 757 this.regions.length = 0;
michael@0 758 };
michael@0 759 RegionCluster.prototype.insert = function (region) {
michael@0 760 var regions = this.regions;
michael@0 761 if (regions.length < 3) {
michael@0 762 regions.push({
michael@0 763 xMin: region.xMin,
michael@0 764 xMax: region.xMax,
michael@0 765 yMin: region.yMin,
michael@0 766 yMax: region.yMax
michael@0 767 });
michael@0 768 return;
michael@0 769 }
michael@0 770 var a = region;
michael@0 771 var b = regions[0];
michael@0 772 var c = regions[1];
michael@0 773 var d = regions[2];
michael@0 774 var ab = (max(a.xMax, b.xMax) - min(a.xMin, b.xMin)) * (max(a.yMax, b.yMax) - min(a.yMin, b.yMin));
michael@0 775 var rb = regions[0];
michael@0 776 var ac = (max(a.xMax, c.xMax) - min(a.xMin, c.xMin)) * (max(a.yMax, c.yMax) - min(a.yMin, c.yMin));
michael@0 777 var ad = (max(a.xMax, d.xMax) - min(a.xMin, d.xMin)) * (max(a.yMax, d.yMax) - min(a.yMin, d.yMin));
michael@0 778 if (ac < ab) {
michael@0 779 ab = ac;
michael@0 780 rb = c;
michael@0 781 }
michael@0 782 if (ad < ab) {
michael@0 783 ab = ad;
michael@0 784 rb = d;
michael@0 785 }
michael@0 786 var bc = (max(b.xMax, c.xMax) - min(b.xMin, c.xMin)) * (max(b.yMax, c.yMax) - min(b.yMin, c.yMin));
michael@0 787 var bd = (max(b.xMax, d.xMax) - min(b.xMin, d.xMin)) * (max(b.yMax, d.yMax) - min(b.yMin, d.yMin));
michael@0 788 var cd = (max(c.xMax, d.xMax) - min(c.xMin, d.xMin)) * (max(c.yMax, d.yMax) - min(c.yMin, d.yMin));
michael@0 789 if (ab < bc && ab < bd && ab < cd) {
michael@0 790 if (a.xMin < rb.xMin) {
michael@0 791 rb.xMin = a.xMin;
michael@0 792 }
michael@0 793 if (a.xMax > rb.xMax) {
michael@0 794 rb.xMax = a.xMax;
michael@0 795 }
michael@0 796 if (a.yMin < rb.yMin) {
michael@0 797 rb.yMin = a.yMin;
michael@0 798 }
michael@0 799 if (a.yMax > rb.yMax) {
michael@0 800 rb.yMax = a.yMax;
michael@0 801 }
michael@0 802 return;
michael@0 803 }
michael@0 804 rb = regions[0];
michael@0 805 var rc = regions[1];
michael@0 806 if (bd < bc) {
michael@0 807 bc = bd;
michael@0 808 rc = regions[2];
michael@0 809 }
michael@0 810 if (cd < bc) {
michael@0 811 rb = regions[1];
michael@0 812 rc = regions[2];
michael@0 813 }
michael@0 814 if (rc.xMin < rb.xMin) {
michael@0 815 rb.xMin = rc.xMin;
michael@0 816 }
michael@0 817 if (rc.xMax > rb.xMax) {
michael@0 818 rb.xMax = rc.xMax;
michael@0 819 }
michael@0 820 if (rc.yMin < rb.yMin) {
michael@0 821 rb.yMin = rc.yMin;
michael@0 822 }
michael@0 823 if (rc.yMax > rb.yMax) {
michael@0 824 rb.yMax = rc.yMax;
michael@0 825 }
michael@0 826 rc.xMin = a.xMin;
michael@0 827 rc.xMax = a.xMax;
michael@0 828 rc.yMin = a.yMin;
michael@0 829 rc.yMax = a.yMax;
michael@0 830 };
michael@0 831 RegionCluster.prototype.retrieve = function () {
michael@0 832 return this.regions;
michael@0 833 };
michael@0 834 var EXTERNAL_INTERFACE_FEATURE = 1;
michael@0 835 var CLIPBOARD_FEATURE = 2;
michael@0 836 var SHAREDOBJECT_FEATURE = 3;
michael@0 837 var VIDEO_FEATURE = 4;
michael@0 838 var SOUND_FEATURE = 5;
michael@0 839 var NETCONNECTION_FEATURE = 6;
michael@0 840 if (!this.performance) {
michael@0 841 this.performance = {};
michael@0 842 }
michael@0 843 if (!this.performance.now) {
michael@0 844 this.performance.now = Date.now;
michael@0 845 }
michael@0 846 var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74;
michael@0 847 var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87;
michael@0 848 var SWF_TAG_CODE_DEFINE_BITS = 6;
michael@0 849 var SWF_TAG_CODE_DEFINE_BITS_JPEG2 = 21;
michael@0 850 var SWF_TAG_CODE_DEFINE_BITS_JPEG3 = 35;
michael@0 851 var SWF_TAG_CODE_DEFINE_BITS_JPEG4 = 90;
michael@0 852 var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS = 20;
michael@0 853 var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2 = 36;
michael@0 854 var SWF_TAG_CODE_DEFINE_BUTTON = 7;
michael@0 855 var SWF_TAG_CODE_DEFINE_BUTTON2 = 34;
michael@0 856 var SWF_TAG_CODE_DEFINE_BUTTON_CXFORM = 23;
michael@0 857 var SWF_TAG_CODE_DEFINE_BUTTON_SOUND = 17;
michael@0 858 var SWF_TAG_CODE_DEFINE_EDIT_TEXT = 37;
michael@0 859 var SWF_TAG_CODE_DEFINE_FONT = 10;
michael@0 860 var SWF_TAG_CODE_DEFINE_FONT2 = 48;
michael@0 861 var SWF_TAG_CODE_DEFINE_FONT3 = 75;
michael@0 862 var SWF_TAG_CODE_DEFINE_FONT4 = 91;
michael@0 863 var SWF_TAG_CODE_DEFINE_FONT_ALIGN_ZONES = 73;
michael@0 864 var SWF_TAG_CODE_DEFINE_FONT_INFO = 13;
michael@0 865 var SWF_TAG_CODE_DEFINE_FONT_INFO2 = 62;
michael@0 866 var SWF_TAG_CODE_DEFINE_FONT_NAME = 88;
michael@0 867 var SWF_TAG_CODE_DEFINE_MORPH_SHAPE = 46;
michael@0 868 var SWF_TAG_CODE_DEFINE_MORPH_SHAPE2 = 84;
michael@0 869 var SWF_TAG_CODE_DEFINE_SCALING_GRID = 78;
michael@0 870 var SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA = 86;
michael@0 871 var SWF_TAG_CODE_DEFINE_SHAPE = 2;
michael@0 872 var SWF_TAG_CODE_DEFINE_SHAPE2 = 22;
michael@0 873 var SWF_TAG_CODE_DEFINE_SHAPE3 = 32;
michael@0 874 var SWF_TAG_CODE_DEFINE_SHAPE4 = 83;
michael@0 875 var SWF_TAG_CODE_DEFINE_SOUND = 14;
michael@0 876 var SWF_TAG_CODE_DEFINE_SPRITE = 39;
michael@0 877 var SWF_TAG_CODE_DEFINE_TEXT = 11;
michael@0 878 var SWF_TAG_CODE_DEFINE_TEXT2 = 33;
michael@0 879 var SWF_TAG_CODE_DEFINE_VIDEO_STREAM = 60;
michael@0 880 var SWF_TAG_CODE_DO_ABC = 82;
michael@0 881 var SWF_TAG_CODE_DO_ABC_ = 72;
michael@0 882 var SWF_TAG_CODE_DO_ACTION = 12;
michael@0 883 var SWF_TAG_CODE_DO_INIT_ACTION = 59;
michael@0 884 var SWF_TAG_CODE_ENABLE_DEBUGGER = 58;
michael@0 885 var SWF_TAG_CODE_ENABLE_DEBUGGER2 = 64;
michael@0 886 var SWF_TAG_CODE_END = 0;
michael@0 887 var SWF_TAG_CODE_EXPORT_ASSETS = 56;
michael@0 888 var SWF_TAG_CODE_FILE_ATTRIBUTES = 69;
michael@0 889 var SWF_TAG_CODE_FRAME_LABEL = 43;
michael@0 890 var SWF_TAG_CODE_IMPORT_ASSETS = 57;
michael@0 891 var SWF_TAG_CODE_IMPORT_ASSETS2 = 71;
michael@0 892 var SWF_TAG_CODE_JPEG_TABLES = 8;
michael@0 893 var SWF_TAG_CODE_METADATA = 77;
michael@0 894 var SWF_TAG_CODE_PLACE_OBJECT = 4;
michael@0 895 var SWF_TAG_CODE_PLACE_OBJECT2 = 26;
michael@0 896 var SWF_TAG_CODE_PLACE_OBJECT3 = 70;
michael@0 897 var SWF_TAG_CODE_PROTECT = 24;
michael@0 898 var SWF_TAG_CODE_REMOVE_OBJECT = 5;
michael@0 899 var SWF_TAG_CODE_REMOVE_OBJECT2 = 28;
michael@0 900 var SWF_TAG_CODE_SCRIPT_LIMITS = 65;
michael@0 901 var SWF_TAG_CODE_SET_BACKGROUND_COLOR = 9;
michael@0 902 var SWF_TAG_CODE_SET_TAB_INDEX = 66;
michael@0 903 var SWF_TAG_CODE_SHOW_FRAME = 1;
michael@0 904 var SWF_TAG_CODE_SOUND_STREAM_BLOCK = 19;
michael@0 905 var SWF_TAG_CODE_SOUND_STREAM_HEAD = 18;
michael@0 906 var SWF_TAG_CODE_SOUND_STREAM_HEAD2 = 45;
michael@0 907 var SWF_TAG_CODE_START_SOUND = 15;
michael@0 908 var SWF_TAG_CODE_START_SOUND2 = 89;
michael@0 909 var SWF_TAG_CODE_SYMBOL_CLASS = 76;
michael@0 910 var SWF_TAG_CODE_VIDEO_FRAME = 61;
michael@0 911 self.SWF = {};
michael@0 912 var FORMAT_COLORMAPPED = 3;
michael@0 913 var FORMAT_15BPP = 4;
michael@0 914 var FORMAT_24BPP = 5;
michael@0 915 var FACTOR_5BBP = 255 / 31;
michael@0 916 var crcTable = [];
michael@0 917 for (var i = 0; i < 256; i++) {
michael@0 918 var c = i;
michael@0 919 for (var h = 0; h < 8; h++) {
michael@0 920 if (c & 1)
michael@0 921 c = 3988292384 ^ c >> 1 & 2147483647;
michael@0 922 else
michael@0 923 c = c >> 1 & 2147483647;
michael@0 924 }
michael@0 925 crcTable[i] = c;
michael@0 926 }
michael@0 927 function crc32(data, start, end) {
michael@0 928 var crc = -1;
michael@0 929 for (var i = start; i < end; i++) {
michael@0 930 var a = (crc ^ data[i]) & 255;
michael@0 931 var b = crcTable[a];
michael@0 932 crc = crc >>> 8 ^ b;
michael@0 933 }
michael@0 934 return crc ^ -1;
michael@0 935 }
michael@0 936 function createPngChunk(type, data) {
michael@0 937 var chunk = new Uint8Array(12 + data.length);
michael@0 938 var p = 0;
michael@0 939 var len = data.length;
michael@0 940 chunk[p] = len >> 24 & 255;
michael@0 941 chunk[p + 1] = len >> 16 & 255;
michael@0 942 chunk[p + 2] = len >> 8 & 255;
michael@0 943 chunk[p + 3] = len & 255;
michael@0 944 chunk[p + 4] = type.charCodeAt(0) & 255;
michael@0 945 chunk[p + 5] = type.charCodeAt(1) & 255;
michael@0 946 chunk[p + 6] = type.charCodeAt(2) & 255;
michael@0 947 chunk[p + 7] = type.charCodeAt(3) & 255;
michael@0 948 if (data instanceof Uint8Array)
michael@0 949 chunk.set(data, 8);
michael@0 950 p = 8 + len;
michael@0 951 var crc = crc32(chunk, 4, p);
michael@0 952 chunk[p] = crc >> 24 & 255;
michael@0 953 chunk[p + 1] = crc >> 16 & 255;
michael@0 954 chunk[p + 2] = crc >> 8 & 255;
michael@0 955 chunk[p + 3] = crc & 255;
michael@0 956 return chunk;
michael@0 957 }
michael@0 958 function adler32(data, start, end) {
michael@0 959 var a = 1;
michael@0 960 var b = 0;
michael@0 961 for (var i = start; i < end; ++i) {
michael@0 962 a = (a + (data[i] & 255)) % 65521;
michael@0 963 b = (b + a) % 65521;
michael@0 964 }
michael@0 965 return b << 16 | a;
michael@0 966 }
michael@0 967 function defineBitmap(tag) {
michael@0 968 var width = tag.width;
michael@0 969 var height = tag.height;
michael@0 970 var hasAlpha = tag.hasAlpha;
michael@0 971 var plte = '';
michael@0 972 var trns = '';
michael@0 973 var literals;
michael@0 974 var bmpData = tag.bmpData;
michael@0 975 switch (tag.format) {
michael@0 976 case FORMAT_COLORMAPPED:
michael@0 977 var colorType = 3;
michael@0 978 var bytesPerLine = width + 3 & ~3;
michael@0 979 var colorTableSize = tag.colorTableSize + 1;
michael@0 980 var paletteSize = colorTableSize * (tag.hasAlpha ? 4 : 3);
michael@0 981 var datalen = paletteSize + bytesPerLine * height;
michael@0 982 var stream = createInflatedStream(bmpData, datalen);
michael@0 983 var bytes = stream.bytes;
michael@0 984 var pos = 0;
michael@0 985 stream.ensure(paletteSize);
michael@0 986 if (hasAlpha) {
michael@0 987 var palette = new Uint8Array(paletteSize / 4 * 3);
michael@0 988 var pp = 0;
michael@0 989 var alphaValues = new Uint8Array(paletteSize / 4);
michael@0 990 var pa = 0;
michael@0 991 while (pos < paletteSize) {
michael@0 992 palette[pp++] = bytes[pos];
michael@0 993 palette[pp++] = bytes[pos + 1];
michael@0 994 palette[pp++] = bytes[pos + 2];
michael@0 995 alphaValues[pa++] = bytes[pos + 3];
michael@0 996 pos += 4;
michael@0 997 }
michael@0 998 plte = createPngChunk('PLTE', palette);
michael@0 999 trns = createPngChunk('tRNS', alphaValues);
michael@0 1000 } else {
michael@0 1001 plte = createPngChunk('PLTE', bytes.subarray(pos, pos + paletteSize));
michael@0 1002 pos += paletteSize;
michael@0 1003 }
michael@0 1004 literals = new Uint8Array(width * height + height);
michael@0 1005 var pl = 0;
michael@0 1006 while (pos < datalen) {
michael@0 1007 stream.ensure(bytesPerLine);
michael@0 1008 var begin = pos;
michael@0 1009 var end = begin + width;
michael@0 1010 pl++;
michael@0 1011 literals.set(bytes.subarray(begin, end), pl);
michael@0 1012 pl += end - begin;
michael@0 1013 stream.pos = pos += bytesPerLine;
michael@0 1014 }
michael@0 1015 break;
michael@0 1016 case FORMAT_15BPP:
michael@0 1017 var colorType = 2;
michael@0 1018 var bytesPerLine = width * 2 + 3 & ~3;
michael@0 1019 var stream = createInflatedStream(bmpData, bytesPerLine * height);
michael@0 1020 var pos = 0;
michael@0 1021 literals = new Uint8Array(width * height * 3 + height);
michael@0 1022 var pl = 0;
michael@0 1023 for (var y = 0; y < height; ++y) {
michael@0 1024 pl++;
michael@0 1025 stream.ensure(bytesPerLine);
michael@0 1026 for (var x = 0; x < width; ++x) {
michael@0 1027 var word = stream.getUint16(pos);
michael@0 1028 pos += 2;
michael@0 1029 literals[pl++] = 0 | FACTOR_5BBP * (word >> 10 & 31);
michael@0 1030 literals[pl++] = 0 | FACTOR_5BBP * (word >> 5 & 31);
michael@0 1031 literals[pl++] = 0 | FACTOR_5BBP * (word & 31);
michael@0 1032 }
michael@0 1033 stream.pos = pos += bytesPerLine;
michael@0 1034 }
michael@0 1035 break;
michael@0 1036 case FORMAT_24BPP:
michael@0 1037 var padding;
michael@0 1038 if (hasAlpha) {
michael@0 1039 var colorType = 6;
michael@0 1040 padding = 0;
michael@0 1041 literals = new Uint8Array(width * height * 4 + height);
michael@0 1042 } else {
michael@0 1043 var colorType = 2;
michael@0 1044 padding = 1;
michael@0 1045 literals = new Uint8Array(width * height * 3 + height);
michael@0 1046 }
michael@0 1047 var bytesPerLine = width * 4;
michael@0 1048 var stream = createInflatedStream(bmpData, bytesPerLine * height);
michael@0 1049 var bytes = stream.bytes;
michael@0 1050 var pos = 0;
michael@0 1051 var pl = 0;
michael@0 1052 for (var y = 0; y < height; ++y) {
michael@0 1053 stream.ensure(bytesPerLine);
michael@0 1054 pl++;
michael@0 1055 for (var x = 0; x < width; ++x) {
michael@0 1056 pos += padding;
michael@0 1057 if (hasAlpha) {
michael@0 1058 var alpha = bytes[pos];
michael@0 1059 if (alpha) {
michael@0 1060 var opacity = alpha / 255;
michael@0 1061 literals[pl++] = 0 | bytes[pos + 1] / opacity;
michael@0 1062 literals[pl++] = 0 | bytes[pos + 2] / opacity;
michael@0 1063 literals[pl++] = 0 | bytes[pos + 3] / opacity;
michael@0 1064 literals[pl++] = alpha;
michael@0 1065 } else {
michael@0 1066 pl += 4;
michael@0 1067 }
michael@0 1068 } else {
michael@0 1069 literals[pl++] = bytes[pos];
michael@0 1070 literals[pl++] = bytes[pos + 1];
michael@0 1071 literals[pl++] = bytes[pos + 2];
michael@0 1072 }
michael@0 1073 pos += 4 - padding;
michael@0 1074 }
michael@0 1075 stream.pos = pos;
michael@0 1076 }
michael@0 1077 break;
michael@0 1078 default:
michael@0 1079 fail('invalid format', 'bitmap');
michael@0 1080 }
michael@0 1081 var ihdr = new Uint8Array([
michael@0 1082 width >> 24 & 255,
michael@0 1083 width >> 16 & 255,
michael@0 1084 width >> 8 & 255,
michael@0 1085 width & 255,
michael@0 1086 height >> 24 & 255,
michael@0 1087 height >> 16 & 255,
michael@0 1088 height >> 8 & 255,
michael@0 1089 height & 255,
michael@0 1090 8,
michael@0 1091 colorType,
michael@0 1092 0,
michael@0 1093 0,
michael@0 1094 0
michael@0 1095 ]);
michael@0 1096 var len = literals.length;
michael@0 1097 var maxBlockLength = 65535;
michael@0 1098 var idat = new Uint8Array(2 + len + Math.ceil(len / maxBlockLength) * 5 + 4);
michael@0 1099 var pi = 0;
michael@0 1100 idat[pi++] = 120;
michael@0 1101 idat[pi++] = 156;
michael@0 1102 var pos = 0;
michael@0 1103 while (len > maxBlockLength) {
michael@0 1104 idat[pi++] = 0;
michael@0 1105 idat[pi++] = 255;
michael@0 1106 idat[pi++] = 255;
michael@0 1107 idat[pi++] = 0;
michael@0 1108 idat[pi++] = 0;
michael@0 1109 idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
michael@0 1110 pi += maxBlockLength;
michael@0 1111 pos += maxBlockLength;
michael@0 1112 len -= maxBlockLength;
michael@0 1113 }
michael@0 1114 idat[pi++] = 1;
michael@0 1115 idat[pi++] = len & 255;
michael@0 1116 idat[pi++] = len >> 8 & 255;
michael@0 1117 idat[pi++] = ~len & 65535 & 255;
michael@0 1118 idat[pi++] = (~len & 65535) >> 8 & 255;
michael@0 1119 idat.set(literals.subarray(pos), pi);
michael@0 1120 pi += literals.length - pos;
michael@0 1121 var adler = adler32(literals, 0, literals.length);
michael@0 1122 idat[pi++] = adler >> 24 & 255;
michael@0 1123 idat[pi++] = adler >> 16 & 255;
michael@0 1124 idat[pi++] = adler >> 8 & 255;
michael@0 1125 idat[pi++] = adler & 255;
michael@0 1126 var chunks = [
michael@0 1127 new Uint8Array([
michael@0 1128 137,
michael@0 1129 80,
michael@0 1130 78,
michael@0 1131 71,
michael@0 1132 13,
michael@0 1133 10,
michael@0 1134 26,
michael@0 1135 10
michael@0 1136 ]),
michael@0 1137 createPngChunk('IHDR', ihdr),
michael@0 1138 plte,
michael@0 1139 trns,
michael@0 1140 createPngChunk('IDAT', idat),
michael@0 1141 createPngChunk('IEND', '')
michael@0 1142 ];
michael@0 1143 return {
michael@0 1144 type: 'image',
michael@0 1145 id: tag.id,
michael@0 1146 width: width,
michael@0 1147 height: height,
michael@0 1148 mimeType: 'image/png',
michael@0 1149 data: new Blob(chunks, {
michael@0 1150 type: 'image/png'
michael@0 1151 })
michael@0 1152 };
michael@0 1153 }
michael@0 1154 function defineButton(tag, dictionary) {
michael@0 1155 var characters = tag.characters;
michael@0 1156 var states = {
michael@0 1157 up: {},
michael@0 1158 over: {},
michael@0 1159 down: {},
michael@0 1160 hitTest: {}
michael@0 1161 };
michael@0 1162 var i = 0, character;
michael@0 1163 while (character = characters[i++]) {
michael@0 1164 if (character.eob)
michael@0 1165 break;
michael@0 1166 var characterItem = dictionary[character.symbolId];
michael@0 1167 var entry = {
michael@0 1168 symbolId: characterItem.id,
michael@0 1169 hasMatrix: !(!character.matrix),
michael@0 1170 matrix: character.matrix
michael@0 1171 };
michael@0 1172 if (character.stateUp)
michael@0 1173 states.up[character.depth] = entry;
michael@0 1174 if (character.stateOver)
michael@0 1175 states.over[character.depth] = entry;
michael@0 1176 if (character.stateDown)
michael@0 1177 states.down[character.depth] = entry;
michael@0 1178 if (character.stateHitTest)
michael@0 1179 states.hitTest[character.depth] = entry;
michael@0 1180 }
michael@0 1181 var button = {
michael@0 1182 type: 'button',
michael@0 1183 id: tag.id,
michael@0 1184 buttonActions: tag.buttonActions,
michael@0 1185 states: states
michael@0 1186 };
michael@0 1187 return button;
michael@0 1188 }
michael@0 1189 var nextFontId = 1;
michael@0 1190 function maxPower2(num) {
michael@0 1191 var maxPower = 0;
michael@0 1192 var val = num;
michael@0 1193 while (val >= 2) {
michael@0 1194 val /= 2;
michael@0 1195 ++maxPower;
michael@0 1196 }
michael@0 1197 return pow(2, maxPower);
michael@0 1198 }
michael@0 1199 function toString16(val) {
michael@0 1200 return fromCharCode(val >> 8 & 255, val & 255);
michael@0 1201 }
michael@0 1202 function toString32(val) {
michael@0 1203 return toString16(val >> 16) + toString16(val);
michael@0 1204 }
michael@0 1205 function defineFont(tag, dictionary) {
michael@0 1206 var tables = {};
michael@0 1207 var codes = [];
michael@0 1208 var glyphIndex = {};
michael@0 1209 var ranges = [];
michael@0 1210 var glyphs = tag.glyphs;
michael@0 1211 var glyphCount = glyphs.length;
michael@0 1212 if (tag.codes) {
michael@0 1213 codes = codes.concat(tag.codes);
michael@0 1214 for (var i = 0, code; code = codes[i]; ++i)
michael@0 1215 glyphIndex[code] = i;
michael@0 1216 codes.sort(function (a, b) {
michael@0 1217 return a - b;
michael@0 1218 });
michael@0 1219 var i = 0;
michael@0 1220 var code;
michael@0 1221 while (code = codes[i++]) {
michael@0 1222 var start = code;
michael@0 1223 var end = start;
michael@0 1224 var indices = [
michael@0 1225 i - 1
michael@0 1226 ];
michael@0 1227 while ((code = codes[i]) && end + 1 === code) {
michael@0 1228 ++end;
michael@0 1229 indices.push(i);
michael@0 1230 ++i;
michael@0 1231 }
michael@0 1232 ranges.push([
michael@0 1233 start,
michael@0 1234 end,
michael@0 1235 indices
michael@0 1236 ]);
michael@0 1237 }
michael@0 1238 } else {
michael@0 1239 var indices = [];
michael@0 1240 var UAC_OFFSET = 57344;
michael@0 1241 for (var i = 0; i < glyphCount; i++) {
michael@0 1242 var code = UAC_OFFSET + i;
michael@0 1243 codes.push(code);
michael@0 1244 glyphIndex[code] = i;
michael@0 1245 indices.push(i);
michael@0 1246 }
michael@0 1247 ranges.push([
michael@0 1248 UAC_OFFSET,
michael@0 1249 UAC_OFFSET + glyphCount - 1,
michael@0 1250 indices
michael@0 1251 ]);
michael@0 1252 }
michael@0 1253 var resolution = tag.resolution || 1;
michael@0 1254 var ascent = Math.ceil(tag.ascent / resolution) || 1024;
michael@0 1255 var descent = -Math.ceil(tag.descent / resolution) | 0;
michael@0 1256 var leading = tag.leading / resolution | 0;
michael@0 1257 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';
michael@0 1258 ;
michael@0 1259 var startCount = '';
michael@0 1260 var endCount = '';
michael@0 1261 var idDelta = '';
michael@0 1262 var idRangeOffset = '';
michael@0 1263 var i = 0;
michael@0 1264 var range;
michael@0 1265 while (range = ranges[i++]) {
michael@0 1266 var start = range[0];
michael@0 1267 var end = range[1];
michael@0 1268 var code = range[2][0];
michael@0 1269 startCount += toString16(start);
michael@0 1270 endCount += toString16(end);
michael@0 1271 idDelta += toString16(code - start + 1 & 65535);
michael@0 1272 idRangeOffset += toString16(0);
michael@0 1273 }
michael@0 1274 endCount += '\xff\xff';
michael@0 1275 startCount += '\xff\xff';
michael@0 1276 idDelta += '\0\x01';
michael@0 1277 idRangeOffset += '\0\0';
michael@0 1278 var segCount = ranges.length + 1;
michael@0 1279 var searchRange = maxPower2(segCount) * 2;
michael@0 1280 var rangeShift = 2 * segCount - searchRange;
michael@0 1281 var format314 = '\0\0' + toString16(segCount * 2) + toString16(searchRange) + toString16(logE(segCount) / logE(2)) + toString16(rangeShift) + endCount + '\0\0' + startCount + idDelta + idRangeOffset;
michael@0 1282 ;
michael@0 1283 tables['cmap'] = '\0\0\0\x01\0\x03\0\x01\0\0\0\f\0\x04' + toString16(format314.length + 4) + format314;
michael@0 1284 ;
michael@0 1285 var glyf = '\0\x01\0\0\0\0\0\0\0\0\0\0\0\x001\0';
michael@0 1286 var loca = '\0\0';
michael@0 1287 var offset = 16;
michael@0 1288 var maxPoints = 0;
michael@0 1289 var xMins = [];
michael@0 1290 var xMaxs = [];
michael@0 1291 var yMins = [];
michael@0 1292 var yMaxs = [];
michael@0 1293 var maxContours = 0;
michael@0 1294 var i = 0;
michael@0 1295 var code;
michael@0 1296 while (code = codes[i++]) {
michael@0 1297 var glyph = glyphs[glyphIndex[code]];
michael@0 1298 var records = glyph.records;
michael@0 1299 var numberOfContours = 1;
michael@0 1300 var endPoint = 0;
michael@0 1301 var endPtsOfContours = '';
michael@0 1302 var flags = '';
michael@0 1303 var xCoordinates = '';
michael@0 1304 var yCoordinates = '';
michael@0 1305 var x = 0;
michael@0 1306 var y = 0;
michael@0 1307 var xMin = 1024;
michael@0 1308 var xMax = -1024;
michael@0 1309 var yMin = 1024;
michael@0 1310 var yMax = -1024;
michael@0 1311 for (var j = 0, record; record = records[j]; ++j) {
michael@0 1312 if (record.type) {
michael@0 1313 if (record.isStraight) {
michael@0 1314 if (record.isGeneral) {
michael@0 1315 flags += '\x01';
michael@0 1316 var dx = record.deltaX / resolution;
michael@0 1317 var dy = -record.deltaY / resolution;
michael@0 1318 xCoordinates += toString16(dx);
michael@0 1319 yCoordinates += toString16(dy);
michael@0 1320 x += dx;
michael@0 1321 y += dy;
michael@0 1322 } else if (record.isVertical) {
michael@0 1323 flags += '\x11';
michael@0 1324 var dy = -record.deltaY / resolution;
michael@0 1325 yCoordinates += toString16(dy);
michael@0 1326 y += dy;
michael@0 1327 } else {
michael@0 1328 flags += '!';
michael@0 1329 var dx = record.deltaX / resolution;
michael@0 1330 xCoordinates += toString16(dx);
michael@0 1331 x += dx;
michael@0 1332 }
michael@0 1333 } else {
michael@0 1334 flags += '\0';
michael@0 1335 var cx = record.controlDeltaX / resolution;
michael@0 1336 var cy = -record.controlDeltaY / resolution;
michael@0 1337 xCoordinates += toString16(cx);
michael@0 1338 yCoordinates += toString16(cy);
michael@0 1339 flags += '\x01';
michael@0 1340 var dx = record.anchorDeltaX / resolution;
michael@0 1341 var dy = -record.anchorDeltaY / resolution;
michael@0 1342 xCoordinates += toString16(dx);
michael@0 1343 yCoordinates += toString16(dy);
michael@0 1344 ++endPoint;
michael@0 1345 x += cx + dx;
michael@0 1346 y += cy + dy;
michael@0 1347 }
michael@0 1348 if (x < xMin)
michael@0 1349 xMin = x;
michael@0 1350 if (x > xMax)
michael@0 1351 xMax = x;
michael@0 1352 if (y < yMin)
michael@0 1353 yMin = y;
michael@0 1354 if (y > yMax)
michael@0 1355 yMax = y;
michael@0 1356 ++endPoint;
michael@0 1357 } else {
michael@0 1358 if (record.eos)
michael@0 1359 break;
michael@0 1360 if (record.move) {
michael@0 1361 if (endPoint) {
michael@0 1362 ++numberOfContours;
michael@0 1363 endPtsOfContours += toString16(endPoint - 1);
michael@0 1364 }
michael@0 1365 flags += '\x01';
michael@0 1366 var moveX = record.moveX / resolution;
michael@0 1367 var moveY = -record.moveY / resolution;
michael@0 1368 var dx = moveX - x;
michael@0 1369 var dy = moveY - y;
michael@0 1370 xCoordinates += toString16(dx);
michael@0 1371 yCoordinates += toString16(dy);
michael@0 1372 x = moveX;
michael@0 1373 y = moveY;
michael@0 1374 if (endPoint > maxPoints)
michael@0 1375 maxPoints = endPoint;
michael@0 1376 if (x < xMin)
michael@0 1377 xMin = x;
michael@0 1378 if (x > xMax)
michael@0 1379 xMax = x;
michael@0 1380 if (y < yMin)
michael@0 1381 yMin = y;
michael@0 1382 if (y > yMax)
michael@0 1383 yMax = y;
michael@0 1384 ++endPoint;
michael@0 1385 }
michael@0 1386 }
michael@0 1387 }
michael@0 1388 endPtsOfContours += toString16((endPoint || 1) - 1);
michael@0 1389 if (!j) {
michael@0 1390 xMin = xMax = yMin = yMax = 0;
michael@0 1391 flags += '1';
michael@0 1392 }
michael@0 1393 var entry = toString16(numberOfContours) + toString16(xMin) + toString16(yMin) + toString16(xMax) + toString16(yMax) + endPtsOfContours + '\0\0' + flags + xCoordinates + yCoordinates;
michael@0 1394 ;
michael@0 1395 if (entry.length & 1)
michael@0 1396 entry += '\0';
michael@0 1397 glyf += entry;
michael@0 1398 loca += toString16(offset / 2);
michael@0 1399 offset += entry.length;
michael@0 1400 xMins.push(xMin);
michael@0 1401 xMaxs.push(xMax);
michael@0 1402 yMins.push(yMin);
michael@0 1403 yMaxs.push(yMax);
michael@0 1404 if (numberOfContours > maxContours)
michael@0 1405 maxContours = numberOfContours;
michael@0 1406 if (endPoint > maxPoints)
michael@0 1407 maxPoints = endPoint;
michael@0 1408 }
michael@0 1409 loca += toString16(offset / 2);
michael@0 1410 tables['glyf'] = glyf;
michael@0 1411 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';
michael@0 1412 ;
michael@0 1413 var advance = tag.advance;
michael@0 1414 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);
michael@0 1415 ;
michael@0 1416 var hmtx = '\0\0\0\0';
michael@0 1417 for (var i = 0; i < glyphCount; ++i)
michael@0 1418 hmtx += toString16(advance ? advance[i] / resolution : 1024) + '\0\0';
michael@0 1419 tables['hmtx'] = hmtx;
michael@0 1420 if (tag.kerning) {
michael@0 1421 var kerning = tag.kerning;
michael@0 1422 var nPairs = kerning.length;
michael@0 1423 var searchRange = maxPower2(nPairs) * 2;
michael@0 1424 var kern = '\0\0\0\x01\0\0' + toString16(14 + nPairs * 6) + '\0\x01' + toString16(nPairs) + toString16(searchRange) + toString16(logE(nPairs) / logE(2)) + toString16(2 * nPairs - searchRange);
michael@0 1425 ;
michael@0 1426 var i = 0;
michael@0 1427 var record;
michael@0 1428 while (record = kerning[i++]) {
michael@0 1429 kern += toString16(glyphIndex[record.code1]) + toString16(glyphIndex[record.code2]) + toString16(record.adjustment);
michael@0 1430 ;
michael@0 1431 }
michael@0 1432 tables['kern'] = kern;
michael@0 1433 }
michael@0 1434 tables['loca'] = loca;
michael@0 1435 tables['maxp'] = '\0\x01\0\0' + toString16(glyphCount + 1) + toString16(maxPoints) + toString16(maxContours) + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0' + '\0\0';
michael@0 1436 ;
michael@0 1437 var uniqueId = 'swf-font-' + nextFontId++;
michael@0 1438 var fontName = tag.name || uniqueId;
michael@0 1439 var psName = fontName.replace(/ /g, '');
michael@0 1440 var strings = [
michael@0 1441 tag.copyright || 'Original licence',
michael@0 1442 fontName,
michael@0 1443 'Unknown',
michael@0 1444 uniqueId,
michael@0 1445 fontName,
michael@0 1446 '1.0',
michael@0 1447 psName,
michael@0 1448 'Unknown',
michael@0 1449 'Unknown',
michael@0 1450 'Unknown'
michael@0 1451 ];
michael@0 1452 var count = strings.length;
michael@0 1453 var name = '\0\0' + toString16(count) + toString16(count * 12 + 6);
michael@0 1454 var offset = 0;
michael@0 1455 var i = 0;
michael@0 1456 var str;
michael@0 1457 while (str = strings[i++]) {
michael@0 1458 name += '\0\x01\0\0\0\0' + toString16(i - 1) + toString16(str.length) + toString16(offset);
michael@0 1459 offset += str.length;
michael@0 1460 }
michael@0 1461 tables['name'] = name + strings.join('');
michael@0 1462 tables['post'] = '\0\x03\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';
michael@0 1463 ;
michael@0 1464 var names = keys(tables);
michael@0 1465 var numTables = names.length;
michael@0 1466 var header = '\0\x01\0\0' + toString16(numTables) + '\0\x80' + '\0\x03' + '\0 ';
michael@0 1467 ;
michael@0 1468 var data = '';
michael@0 1469 var offset = numTables * 16 + header.length;
michael@0 1470 var i = 0;
michael@0 1471 var name;
michael@0 1472 while (name = names[i++]) {
michael@0 1473 var table = tables[name];
michael@0 1474 var length = table.length;
michael@0 1475 header += name + '\0\0\0\0' + toString32(offset) + toString32(length);
michael@0 1476 ;
michael@0 1477 while (length & 3) {
michael@0 1478 table += '\0';
michael@0 1479 ++length;
michael@0 1480 }
michael@0 1481 data += table;
michael@0 1482 while (offset & 3)
michael@0 1483 ++offset;
michael@0 1484 offset += length;
michael@0 1485 }
michael@0 1486 var otf = header + data;
michael@0 1487 var unitPerEm = 1024;
michael@0 1488 var metrics = {
michael@0 1489 ascent: ascent / unitPerEm,
michael@0 1490 descent: -descent / unitPerEm,
michael@0 1491 leading: leading / unitPerEm
michael@0 1492 };
michael@0 1493 return {
michael@0 1494 type: 'font',
michael@0 1495 id: tag.id,
michael@0 1496 name: fontName,
michael@0 1497 uniqueName: psName + uniqueId,
michael@0 1498 codes: codes,
michael@0 1499 metrics: metrics,
michael@0 1500 bold: tag.bold === 1,
michael@0 1501 italic: tag.italic === 1,
michael@0 1502 data: otf
michael@0 1503 };
michael@0 1504 }
michael@0 1505 function getUint16(buff, pos) {
michael@0 1506 return buff[pos] << 8 | buff[pos + 1];
michael@0 1507 }
michael@0 1508 function parseJpegChunks(imgDef, bytes) {
michael@0 1509 var i = 0;
michael@0 1510 var n = bytes.length;
michael@0 1511 var chunks = [];
michael@0 1512 var code;
michael@0 1513 do {
michael@0 1514 var begin = i;
michael@0 1515 while (i < n && bytes[i] !== 255)
michael@0 1516 ++i;
michael@0 1517 while (i < n && bytes[i] === 255)
michael@0 1518 ++i;
michael@0 1519 code = bytes[i++];
michael@0 1520 if (code === 218) {
michael@0 1521 i = n;
michael@0 1522 } else if (code === 217) {
michael@0 1523 i += 2;
michael@0 1524 continue;
michael@0 1525 } else if (code < 208 || code > 216) {
michael@0 1526 var length = getUint16(bytes, i);
michael@0 1527 if (code >= 192 && code <= 195) {
michael@0 1528 imgDef.height = getUint16(bytes, i + 3);
michael@0 1529 imgDef.width = getUint16(bytes, i + 5);
michael@0 1530 }
michael@0 1531 i += length;
michael@0 1532 }
michael@0 1533 chunks.push(bytes.subarray(begin, i));
michael@0 1534 } while (i < n);
michael@0 1535 return chunks;
michael@0 1536 }
michael@0 1537 function defineImage(tag, dictionary) {
michael@0 1538 var img = {
michael@0 1539 type: 'image',
michael@0 1540 id: tag.id,
michael@0 1541 mimeType: tag.mimeType
michael@0 1542 };
michael@0 1543 var imgData = tag.imgData;
michael@0 1544 var chunks;
michael@0 1545 if (tag.mimeType === 'image/jpeg') {
michael@0 1546 chunks = parseJpegChunks(img, imgData);
michael@0 1547 var alphaData = tag.alphaData;
michael@0 1548 if (alphaData) {
michael@0 1549 img.mask = createInflatedStream(alphaData, img.width * img.height).bytes;
michael@0 1550 }
michael@0 1551 if (tag.incomplete) {
michael@0 1552 var tables = dictionary[0];
michael@0 1553 var header = tables.data;
michael@0 1554 if (header && header.size) {
michael@0 1555 chunks[0] = chunks[0].subarray(2);
michael@0 1556 chunks.unshift(header.slice(0, header.size - 2));
michael@0 1557 }
michael@0 1558 }
michael@0 1559 } else {
michael@0 1560 chunks = [
michael@0 1561 imgData
michael@0 1562 ];
michael@0 1563 }
michael@0 1564 img.data = new Blob(chunks, {
michael@0 1565 type: tag.mimeType
michael@0 1566 });
michael@0 1567 return img;
michael@0 1568 }
michael@0 1569 function defineLabel(tag, dictionary) {
michael@0 1570 var records = tag.records;
michael@0 1571 var m = tag.matrix;
michael@0 1572 var cmds = [
michael@0 1573 'c.save()',
michael@0 1574 'c.transform(' + [
michael@0 1575 m.a,
michael@0 1576 m.b,
michael@0 1577 m.c,
michael@0 1578 m.d,
michael@0 1579 m.tx / 20,
michael@0 1580 m.ty / 20
michael@0 1581 ].join(',') + ')',
michael@0 1582 'c.scale(0.05, 0.05)'
michael@0 1583 ];
michael@0 1584 var dependencies = [];
michael@0 1585 var x = 0;
michael@0 1586 var y = 0;
michael@0 1587 var i = 0;
michael@0 1588 var record;
michael@0 1589 var codes;
michael@0 1590 while (record = records[i++]) {
michael@0 1591 if (record.eot)
michael@0 1592 break;
michael@0 1593 if (record.hasFont) {
michael@0 1594 var font = dictionary[record.fontId];
michael@0 1595 codes = font.codes;
michael@0 1596 cmds.push('c.font="' + record.fontHeight + 'px \'' + font.uniqueName + '\'"');
michael@0 1597 dependencies.push(font.id);
michael@0 1598 }
michael@0 1599 if (record.hasColor) {
michael@0 1600 cmds.push('ct.setFillStyle(c,"' + rgbaObjToStr(record.color) + '")');
michael@0 1601 cmds.push('ct.setAlpha(c)');
michael@0 1602 } else {
michael@0 1603 cmds.push('ct.setAlpha(c,true)');
michael@0 1604 }
michael@0 1605 if (record.hasMoveX)
michael@0 1606 x = record.moveX;
michael@0 1607 if (record.hasMoveY)
michael@0 1608 y = record.moveY;
michael@0 1609 var entries = record.entries;
michael@0 1610 var j = 0;
michael@0 1611 var entry;
michael@0 1612 while (entry = entries[j++]) {
michael@0 1613 var code = codes[entry.glyphIndex];
michael@0 1614 var text = code >= 32 && code != 34 && code != 92 ? fromCharCode(code) : '\\u' + (code + 65536).toString(16).substring(1);
michael@0 1615 cmds.push('c.fillText("' + text + '",' + x + ',' + y + ')');
michael@0 1616 x += entry.advance;
michael@0 1617 }
michael@0 1618 }
michael@0 1619 cmds.push('c.restore()');
michael@0 1620 var label = {
michael@0 1621 type: 'label',
michael@0 1622 id: tag.id,
michael@0 1623 bbox: tag.bbox,
michael@0 1624 data: cmds.join('\n')
michael@0 1625 };
michael@0 1626 if (dependencies.length)
michael@0 1627 label.require = dependencies;
michael@0 1628 return label;
michael@0 1629 }
michael@0 1630 var GRAPHICS_FILL_CLIPPED_BITMAP = 65;
michael@0 1631 var GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT = 19;
michael@0 1632 var GRAPHICS_FILL_LINEAR_GRADIENT = 16;
michael@0 1633 var GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP = 67;
michael@0 1634 var GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP = 66;
michael@0 1635 var GRAPHICS_FILL_RADIAL_GRADIENT = 18;
michael@0 1636 var GRAPHICS_FILL_REPEATING_BITMAP = 64;
michael@0 1637 var GRAPHICS_FILL_SOLID = 0;
michael@0 1638 function applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph) {
michael@0 1639 if (!segment) {
michael@0 1640 return;
michael@0 1641 }
michael@0 1642 var commands = segment.commands;
michael@0 1643 var data = segment.data;
michael@0 1644 var morphData = segment.morphData;
michael@0 1645 if (morphData) {
michael@0 1646 }
michael@0 1647 var path;
michael@0 1648 var targetSegment;
michael@0 1649 var command;
michael@0 1650 var i;
michael@0 1651 if (styles.fill0) {
michael@0 1652 path = fillPaths[styles.fill0 - 1];
michael@0 1653 if (!(styles.fill1 || styles.line)) {
michael@0 1654 targetSegment = path.head();
michael@0 1655 targetSegment.commands = [];
michael@0 1656 targetSegment.data = [];
michael@0 1657 targetSegment.morphData = isMorph ? [] : null;
michael@0 1658 } else {
michael@0 1659 targetSegment = path.addSegment([], [], isMorph ? [] : null);
michael@0 1660 }
michael@0 1661 var targetCommands = targetSegment.commands;
michael@0 1662 var targetData = targetSegment.data;
michael@0 1663 var targetMorphData = targetSegment.morphData;
michael@0 1664 targetCommands.push(SHAPE_MOVE_TO);
michael@0 1665 var j = data.length - 2;
michael@0 1666 targetData.push(data[j], data[j + 1]);
michael@0 1667 if (isMorph) {
michael@0 1668 targetMorphData.push(morphData[j], morphData[j + 1]);
michael@0 1669 }
michael@0 1670 for (i = commands.length; i-- > 1; j -= 2) {
michael@0 1671 command = commands[i];
michael@0 1672 targetCommands.push(command);
michael@0 1673 targetData.push(data[j - 2], data[j - 1]);
michael@0 1674 if (isMorph) {
michael@0 1675 targetMorphData.push(morphData[j - 2], morphData[j - 1]);
michael@0 1676 }
michael@0 1677 if (command === SHAPE_CURVE_TO) {
michael@0 1678 targetData.push(data[j - 4], data[j - 3]);
michael@0 1679 if (isMorph) {
michael@0 1680 targetMorphData.push(morphData[j - 4], morphData[j - 3]);
michael@0 1681 }
michael@0 1682 j -= 2;
michael@0 1683 }
michael@0 1684 }
michael@0 1685 if (isMorph) {
michael@0 1686 }
michael@0 1687 }
michael@0 1688 if (styles.line && styles.fill1) {
michael@0 1689 path = linePaths[styles.line - 1];
michael@0 1690 path.addSegment(commands, data, morphData);
michael@0 1691 }
michael@0 1692 }
michael@0 1693 function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) {
michael@0 1694 var isMorph = recordsMorph !== null;
michael@0 1695 var styles = {
michael@0 1696 fill0: 0,
michael@0 1697 fill1: 0,
michael@0 1698 line: 0
michael@0 1699 };
michael@0 1700 var segment = null;
michael@0 1701 var allPaths;
michael@0 1702 var defaultPath;
michael@0 1703 var numRecords = records.length - 1;
michael@0 1704 var x = 0;
michael@0 1705 var y = 0;
michael@0 1706 var morphX = 0;
michael@0 1707 var morphY = 0;
michael@0 1708 var path;
michael@0 1709 for (var i = 0, j = 0; i < numRecords; i++) {
michael@0 1710 var record = records[i];
michael@0 1711 var morphRecord;
michael@0 1712 if (isMorph) {
michael@0 1713 morphRecord = recordsMorph[j++];
michael@0 1714 }
michael@0 1715 if (record.type === 0) {
michael@0 1716 if (segment) {
michael@0 1717 applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
michael@0 1718 }
michael@0 1719 if (record.hasNewStyles) {
michael@0 1720 if (!allPaths) {
michael@0 1721 allPaths = [];
michael@0 1722 }
michael@0 1723 push.apply(allPaths, fillPaths);
michael@0 1724 fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies);
michael@0 1725 push.apply(allPaths, linePaths);
michael@0 1726 linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies);
michael@0 1727 if (defaultPath) {
michael@0 1728 allPaths.push(defaultPath);
michael@0 1729 defaultPath = null;
michael@0 1730 }
michael@0 1731 styles = {
michael@0 1732 fill0: 0,
michael@0 1733 fill1: 0,
michael@0 1734 line: 0
michael@0 1735 };
michael@0 1736 }
michael@0 1737 if (record.hasFillStyle0) {
michael@0 1738 styles.fill0 = record.fillStyle0;
michael@0 1739 }
michael@0 1740 if (record.hasFillStyle1) {
michael@0 1741 styles.fill1 = record.fillStyle1;
michael@0 1742 }
michael@0 1743 if (record.hasLineStyle) {
michael@0 1744 styles.line = record.lineStyle;
michael@0 1745 }
michael@0 1746 if (styles.fill1) {
michael@0 1747 path = fillPaths[styles.fill1 - 1];
michael@0 1748 } else if (styles.line) {
michael@0 1749 path = linePaths[styles.line - 1];
michael@0 1750 } else if (styles.fill0) {
michael@0 1751 path = fillPaths[styles.fill0 - 1];
michael@0 1752 }
michael@0 1753 if (record.move) {
michael@0 1754 x = record.moveX | 0;
michael@0 1755 y = record.moveY | 0;
michael@0 1756 }
michael@0 1757 if (path) {
michael@0 1758 segment = path.addSegment([], [], isMorph ? [] : null);
michael@0 1759 segment.commands.push(SHAPE_MOVE_TO);
michael@0 1760 segment.data.push(x, y);
michael@0 1761 if (isMorph) {
michael@0 1762 if (morphRecord.type === 0) {
michael@0 1763 morphX = morphRecord.moveX | 0;
michael@0 1764 morphY = morphRecord.moveY | 0;
michael@0 1765 } else {
michael@0 1766 morphX = x;
michael@0 1767 morphY = y;
michael@0 1768 j--;
michael@0 1769 }
michael@0 1770 segment.morphData.push(morphX, morphY);
michael@0 1771 }
michael@0 1772 }
michael@0 1773 } else {
michael@0 1774 if (!segment) {
michael@0 1775 if (!defaultPath) {
michael@0 1776 var style = {
michael@0 1777 color: {
michael@0 1778 red: 0,
michael@0 1779 green: 0,
michael@0 1780 blue: 0,
michael@0 1781 alpha: 255
michael@0 1782 },
michael@0 1783 width: 20
michael@0 1784 };
michael@0 1785 defaultPath = new SegmentedPath(null, processStyle(style, true));
michael@0 1786 }
michael@0 1787 segment = defaultPath.addSegment([], [], isMorph ? [] : null);
michael@0 1788 segment.commands.push(SHAPE_MOVE_TO);
michael@0 1789 segment.data.push(x, y);
michael@0 1790 if (isMorph) {
michael@0 1791 segment.morphData.push(morphX, morphY);
michael@0 1792 }
michael@0 1793 }
michael@0 1794 if (isMorph) {
michael@0 1795 while (morphRecord && morphRecord.type === 0) {
michael@0 1796 morphRecord = recordsMorph[j++];
michael@0 1797 }
michael@0 1798 if (!morphRecord) {
michael@0 1799 morphRecord = record;
michael@0 1800 }
michael@0 1801 }
michael@0 1802 if (record.isStraight && (!isMorph || morphRecord.isStraight)) {
michael@0 1803 x += record.deltaX | 0;
michael@0 1804 y += record.deltaY | 0;
michael@0 1805 segment.commands.push(SHAPE_LINE_TO);
michael@0 1806 segment.data.push(x, y);
michael@0 1807 if (isMorph) {
michael@0 1808 morphX += morphRecord.deltaX | 0;
michael@0 1809 morphY += morphRecord.deltaY | 0;
michael@0 1810 segment.morphData.push(morphX, morphY);
michael@0 1811 }
michael@0 1812 } else {
michael@0 1813 var cx, cy;
michael@0 1814 var deltaX, deltaY;
michael@0 1815 if (!record.isStraight) {
michael@0 1816 cx = x + record.controlDeltaX | 0;
michael@0 1817 cy = y + record.controlDeltaY | 0;
michael@0 1818 x = cx + record.anchorDeltaX | 0;
michael@0 1819 y = cy + record.anchorDeltaY | 0;
michael@0 1820 } else {
michael@0 1821 deltaX = record.deltaX | 0;
michael@0 1822 deltaY = record.deltaY | 0;
michael@0 1823 cx = x + (deltaX >> 1);
michael@0 1824 cy = y + (deltaY >> 1);
michael@0 1825 x += deltaX;
michael@0 1826 y += deltaY;
michael@0 1827 }
michael@0 1828 segment.commands.push(SHAPE_CURVE_TO);
michael@0 1829 segment.data.push(cx, cy, x, y);
michael@0 1830 if (isMorph) {
michael@0 1831 if (!morphRecord.isStraight) {
michael@0 1832 cx = morphX + morphRecord.controlDeltaX | 0;
michael@0 1833 cy = morphY + morphRecord.controlDeltaY | 0;
michael@0 1834 morphX = cx + morphRecord.anchorDeltaX | 0;
michael@0 1835 morphY = cy + morphRecord.anchorDeltaY | 0;
michael@0 1836 } else {
michael@0 1837 deltaX = morphRecord.deltaX | 0;
michael@0 1838 deltaY = morphRecord.deltaY | 0;
michael@0 1839 cx = morphX + (deltaX >> 1);
michael@0 1840 cy = morphY + (deltaY >> 1);
michael@0 1841 morphX += deltaX;
michael@0 1842 morphY += deltaY;
michael@0 1843 }
michael@0 1844 segment.morphData.push(cx, cy, morphX, morphY);
michael@0 1845 }
michael@0 1846 }
michael@0 1847 }
michael@0 1848 }
michael@0 1849 applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
michael@0 1850 if (allPaths) {
michael@0 1851 push.apply(allPaths, fillPaths);
michael@0 1852 } else {
michael@0 1853 allPaths = fillPaths;
michael@0 1854 }
michael@0 1855 push.apply(allPaths, linePaths);
michael@0 1856 if (defaultPath) {
michael@0 1857 allPaths.push(defaultPath);
michael@0 1858 }
michael@0 1859 var removeCount = 0;
michael@0 1860 for (i = 0; i < allPaths.length; i++) {
michael@0 1861 path = allPaths[i];
michael@0 1862 if (!path.head()) {
michael@0 1863 removeCount++;
michael@0 1864 continue;
michael@0 1865 }
michael@0 1866 allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables);
michael@0 1867 }
michael@0 1868 allPaths.length -= removeCount;
michael@0 1869 return allPaths;
michael@0 1870 }
michael@0 1871 function segmentedPathToShapePath(path, isMorph, transferables) {
michael@0 1872 var start = path.head();
michael@0 1873 var end = start;
michael@0 1874 var finalRoot = null;
michael@0 1875 var finalHead = null;
michael@0 1876 var skippedMoves = 0;
michael@0 1877 var current = start.prev;
michael@0 1878 while (start) {
michael@0 1879 while (current) {
michael@0 1880 if (path.segmentsConnect(current, start)) {
michael@0 1881 if (current.next !== start) {
michael@0 1882 path.removeSegment(current);
michael@0 1883 path.insertSegment(current, start);
michael@0 1884 }
michael@0 1885 start = current;
michael@0 1886 current = start.prev;
michael@0 1887 skippedMoves++;
michael@0 1888 continue;
michael@0 1889 }
michael@0 1890 if (path.segmentsConnect(end, current)) {
michael@0 1891 path.removeSegment(current);
michael@0 1892 end.next = current;
michael@0 1893 current = current.prev;
michael@0 1894 end.next.prev = end;
michael@0 1895 end.next.next = null;
michael@0 1896 end = end.next;
michael@0 1897 skippedMoves++;
michael@0 1898 continue;
michael@0 1899 }
michael@0 1900 current = current.prev;
michael@0 1901 }
michael@0 1902 current = start.prev;
michael@0 1903 if (!finalRoot) {
michael@0 1904 finalRoot = start;
michael@0 1905 finalHead = end;
michael@0 1906 } else {
michael@0 1907 finalHead.next = start;
michael@0 1908 start.prev = finalHead;
michael@0 1909 finalHead = end;
michael@0 1910 finalHead.next = null;
michael@0 1911 }
michael@0 1912 if (!current) {
michael@0 1913 break;
michael@0 1914 }
michael@0 1915 start = end = current;
michael@0 1916 current = start.prev;
michael@0 1917 }
michael@0 1918 var totalCommandsLength = -skippedMoves;
michael@0 1919 var totalDataLength = -skippedMoves << 1;
michael@0 1920 current = finalRoot;
michael@0 1921 while (current) {
michael@0 1922 totalCommandsLength += current.commands.length;
michael@0 1923 totalDataLength += current.data.length;
michael@0 1924 current = current.next;
michael@0 1925 }
michael@0 1926 var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables);
michael@0 1927 var allCommands = shape.commands;
michael@0 1928 var allData = shape.data;
michael@0 1929 var allMorphData = shape.morphData;
michael@0 1930 var commandsIndex = 0;
michael@0 1931 var dataIndex = 0;
michael@0 1932 current = finalRoot;
michael@0 1933 while (current) {
michael@0 1934 var commands = current.commands;
michael@0 1935 var data = current.data;
michael@0 1936 var morphData = current.morphData;
michael@0 1937 var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]);
michael@0 1938 for (var i = offset; i < commands.length; i++, commandsIndex++) {
michael@0 1939 allCommands[commandsIndex] = commands[i];
michael@0 1940 }
michael@0 1941 for (i = offset << 1; i < data.length; i++, dataIndex++) {
michael@0 1942 allData[dataIndex] = data[i];
michael@0 1943 if (isMorph) {
michael@0 1944 allMorphData[dataIndex] = morphData[i];
michael@0 1945 }
michael@0 1946 }
michael@0 1947 current = current.next;
michael@0 1948 }
michael@0 1949 return shape;
michael@0 1950 }
michael@0 1951 var CAPS_STYLE_TYPES = [
michael@0 1952 'round',
michael@0 1953 'none',
michael@0 1954 'square'
michael@0 1955 ];
michael@0 1956 var JOIN_STYLE_TYPES = [
michael@0 1957 'round',
michael@0 1958 'bevel',
michael@0 1959 'miter'
michael@0 1960 ];
michael@0 1961 function processStyle(style, isLineStyle, dictionary, dependencies) {
michael@0 1962 if (isLineStyle) {
michael@0 1963 style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0];
michael@0 1964 style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0];
michael@0 1965 style.miterLimit = (style.miterLimitFactor || 1.5) * 2;
michael@0 1966 if (!style.color && style.hasFill) {
michael@0 1967 var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies);
michael@0 1968 style.style = fillStyle.style;
michael@0 1969 style.type = fillStyle.type;
michael@0 1970 style.transform = fillStyle.transform;
michael@0 1971 style.records = fillStyle.records;
michael@0 1972 style.focalPoint = fillStyle.focalPoint;
michael@0 1973 style.bitmapId = fillStyle.bitmapId;
michael@0 1974 style.repeat = fillStyle.repeat;
michael@0 1975 style.fillStyle = null;
michael@0 1976 return style;
michael@0 1977 }
michael@0 1978 }
michael@0 1979 var color;
michael@0 1980 if (style.type === undefined || style.type === GRAPHICS_FILL_SOLID) {
michael@0 1981 color = style.color;
michael@0 1982 style.style = 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
michael@0 1983 style.color = null;
michael@0 1984 return style;
michael@0 1985 }
michael@0 1986 var scale;
michael@0 1987 switch (style.type) {
michael@0 1988 case GRAPHICS_FILL_LINEAR_GRADIENT:
michael@0 1989 case GRAPHICS_FILL_RADIAL_GRADIENT:
michael@0 1990 case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT:
michael@0 1991 scale = 819.2;
michael@0 1992 break;
michael@0 1993 case GRAPHICS_FILL_REPEATING_BITMAP:
michael@0 1994 case GRAPHICS_FILL_CLIPPED_BITMAP:
michael@0 1995 case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
michael@0 1996 case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
michael@0 1997 if (dictionary[style.bitmapId]) {
michael@0 1998 dependencies.push(dictionary[style.bitmapId].id);
michael@0 1999 scale = 0.05;
michael@0 2000 }
michael@0 2001 break;
michael@0 2002 default:
michael@0 2003 fail('invalid fill style', 'shape');
michael@0 2004 }
michael@0 2005 if (!style.matrix) {
michael@0 2006 return style;
michael@0 2007 }
michael@0 2008 var matrix = style.matrix;
michael@0 2009 style.transform = {
michael@0 2010 a: matrix.a * scale,
michael@0 2011 b: matrix.b * scale,
michael@0 2012 c: matrix.c * scale,
michael@0 2013 d: matrix.d * scale,
michael@0 2014 e: matrix.tx,
michael@0 2015 f: matrix.ty
michael@0 2016 };
michael@0 2017 style.matrix = null;
michael@0 2018 return style;
michael@0 2019 }
michael@0 2020 function createPathsList(styles, isLineStyle, dictionary, dependencies) {
michael@0 2021 var paths = [];
michael@0 2022 for (var i = 0; i < styles.length; i++) {
michael@0 2023 var style = processStyle(styles[i], isLineStyle, dictionary, dependencies);
michael@0 2024 if (!isLineStyle) {
michael@0 2025 paths[i] = new SegmentedPath(style, null);
michael@0 2026 } else {
michael@0 2027 paths[i] = new SegmentedPath(null, style);
michael@0 2028 }
michael@0 2029 }
michael@0 2030 return paths;
michael@0 2031 }
michael@0 2032 function defineShape(tag, dictionary) {
michael@0 2033 var dependencies = [];
michael@0 2034 var transferables = [];
michael@0 2035 var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies);
michael@0 2036 var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies);
michael@0 2037 var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables);
michael@0 2038 if (tag.bboxMorph) {
michael@0 2039 var mbox = tag.bboxMorph;
michael@0 2040 extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin);
michael@0 2041 extendBoundsByPoint(tag.bbox, mbox.xMax, mbox.yMax);
michael@0 2042 mbox = tag.strokeBboxMorph;
michael@0 2043 if (mbox) {
michael@0 2044 extendBoundsByPoint(tag.strokeBbox, mbox.xMin, mbox.yMin);
michael@0 2045 extendBoundsByPoint(tag.strokeBbox, mbox.xMax, mbox.yMax);
michael@0 2046 }
michael@0 2047 }
michael@0 2048 return {
michael@0 2049 type: 'shape',
michael@0 2050 id: tag.id,
michael@0 2051 strokeBbox: tag.strokeBbox,
michael@0 2052 strokeBboxMorph: tag.strokeBboxMorph,
michael@0 2053 bbox: tag.bbox,
michael@0 2054 bboxMorph: tag.bboxMorph,
michael@0 2055 isMorph: tag.isMorph,
michael@0 2056 paths: paths,
michael@0 2057 require: dependencies.length ? dependencies : null,
michael@0 2058 transferables: transferables
michael@0 2059 };
michael@0 2060 }
michael@0 2061 function logShape(paths, bbox) {
michael@0 2062 var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) {
michael@0 2063 return path.serialize();
michael@0 2064 }).join() + ']}';
michael@0 2065 console.log(output);
michael@0 2066 }
michael@0 2067 function SegmentedPath(fillStyle, lineStyle) {
michael@0 2068 this.fillStyle = fillStyle;
michael@0 2069 this.lineStyle = lineStyle;
michael@0 2070 this._head = null;
michael@0 2071 }
michael@0 2072 SegmentedPath.prototype = {
michael@0 2073 addSegment: function (commands, data, morphData) {
michael@0 2074 var segment = {
michael@0 2075 commands: commands,
michael@0 2076 data: data,
michael@0 2077 morphData: morphData,
michael@0 2078 prev: this._head,
michael@0 2079 next: null
michael@0 2080 };
michael@0 2081 if (this._head) {
michael@0 2082 this._head.next = segment;
michael@0 2083 }
michael@0 2084 this._head = segment;
michael@0 2085 return segment;
michael@0 2086 },
michael@0 2087 removeSegment: function (segment) {
michael@0 2088 if (segment.prev) {
michael@0 2089 segment.prev.next = segment.next;
michael@0 2090 }
michael@0 2091 if (segment.next) {
michael@0 2092 segment.next.prev = segment.prev;
michael@0 2093 }
michael@0 2094 },
michael@0 2095 insertSegment: function (segment, next) {
michael@0 2096 var prev = next.prev;
michael@0 2097 segment.prev = prev;
michael@0 2098 segment.next = next;
michael@0 2099 if (prev) {
michael@0 2100 prev.next = segment;
michael@0 2101 }
michael@0 2102 next.prev = segment;
michael@0 2103 },
michael@0 2104 head: function () {
michael@0 2105 return this._head;
michael@0 2106 },
michael@0 2107 segmentsConnect: function (first, second) {
michael@0 2108 var firstLength = first.data.length;
michael@0 2109 return first.data[firstLength - 2] === second.data[0] && first.data[firstLength - 1] === second.data[1];
michael@0 2110 }
michael@0 2111 };
michael@0 2112 var SHAPE_MOVE_TO = 1;
michael@0 2113 var SHAPE_LINE_TO = 2;
michael@0 2114 var SHAPE_CURVE_TO = 3;
michael@0 2115 var SHAPE_WIDE_MOVE_TO = 4;
michael@0 2116 var SHAPE_WIDE_LINE_TO = 5;
michael@0 2117 var SHAPE_CUBIC_CURVE_TO = 6;
michael@0 2118 var SHAPE_CIRCLE = 7;
michael@0 2119 var SHAPE_ELLIPSE = 8;
michael@0 2120 function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) {
michael@0 2121 this.fillStyle = fillStyle;
michael@0 2122 this.lineStyle = lineStyle;
michael@0 2123 if (commandsCount) {
michael@0 2124 this.commands = new Uint8Array(commandsCount);
michael@0 2125 this.data = new Int32Array(dataLength);
michael@0 2126 this.morphData = isMorph ? new Int32Array(dataLength) : null;
michael@0 2127 } else {
michael@0 2128 this.commands = [];
michael@0 2129 this.data = [];
michael@0 2130 }
michael@0 2131 this.bounds = null;
michael@0 2132 this.strokeBounds = null;
michael@0 2133 this.isMorph = !(!isMorph);
michael@0 2134 this.fullyInitialized = false;
michael@0 2135 if (inWorker) {
michael@0 2136 this.buffers = [
michael@0 2137 this.commands.buffer,
michael@0 2138 this.data.buffer
michael@0 2139 ];
michael@0 2140 transferables.push(this.commands.buffer, this.data.buffer);
michael@0 2141 if (isMorph) {
michael@0 2142 this.buffers.push(this.morphData.buffer);
michael@0 2143 transferables.push(this.morphData.buffer);
michael@0 2144 }
michael@0 2145 } else {
michael@0 2146 this.buffers = null;
michael@0 2147 }
michael@0 2148 }
michael@0 2149 ShapePath.prototype = {
michael@0 2150 get isEmpty() {
michael@0 2151 return this.commands.length === 0;
michael@0 2152 },
michael@0 2153 moveTo: function (x, y) {
michael@0 2154 if (this.commands[this.commands.length - 1] === SHAPE_MOVE_TO) {
michael@0 2155 this.data[this.data.length - 2] = x;
michael@0 2156 this.data[this.data.length - 1] = y;
michael@0 2157 return;
michael@0 2158 }
michael@0 2159 this.commands.push(SHAPE_MOVE_TO);
michael@0 2160 this.data.push(x, y);
michael@0 2161 },
michael@0 2162 lineTo: function (x, y) {
michael@0 2163 this.commands.push(SHAPE_LINE_TO);
michael@0 2164 this.data.push(x, y);
michael@0 2165 },
michael@0 2166 curveTo: function (controlX, controlY, anchorX, anchorY) {
michael@0 2167 this.commands.push(SHAPE_CURVE_TO);
michael@0 2168 this.data.push(controlX, controlY, anchorX, anchorY);
michael@0 2169 },
michael@0 2170 cubicCurveTo: function (control1X, control1Y, control2X, control2Y, anchorX, anchorY) {
michael@0 2171 this.commands.push(SHAPE_CUBIC_CURVE_TO);
michael@0 2172 this.data.push(control1X, control1Y, control2X, control2Y, anchorX, anchorY);
michael@0 2173 },
michael@0 2174 rect: function (x, y, w, h) {
michael@0 2175 var x2 = x + w;
michael@0 2176 var y2 = y + h;
michael@0 2177 this.commands.push(SHAPE_MOVE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO);
michael@0 2178 this.data.push(x, y, x2, y, x2, y2, x, y2, x, y);
michael@0 2179 },
michael@0 2180 circle: function (x, y, radius) {
michael@0 2181 this.commands.push(SHAPE_CIRCLE);
michael@0 2182 this.data.push(x, y, radius);
michael@0 2183 },
michael@0 2184 ellipse: function (x, y, radiusX, radiusY) {
michael@0 2185 this.commands.push(SHAPE_ELLIPSE);
michael@0 2186 this.data.push(x, y, radiusX, radiusY);
michael@0 2187 },
michael@0 2188 draw: function (ctx, clip, ratio, colorTransform) {
michael@0 2189 if (clip && !this.fillStyle) {
michael@0 2190 return;
michael@0 2191 }
michael@0 2192 ctx.beginPath();
michael@0 2193 var commands = this.commands;
michael@0 2194 var data = this.data;
michael@0 2195 var morphData = this.morphData;
michael@0 2196 var formOpen = false;
michael@0 2197 var formOpenX = 0;
michael@0 2198 var formOpenY = 0;
michael@0 2199 if (!this.isMorph) {
michael@0 2200 for (var j = 0, k = 0; j < commands.length; j++) {
michael@0 2201 switch (commands[j]) {
michael@0 2202 case SHAPE_MOVE_TO:
michael@0 2203 formOpen = true;
michael@0 2204 formOpenX = data[k++] / 20;
michael@0 2205 formOpenY = data[k++] / 20;
michael@0 2206 ctx.moveTo(formOpenX, formOpenY);
michael@0 2207 break;
michael@0 2208 case SHAPE_WIDE_MOVE_TO:
michael@0 2209 ctx.moveTo(data[k++] / 20, data[k++] / 20);
michael@0 2210 k += 2;
michael@0 2211 break;
michael@0 2212 case SHAPE_LINE_TO:
michael@0 2213 ctx.lineTo(data[k++] / 20, data[k++] / 20);
michael@0 2214 break;
michael@0 2215 case SHAPE_WIDE_LINE_TO:
michael@0 2216 ctx.lineTo(data[k++] / 20, data[k++] / 20);
michael@0 2217 k += 2;
michael@0 2218 break;
michael@0 2219 case SHAPE_CURVE_TO:
michael@0 2220 ctx.quadraticCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
michael@0 2221 break;
michael@0 2222 case SHAPE_CUBIC_CURVE_TO:
michael@0 2223 ctx.bezierCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
michael@0 2224 break;
michael@0 2225 case SHAPE_CIRCLE:
michael@0 2226 if (formOpen) {
michael@0 2227 ctx.lineTo(formOpenX, formOpenY);
michael@0 2228 formOpen = false;
michael@0 2229 }
michael@0 2230 ctx.moveTo((data[k] + data[k + 2]) / 20, data[k + 1] / 20);
michael@0 2231 ctx.arc(data[k++] / 20, data[k++] / 20, data[k++] / 20, 0, Math.PI * 2, false);
michael@0 2232 break;
michael@0 2233 case SHAPE_ELLIPSE:
michael@0 2234 if (formOpen) {
michael@0 2235 ctx.lineTo(formOpenX, formOpenY);
michael@0 2236 formOpen = false;
michael@0 2237 }
michael@0 2238 var x = data[k++];
michael@0 2239 var y = data[k++];
michael@0 2240 var rX = data[k++];
michael@0 2241 var rY = data[k++];
michael@0 2242 var radius;
michael@0 2243 if (rX !== rY) {
michael@0 2244 ctx.save();
michael@0 2245 var ellipseScale;
michael@0 2246 if (rX > rY) {
michael@0 2247 ellipseScale = rX / rY;
michael@0 2248 radius = rY;
michael@0 2249 x /= ellipseScale;
michael@0 2250 ctx.scale(ellipseScale, 1);
michael@0 2251 } else {
michael@0 2252 ellipseScale = rY / rX;
michael@0 2253 radius = rX;
michael@0 2254 y /= ellipseScale;
michael@0 2255 ctx.scale(1, ellipseScale);
michael@0 2256 }
michael@0 2257 }
michael@0 2258 ctx.moveTo((x + radius) / 20, y / 20);
michael@0 2259 ctx.arc(x / 20, y / 20, radius / 20, 0, Math.PI * 2, false);
michael@0 2260 if (rX !== rY) {
michael@0 2261 ctx.restore();
michael@0 2262 }
michael@0 2263 break;
michael@0 2264 default:
michael@0 2265 if (commands[j] === 0 && j === commands.length - 1) {
michael@0 2266 break;
michael@0 2267 }
michael@0 2268 console.warn('Unknown drawing command encountered: ' + commands[j]);
michael@0 2269 }
michael@0 2270 }
michael@0 2271 } else {
michael@0 2272 for (var j = 0, k = 0; j < commands.length; j++) {
michael@0 2273 switch (commands[j]) {
michael@0 2274 case SHAPE_MOVE_TO:
michael@0 2275 ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
michael@0 2276 break;
michael@0 2277 case SHAPE_LINE_TO:
michael@0 2278 ctx.lineTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
michael@0 2279 break;
michael@0 2280 case SHAPE_CURVE_TO:
michael@0 2281 ctx.quadraticCurveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
michael@0 2282 break;
michael@0 2283 default:
michael@0 2284 console.warn('Drawing command not supported for morph shapes: ' + commands[j]);
michael@0 2285 }
michael@0 2286 }
michael@0 2287 }
michael@0 2288 if (!clip) {
michael@0 2289 var fillStyle = this.fillStyle;
michael@0 2290 if (fillStyle) {
michael@0 2291 colorTransform.setFillStyle(ctx, fillStyle.style);
michael@0 2292 ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = fillStyle.smooth;
michael@0 2293 var m = fillStyle.transform;
michael@0 2294 ctx.save();
michael@0 2295 colorTransform.setAlpha(ctx);
michael@0 2296 if (m) {
michael@0 2297 ctx.transform(m.a, m.b, m.c, m.d, m.e / 20, m.f / 20);
michael@0 2298 }
michael@0 2299 ctx.fill();
michael@0 2300 ctx.restore();
michael@0 2301 }
michael@0 2302 var lineStyle = this.lineStyle;
michael@0 2303 if (lineStyle) {
michael@0 2304 colorTransform.setStrokeStyle(ctx, lineStyle.style);
michael@0 2305 ctx.save();
michael@0 2306 colorTransform.setAlpha(ctx);
michael@0 2307 ctx.lineWidth = Math.max(lineStyle.width / 20, 1);
michael@0 2308 ctx.lineCap = lineStyle.lineCap;
michael@0 2309 ctx.lineJoin = lineStyle.lineJoin;
michael@0 2310 ctx.miterLimit = lineStyle.miterLimit;
michael@0 2311 ctx.stroke();
michael@0 2312 ctx.restore();
michael@0 2313 }
michael@0 2314 } else {
michael@0 2315 ctx.fill();
michael@0 2316 }
michael@0 2317 ctx.closePath();
michael@0 2318 },
michael@0 2319 isPointInPath: function (x, y) {
michael@0 2320 if (!(this.fillStyle || this.lineStyle)) {
michael@0 2321 return false;
michael@0 2322 }
michael@0 2323 var bounds = this.strokeBounds || this.bounds || this._calculateBounds();
michael@0 2324 if (x < bounds.xMin || x > bounds.xMax || y < bounds.yMin || y > bounds.yMax) {
michael@0 2325 return false;
michael@0 2326 }
michael@0 2327 if (this.fillStyle && this.isPointInFill(x, y)) {
michael@0 2328 return true;
michael@0 2329 }
michael@0 2330 return this.lineStyle && this.lineStyle.width !== undefined && this.isPointInStroke(x, y);
michael@0 2331 },
michael@0 2332 isPointInFill: function (x, y) {
michael@0 2333 var commands = this.commands;
michael@0 2334 var data = this.data;
michael@0 2335 var length = commands.length;
michael@0 2336 var inside = false;
michael@0 2337 var fromX = 0;
michael@0 2338 var fromY = 0;
michael@0 2339 var toX = 0;
michael@0 2340 var toY = 0;
michael@0 2341 var localX;
michael@0 2342 var localY;
michael@0 2343 var cpX;
michael@0 2344 var cpY;
michael@0 2345 var rX;
michael@0 2346 var rY;
michael@0 2347 var formOpen = false;
michael@0 2348 var formOpenX = 0;
michael@0 2349 var formOpenY = 0;
michael@0 2350 for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
michael@0 2351 switch (commands[commandIndex]) {
michael@0 2352 case SHAPE_WIDE_MOVE_TO:
michael@0 2353 dataIndex += 2;
michael@0 2354 case SHAPE_MOVE_TO:
michael@0 2355 toX = data[dataIndex++];
michael@0 2356 toY = data[dataIndex++];
michael@0 2357 if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) {
michael@0 2358 inside = !inside;
michael@0 2359 }
michael@0 2360 formOpen = true;
michael@0 2361 formOpenX = toX;
michael@0 2362 formOpenY = toY;
michael@0 2363 break;
michael@0 2364 case SHAPE_WIDE_LINE_TO:
michael@0 2365 dataIndex += 2;
michael@0 2366 case SHAPE_LINE_TO:
michael@0 2367 toX = data[dataIndex++];
michael@0 2368 toY = data[dataIndex++];
michael@0 2369 if (intersectsLine(x, y, fromX, fromY, toX, toY)) {
michael@0 2370 inside = !inside;
michael@0 2371 }
michael@0 2372 break;
michael@0 2373 case SHAPE_CURVE_TO:
michael@0 2374 cpX = data[dataIndex++];
michael@0 2375 cpY = data[dataIndex++];
michael@0 2376 toX = data[dataIndex++];
michael@0 2377 toY = data[dataIndex++];
michael@0 2378 if (cpY > y === fromY > y && toY > y === fromY > y) {
michael@0 2379 break;
michael@0 2380 }
michael@0 2381 if (fromX >= x && cpX >= x && toX >= x) {
michael@0 2382 inside = !inside;
michael@0 2383 break;
michael@0 2384 }
michael@0 2385 var a = fromY - 2 * cpY + toY;
michael@0 2386 var c = fromY - y;
michael@0 2387 var b = 2 * (cpY - fromY);
michael@0 2388 var d = b * b - 4 * a * c;
michael@0 2389 if (d < 0) {
michael@0 2390 break;
michael@0 2391 }
michael@0 2392 d = Math.sqrt(d);
michael@0 2393 a = 1 / (a + a);
michael@0 2394 var t1 = (d - b) * a;
michael@0 2395 var t2 = (-b - d) * a;
michael@0 2396 if (t1 >= 0 && t1 <= 1 && quadraticBezier(fromX, cpX, toX, t1) > x) {
michael@0 2397 inside = !inside;
michael@0 2398 }
michael@0 2399 if (t2 >= 0 && t2 <= 1 && quadraticBezier(fromX, cpX, toX, t2) > x) {
michael@0 2400 inside = !inside;
michael@0 2401 }
michael@0 2402 break;
michael@0 2403 case SHAPE_CUBIC_CURVE_TO:
michael@0 2404 cpX = data[dataIndex++];
michael@0 2405 cpY = data[dataIndex++];
michael@0 2406 var cp2X = data[dataIndex++];
michael@0 2407 var cp2Y = data[dataIndex++];
michael@0 2408 toX = data[dataIndex++];
michael@0 2409 toY = data[dataIndex++];
michael@0 2410 if (cpY > y === fromY > y && cp2Y > y === fromY > y && toY > y === fromY > y) {
michael@0 2411 break;
michael@0 2412 }
michael@0 2413 if (fromX >= x && cpX >= x && cp2X >= x && toX >= x) {
michael@0 2414 inside = !inside;
michael@0 2415 break;
michael@0 2416 }
michael@0 2417 var roots = cubicXAtY(fromX, fromY, cpX, cpY, cp2X, cp2Y, toX, toY, y);
michael@0 2418 for (var i = roots.length; i--;) {
michael@0 2419 if (roots[i] >= x) {
michael@0 2420 inside = !inside;
michael@0 2421 }
michael@0 2422 }
michael@0 2423 break;
michael@0 2424 case SHAPE_CIRCLE:
michael@0 2425 toX = data[dataIndex++];
michael@0 2426 toY = data[dataIndex++];
michael@0 2427 var r = data[dataIndex++];
michael@0 2428 localX = x - toX;
michael@0 2429 localY = y - toY;
michael@0 2430 if (localX * localX + localY * localY < r * r) {
michael@0 2431 inside = !inside;
michael@0 2432 }
michael@0 2433 toX += r;
michael@0 2434 break;
michael@0 2435 case SHAPE_ELLIPSE:
michael@0 2436 cpX = data[dataIndex++];
michael@0 2437 cpY = data[dataIndex++];
michael@0 2438 rX = data[dataIndex++];
michael@0 2439 rY = data[dataIndex++];
michael@0 2440 localX = x - cpX;
michael@0 2441 localY = y - cpY;
michael@0 2442 if (localX * localX / (rX * rX) + localY * localY / (rY * rY) <= 1) {
michael@0 2443 inside = !inside;
michael@0 2444 }
michael@0 2445 toX = cpX + rX;
michael@0 2446 toY = cpY;
michael@0 2447 break;
michael@0 2448 default:
michael@0 2449 if (!inWorker) {
michael@0 2450 console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]);
michael@0 2451 }
michael@0 2452 }
michael@0 2453 fromX = toX;
michael@0 2454 fromY = toY;
michael@0 2455 }
michael@0 2456 if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) {
michael@0 2457 inside = !inside;
michael@0 2458 }
michael@0 2459 return inside;
michael@0 2460 },
michael@0 2461 isPointInStroke: function (x, y) {
michael@0 2462 var commands = this.commands;
michael@0 2463 var data = this.data;
michael@0 2464 var length = commands.length;
michael@0 2465 var width = this.lineStyle.width;
michael@0 2466 var halfWidth = width / 2;
michael@0 2467 var halfWidthSq = halfWidth * halfWidth;
michael@0 2468 var minX = x - halfWidth;
michael@0 2469 var maxX = x + halfWidth;
michael@0 2470 var minY = y - halfWidth;
michael@0 2471 var maxY = y + halfWidth;
michael@0 2472 var fromX = 0;
michael@0 2473 var fromY = 0;
michael@0 2474 var toX = 0;
michael@0 2475 var toY = 0;
michael@0 2476 var localX;
michael@0 2477 var localY;
michael@0 2478 var cpX;
michael@0 2479 var cpY;
michael@0 2480 var rX;
michael@0 2481 var rY;
michael@0 2482 var curveX;
michael@0 2483 var curveY;
michael@0 2484 var t;
michael@0 2485 for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
michael@0 2486 switch (commands[commandIndex]) {
michael@0 2487 case SHAPE_WIDE_MOVE_TO:
michael@0 2488 dataIndex += 2;
michael@0 2489 case SHAPE_MOVE_TO:
michael@0 2490 toX = data[dataIndex++];
michael@0 2491 toY = data[dataIndex++];
michael@0 2492 break;
michael@0 2493 case SHAPE_WIDE_LINE_TO:
michael@0 2494 dataIndex += 2;
michael@0 2495 case SHAPE_LINE_TO:
michael@0 2496 toX = data[dataIndex++];
michael@0 2497 toY = data[dataIndex++];
michael@0 2498 if (fromX === toX && fromY === toY) {
michael@0 2499 break;
michael@0 2500 }
michael@0 2501 if (maxX < fromX && maxX < toX || minX > fromX && minX > toX || maxY < fromY && maxY < toY || minY > fromY && minY > toY) {
michael@0 2502 break;
michael@0 2503 }
michael@0 2504 if (toX === fromX || toY === fromY) {
michael@0 2505 return true;
michael@0 2506 }
michael@0 2507 t = ((x - fromX) * (toX - fromX) + (y - fromY) * (toY - fromY)) / distanceSq(fromX, fromY, toX, toY);
michael@0 2508 if (t < 0) {
michael@0 2509 if (distanceSq(x, y, fromX, fromY) <= halfWidthSq) {
michael@0 2510 return true;
michael@0 2511 }
michael@0 2512 break;
michael@0 2513 }
michael@0 2514 if (t > 1) {
michael@0 2515 if (distanceSq(x, y, toX, toY) <= halfWidthSq) {
michael@0 2516 return true;
michael@0 2517 }
michael@0 2518 break;
michael@0 2519 }
michael@0 2520 if (distanceSq(x, y, fromX + t * (toX - fromX), fromY + t * (toY - fromY)) <= halfWidthSq) {
michael@0 2521 return true;
michael@0 2522 }
michael@0 2523 break;
michael@0 2524 case SHAPE_CURVE_TO:
michael@0 2525 cpX = data[dataIndex++];
michael@0 2526 cpY = data[dataIndex++];
michael@0 2527 toX = data[dataIndex++];
michael@0 2528 toY = data[dataIndex++];
michael@0 2529 var extremeX = quadraticBezierExtreme(fromX, cpX, toX);
michael@0 2530 if (maxX < fromX && maxX < extremeX && maxX < toX || minX > fromX && minX > extremeX && minX > toX) {
michael@0 2531 break;
michael@0 2532 }
michael@0 2533 var extremeY = quadraticBezierExtreme(fromY, cpY, toY);
michael@0 2534 if (maxY < fromY && maxY < extremeY && maxY < toY || minY > fromY && minY > extremeY && minY > toY) {
michael@0 2535 break;
michael@0 2536 }
michael@0 2537 for (t = 0; t < 1; t += 0.02) {
michael@0 2538 curveX = quadraticBezier(fromX, cpX, toX, t);
michael@0 2539 if (curveX < minX || curveX > maxX) {
michael@0 2540 continue;
michael@0 2541 }
michael@0 2542 curveY = quadraticBezier(fromY, cpY, toY, t);
michael@0 2543 if (curveY < minY || curveY > maxY) {
michael@0 2544 continue;
michael@0 2545 }
michael@0 2546 if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
michael@0 2547 return true;
michael@0 2548 }
michael@0 2549 }
michael@0 2550 break;
michael@0 2551 case SHAPE_CUBIC_CURVE_TO:
michael@0 2552 cpX = data[dataIndex++];
michael@0 2553 cpY = data[dataIndex++];
michael@0 2554 var cp2X = data[dataIndex++];
michael@0 2555 var cp2Y = data[dataIndex++];
michael@0 2556 toX = data[dataIndex++];
michael@0 2557 toY = data[dataIndex++];
michael@0 2558 var extremesX = cubicBezierExtremes(fromX, cpX, cp2X, toX);
michael@0 2559 while (extremesX.length < 2) {
michael@0 2560 extremesX.push(toX);
michael@0 2561 }
michael@0 2562 if (maxX < fromX && maxX < toX && maxX < extremesX[0] && maxX < extremesX[1] || minX > fromX && minX > toX && minX > extremesX[0] && minX > extremesX[1]) {
michael@0 2563 break;
michael@0 2564 }
michael@0 2565 var extremesY = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
michael@0 2566 while (extremesY.length < 2) {
michael@0 2567 extremesY.push(toY);
michael@0 2568 }
michael@0 2569 if (maxY < fromY && maxY < toY && maxY < extremesY[0] && maxY < extremesY[1] || minY > fromY && minY > toY && minY > extremesY[0] && minY > extremesY[1]) {
michael@0 2570 break;
michael@0 2571 }
michael@0 2572 for (t = 0; t < 1; t += 0.02) {
michael@0 2573 curveX = cubicBezier(fromX, cpX, cp2X, toX, t);
michael@0 2574 if (curveX < minX || curveX > maxX) {
michael@0 2575 continue;
michael@0 2576 }
michael@0 2577 curveY = cubicBezier(fromY, cpY, cp2Y, toY, t);
michael@0 2578 if (curveY < minY || curveY > maxY) {
michael@0 2579 continue;
michael@0 2580 }
michael@0 2581 if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
michael@0 2582 return true;
michael@0 2583 }
michael@0 2584 }
michael@0 2585 break;
michael@0 2586 case SHAPE_CIRCLE:
michael@0 2587 cpX = data[dataIndex++];
michael@0 2588 cpY = data[dataIndex++];
michael@0 2589 var r = data[dataIndex++];
michael@0 2590 toX = cpX + r;
michael@0 2591 toY = cpY;
michael@0 2592 if (maxX < cpX - r || minX > cpX + r || maxY < cpY - r || minY > cpY + r) {
michael@0 2593 break;
michael@0 2594 }
michael@0 2595 localX = x - cpX;
michael@0 2596 localY = y - cpY;
michael@0 2597 var rMin = r - halfWidth;
michael@0 2598 var rMax = r + halfWidth;
michael@0 2599 var distSq = localX * localX + localY * localY;
michael@0 2600 if (distSq >= rMin * rMin && distSq <= rMax * rMax) {
michael@0 2601 return true;
michael@0 2602 }
michael@0 2603 break;
michael@0 2604 case SHAPE_ELLIPSE:
michael@0 2605 cpX = data[dataIndex++];
michael@0 2606 cpY = data[dataIndex++];
michael@0 2607 rX = data[dataIndex++];
michael@0 2608 rY = data[dataIndex++];
michael@0 2609 toX = cpX + rX;
michael@0 2610 toY = cpY;
michael@0 2611 localX = Math.abs(x - cpX);
michael@0 2612 localY = Math.abs(y - cpY);
michael@0 2613 localX -= halfWidth;
michael@0 2614 localY -= halfWidth;
michael@0 2615 if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
michael@0 2616 break;
michael@0 2617 }
michael@0 2618 localX += width;
michael@0 2619 localY += width;
michael@0 2620 if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
michael@0 2621 return true;
michael@0 2622 }
michael@0 2623 break;
michael@0 2624 default:
michael@0 2625 if (!inWorker) {
michael@0 2626 console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]);
michael@0 2627 }
michael@0 2628 }
michael@0 2629 fromX = toX;
michael@0 2630 fromY = toY;
michael@0 2631 }
michael@0 2632 return false;
michael@0 2633 },
michael@0 2634 getBounds: function (includeStroke) {
michael@0 2635 var bounds = includeStroke ? this.strokeBounds : this.bounds;
michael@0 2636 if (!bounds) {
michael@0 2637 this._calculateBounds();
michael@0 2638 bounds = includeStroke ? this.strokeBounds : this.bounds;
michael@0 2639 }
michael@0 2640 return bounds;
michael@0 2641 },
michael@0 2642 _calculateBounds: function () {
michael@0 2643 var commands = this.commands;
michael@0 2644 var data = this.data;
michael@0 2645 var length = commands.length;
michael@0 2646 var bounds;
michael@0 2647 if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_CUBIC_CURVE_TO) {
michael@0 2648 bounds = {
michael@0 2649 xMin: data[0],
michael@0 2650 yMin: data[1]
michael@0 2651 };
michael@0 2652 } else {
michael@0 2653 bounds = {
michael@0 2654 xMin: 0,
michael@0 2655 yMin: 0
michael@0 2656 };
michael@0 2657 }
michael@0 2658 bounds.xMax = bounds.xMin;
michael@0 2659 bounds.yMax = bounds.yMin;
michael@0 2660 var fromX = bounds.xMin;
michael@0 2661 var fromY = bounds.yMin;
michael@0 2662 for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
michael@0 2663 var toX;
michael@0 2664 var toY;
michael@0 2665 var cpX;
michael@0 2666 var cpY;
michael@0 2667 switch (commands[commandIndex]) {
michael@0 2668 case SHAPE_WIDE_MOVE_TO:
michael@0 2669 dataIndex += 2;
michael@0 2670 case SHAPE_MOVE_TO:
michael@0 2671 toX = data[dataIndex++];
michael@0 2672 toY = data[dataIndex++];
michael@0 2673 extendBoundsByPoint(bounds, toX, toY);
michael@0 2674 break;
michael@0 2675 case SHAPE_WIDE_LINE_TO:
michael@0 2676 dataIndex += 2;
michael@0 2677 case SHAPE_LINE_TO:
michael@0 2678 toX = data[dataIndex++];
michael@0 2679 toY = data[dataIndex++];
michael@0 2680 extendBoundsByPoint(bounds, toX, toY);
michael@0 2681 break;
michael@0 2682 case SHAPE_CURVE_TO:
michael@0 2683 cpX = data[dataIndex++];
michael@0 2684 cpY = data[dataIndex++];
michael@0 2685 toX = data[dataIndex++];
michael@0 2686 toY = data[dataIndex++];
michael@0 2687 extendBoundsByPoint(bounds, toX, toY);
michael@0 2688 if (cpX < fromX || cpX > toX) {
michael@0 2689 extendBoundsByX(bounds, quadraticBezierExtreme(fromX, cpX, toX));
michael@0 2690 }
michael@0 2691 if (cpY < fromY || cpY > toY) {
michael@0 2692 extendBoundsByY(bounds, quadraticBezierExtreme(fromY, cpY, toY));
michael@0 2693 }
michael@0 2694 break;
michael@0 2695 case SHAPE_CUBIC_CURVE_TO:
michael@0 2696 cpX = data[dataIndex++];
michael@0 2697 cpY = data[dataIndex++];
michael@0 2698 var cp2X = data[dataIndex++];
michael@0 2699 var cp2Y = data[dataIndex++];
michael@0 2700 toX = data[dataIndex++];
michael@0 2701 toY = data[dataIndex++];
michael@0 2702 extendBoundsByPoint(bounds, toX, toY);
michael@0 2703 var extremes;
michael@0 2704 var i;
michael@0 2705 if (cpX < fromX || cp2X < fromX || cpX > toX || cp2X > toX) {
michael@0 2706 extremes = cubicBezierExtremes(fromX, cpX, cp2X, toX);
michael@0 2707 for (i = extremes.length; i--;) {
michael@0 2708 extendBoundsByX(bounds, extremes[i]);
michael@0 2709 }
michael@0 2710 }
michael@0 2711 if (cpY < fromY || cp2Y < fromY || cpY > toY || cp2Y > toY) {
michael@0 2712 extremes = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
michael@0 2713 for (i = extremes.length; i--;) {
michael@0 2714 extendBoundsByY(bounds, extremes[i]);
michael@0 2715 }
michael@0 2716 }
michael@0 2717 break;
michael@0 2718 case SHAPE_CIRCLE:
michael@0 2719 toX = data[dataIndex++];
michael@0 2720 toY = data[dataIndex++];
michael@0 2721 var radius = data[dataIndex++];
michael@0 2722 extendBoundsByPoint(bounds, toX - radius, toY - radius);
michael@0 2723 extendBoundsByPoint(bounds, toX + radius, toY + radius);
michael@0 2724 toX += radius;
michael@0 2725 break;
michael@0 2726 case SHAPE_ELLIPSE:
michael@0 2727 toX = data[dataIndex++];
michael@0 2728 toY = data[dataIndex++];
michael@0 2729 var radiusX = data[dataIndex++];
michael@0 2730 var radiusY = data[dataIndex++];
michael@0 2731 extendBoundsByPoint(bounds, toX - radiusX, toY - radiusY);
michael@0 2732 extendBoundsByPoint(bounds, toX + radiusX, toY + radiusY);
michael@0 2733 toX += radiusX;
michael@0 2734 break;
michael@0 2735 default:
michael@0 2736 if (!inWorker) {
michael@0 2737 console.warn('Drawing command not handled in bounds calculation: ' + commands[commandIndex]);
michael@0 2738 }
michael@0 2739 }
michael@0 2740 fromX = toX;
michael@0 2741 fromY = toY;
michael@0 2742 }
michael@0 2743 this.bounds = bounds;
michael@0 2744 if (this.lineStyle) {
michael@0 2745 var halfLineWidth = this.lineStyle.width / 2;
michael@0 2746 this.strokeBounds = {
michael@0 2747 xMin: bounds.xMin - halfLineWidth,
michael@0 2748 yMin: bounds.yMin - halfLineWidth,
michael@0 2749 xMax: bounds.xMax + halfLineWidth,
michael@0 2750 yMax: bounds.yMax + halfLineWidth
michael@0 2751 };
michael@0 2752 return this.strokeBounds;
michael@0 2753 } else {
michael@0 2754 this.strokeBounds = bounds;
michael@0 2755 }
michael@0 2756 return bounds;
michael@0 2757 },
michael@0 2758 serialize: function () {
michael@0 2759 var output = '{';
michael@0 2760 if (this.fillStyle) {
michael@0 2761 output += '"fill":' + JSON.stringify(this.fillStyle) + ',';
michael@0 2762 }
michael@0 2763 if (this.lineStyle) {
michael@0 2764 output += '"stroke":' + JSON.stringify(this.lineStyle) + ',';
michael@0 2765 }
michael@0 2766 output += '"commands":[' + Array.apply([], this.commands).join() + '],';
michael@0 2767 output += '"data":[' + Array.apply([], this.data).join() + ']';
michael@0 2768 return output + '}';
michael@0 2769 }
michael@0 2770 };
michael@0 2771 ShapePath.fromPlainObject = function (obj) {
michael@0 2772 var path = new ShapePath(obj.fill || null, obj.stroke || null);
michael@0 2773 path.commands = new Uint8Array(obj.commands);
michael@0 2774 path.data = new Int32Array(obj.data);
michael@0 2775 if (!inWorker) {
michael@0 2776 finishShapePath(path);
michael@0 2777 }
michael@0 2778 return path;
michael@0 2779 };
michael@0 2780 function distanceSq(x1, y1, x2, y2) {
michael@0 2781 var dX = x2 - x1;
michael@0 2782 var dY = y2 - y1;
michael@0 2783 return dX * dX + dY * dY;
michael@0 2784 }
michael@0 2785 function intersectsLine(x, y, x1, y1, x2, y2) {
michael@0 2786 return y2 > y !== y1 > y && x < (x1 - x2) * (y - y2) / (y1 - y2) + x2;
michael@0 2787 }
michael@0 2788 function quadraticBezier(from, cp, to, t) {
michael@0 2789 var inverseT = 1 - t;
michael@0 2790 return from * inverseT * inverseT + 2 * cp * inverseT * t + to * t * t;
michael@0 2791 }
michael@0 2792 function quadraticBezierExtreme(from, cp, to) {
michael@0 2793 var t = (from - cp) / (from - 2 * cp + to);
michael@0 2794 if (t < 0) {
michael@0 2795 return from;
michael@0 2796 }
michael@0 2797 if (t > 1) {
michael@0 2798 return to;
michael@0 2799 }
michael@0 2800 return quadraticBezier(from, cp, to, t);
michael@0 2801 }
michael@0 2802 function cubicBezier(from, cp, cp2, to, t) {
michael@0 2803 var tSq = t * t;
michael@0 2804 var inverseT = 1 - t;
michael@0 2805 var inverseTSq = inverseT * inverseT;
michael@0 2806 return from * inverseT * inverseTSq + 3 * cp * t * inverseTSq + 3 * cp2 * inverseT * tSq + to * t * tSq;
michael@0 2807 }
michael@0 2808 function cubicBezierExtremes(from, cp, cp2, to) {
michael@0 2809 var d1 = cp - from;
michael@0 2810 var d2 = cp2 - cp;
michael@0 2811 d2 *= 2;
michael@0 2812 var d3 = to - cp2;
michael@0 2813 if (d1 + d3 === d2) {
michael@0 2814 d3 *= 1.0001;
michael@0 2815 }
michael@0 2816 var fHead = 2 * d1 - d2;
michael@0 2817 var part1 = d2 - 2 * d1;
michael@0 2818 var fCenter = Math.sqrt(part1 * part1 - 4 * d1 * (d1 - d2 + d3));
michael@0 2819 var fTail = 2 * (d1 - d2 + d3);
michael@0 2820 var t1 = (fHead + fCenter) / fTail;
michael@0 2821 var t2 = (fHead - fCenter) / fTail;
michael@0 2822 var result = [];
michael@0 2823 if (t1 >= 0 && t1 <= 1) {
michael@0 2824 result.push(cubicBezier(from, cp, cp2, to, t1));
michael@0 2825 }
michael@0 2826 if (t2 >= 0 && t2 <= 1) {
michael@0 2827 result.push(cubicBezier(from, cp, cp2, to, t2));
michael@0 2828 }
michael@0 2829 return result;
michael@0 2830 }
michael@0 2831 function cubicXAtY(x0, y0, cx, cy, cx1, cy1, x1, y1, y) {
michael@0 2832 var dX = 3 * (cx - x0);
michael@0 2833 var dY = 3 * (cy - y0);
michael@0 2834 var bX = 3 * (cx1 - cx) - dX;
michael@0 2835 var bY = 3 * (cy1 - cy) - dY;
michael@0 2836 var c3X = x1 - x0 - dX - bX;
michael@0 2837 var c3Y = y1 - y0 - dY - bY;
michael@0 2838 function f(t) {
michael@0 2839 return t * (dY + t * (bY + t * c3Y)) + y0 - y;
michael@0 2840 }
michael@0 2841 function pointAt(t) {
michael@0 2842 if (t < 0) {
michael@0 2843 t = 0;
michael@0 2844 } else if (t > 1) {
michael@0 2845 t = 1;
michael@0 2846 }
michael@0 2847 return x0 + t * (dX + t * (bX + t * c3X));
michael@0 2848 }
michael@0 2849 function bisectCubicBezierRange(f, l, r, limit) {
michael@0 2850 if (Math.abs(r - l) <= limit) {
michael@0 2851 return;
michael@0 2852 }
michael@0 2853 var middle = 0.5 * (l + r);
michael@0 2854 if (f(l) * f(r) <= 0) {
michael@0 2855 left = l;
michael@0 2856 right = r;
michael@0 2857 return;
michael@0 2858 }
michael@0 2859 bisectCubicBezierRange(f, l, middle, limit);
michael@0 2860 bisectCubicBezierRange(f, middle, r, limit);
michael@0 2861 }
michael@0 2862 var left = 0;
michael@0 2863 var right = 1;
michael@0 2864 bisectCubicBezierRange(f, 0, 1, 0.05);
michael@0 2865 var t0 = findRoot(left, right, f, 50, 0.000001);
michael@0 2866 var evalResult = Math.abs(f(t0));
michael@0 2867 if (evalResult > 0.00001) {
michael@0 2868 return [];
michael@0 2869 }
michael@0 2870 var result = [];
michael@0 2871 if (t0 <= 1) {
michael@0 2872 result.push(pointAt(t0));
michael@0 2873 }
michael@0 2874 var a = c3Y;
michael@0 2875 var b = t0 * a + bY;
michael@0 2876 var c = t0 * b + dY;
michael@0 2877 var d = b * b - 4 * a * c;
michael@0 2878 if (d < 0) {
michael@0 2879 return result;
michael@0 2880 }
michael@0 2881 d = Math.sqrt(d);
michael@0 2882 a = 1 / (a + a);
michael@0 2883 var t1 = (d - b) * a;
michael@0 2884 var t2 = (-b - d) * a;
michael@0 2885 if (t1 >= 0 && t1 <= 1) {
michael@0 2886 result.push(pointAt(t1));
michael@0 2887 }
michael@0 2888 if (t2 >= 0 && t2 <= 1) {
michael@0 2889 result.push(pointAt(t2));
michael@0 2890 }
michael@0 2891 return result;
michael@0 2892 }
michael@0 2893 function findRoot(x0, x2, f, maxIterations, epsilon) {
michael@0 2894 var x1;
michael@0 2895 var y0;
michael@0 2896 var y1;
michael@0 2897 var y2;
michael@0 2898 var b;
michael@0 2899 var c;
michael@0 2900 var y10;
michael@0 2901 var y20;
michael@0 2902 var y21;
michael@0 2903 var xm;
michael@0 2904 var ym;
michael@0 2905 var temp;
michael@0 2906 var xmlast = x0;
michael@0 2907 y0 = f(x0);
michael@0 2908 if (y0 === 0) {
michael@0 2909 return x0;
michael@0 2910 }
michael@0 2911 y2 = f(x2);
michael@0 2912 if (y2 === 0) {
michael@0 2913 return x2;
michael@0 2914 }
michael@0 2915 if (y2 * y0 > 0) {
michael@0 2916 return x0;
michael@0 2917 }
michael@0 2918 var __iter = 0;
michael@0 2919 for (var i = 0; i < maxIterations; ++i) {
michael@0 2920 __iter++;
michael@0 2921 x1 = 0.5 * (x2 + x0);
michael@0 2922 y1 = f(x1);
michael@0 2923 if (y1 === 0) {
michael@0 2924 return x1;
michael@0 2925 }
michael@0 2926 if (Math.abs(x1 - x0) < epsilon) {
michael@0 2927 return x1;
michael@0 2928 }
michael@0 2929 if (y1 * y0 > 0) {
michael@0 2930 temp = x0;
michael@0 2931 x0 = x2;
michael@0 2932 x2 = temp;
michael@0 2933 temp = y0;
michael@0 2934 y0 = y2;
michael@0 2935 y2 = temp;
michael@0 2936 }
michael@0 2937 y10 = y1 - y0;
michael@0 2938 y21 = y2 - y1;
michael@0 2939 y20 = y2 - y0;
michael@0 2940 if (y2 * y20 < 2 * y1 * y10) {
michael@0 2941 x2 = x1;
michael@0 2942 y2 = y1;
michael@0 2943 } else {
michael@0 2944 b = (x1 - x0) / y10;
michael@0 2945 c = (y10 - y21) / (y21 * y20);
michael@0 2946 xm = x0 - b * y0 * (1 - c * y1);
michael@0 2947 ym = f(xm);
michael@0 2948 if (ym === 0) {
michael@0 2949 return xm;
michael@0 2950 }
michael@0 2951 if (Math.abs(xm - xmlast) < epsilon) {
michael@0 2952 return xm;
michael@0 2953 }
michael@0 2954 xmlast = xm;
michael@0 2955 if (ym * y0 < 0) {
michael@0 2956 x2 = xm;
michael@0 2957 y2 = ym;
michael@0 2958 } else {
michael@0 2959 x0 = xm;
michael@0 2960 y0 = ym;
michael@0 2961 x2 = x1;
michael@0 2962 y2 = y1;
michael@0 2963 }
michael@0 2964 }
michael@0 2965 }
michael@0 2966 return x1;
michael@0 2967 }
michael@0 2968 function extendBoundsByPoint(bounds, x, y) {
michael@0 2969 if (x < bounds.xMin) {
michael@0 2970 bounds.xMin = x;
michael@0 2971 } else if (x > bounds.xMax) {
michael@0 2972 bounds.xMax = x;
michael@0 2973 }
michael@0 2974 if (y < bounds.yMin) {
michael@0 2975 bounds.yMin = y;
michael@0 2976 } else if (y > bounds.yMax) {
michael@0 2977 bounds.yMax = y;
michael@0 2978 }
michael@0 2979 }
michael@0 2980 function extendBoundsByX(bounds, x) {
michael@0 2981 if (x < bounds.xMin) {
michael@0 2982 bounds.xMin = x;
michael@0 2983 } else if (x > bounds.xMax) {
michael@0 2984 bounds.xMax = x;
michael@0 2985 }
michael@0 2986 }
michael@0 2987 function extendBoundsByY(bounds, y) {
michael@0 2988 if (y < bounds.yMin) {
michael@0 2989 bounds.yMin = y;
michael@0 2990 } else if (y > bounds.yMax) {
michael@0 2991 bounds.yMax = y;
michael@0 2992 }
michael@0 2993 }
michael@0 2994 function morph(start, end, ratio) {
michael@0 2995 return start + (end - start) * ratio;
michael@0 2996 }
michael@0 2997 function finishShapePath(path, dictionaryResolved) {
michael@0 2998 if (path.fullyInitialized) {
michael@0 2999 return path;
michael@0 3000 }
michael@0 3001 if (!(path instanceof ShapePath)) {
michael@0 3002 var untypedPath = path;
michael@0 3003 path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
michael@0 3004 path.commands = new Uint8Array(untypedPath.buffers[0]);
michael@0 3005 path.data = new Int32Array(untypedPath.buffers[1]);
michael@0 3006 if (untypedPath.isMorph) {
michael@0 3007 path.morphData = new Int32Array(untypedPath.buffers[2]);
michael@0 3008 }
michael@0 3009 path.buffers = null;
michael@0 3010 }
michael@0 3011 path.fillStyle && initStyle(path.fillStyle, dictionaryResolved);
michael@0 3012 path.lineStyle && initStyle(path.lineStyle, dictionaryResolved);
michael@0 3013 path.fullyInitialized = true;
michael@0 3014 return path;
michael@0 3015 }
michael@0 3016 var inWorker = typeof window === 'undefined';
michael@0 3017 var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
michael@0 3018 function buildLinearGradientFactory(colorStops) {
michael@0 3019 var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
michael@0 3020 for (var i = 0; i < colorStops.length; i++) {
michael@0 3021 defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
michael@0 3022 }
michael@0 3023 var fn = function createLinearGradient(ctx, colorTransform) {
michael@0 3024 var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
michael@0 3025 for (var i = 0; i < colorStops.length; i++) {
michael@0 3026 colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
michael@0 3027 }
michael@0 3028 return gradient;
michael@0 3029 };
michael@0 3030 fn.defaultFillStyle = defaultGradient;
michael@0 3031 return fn;
michael@0 3032 }
michael@0 3033 function buildRadialGradientFactory(focalPoint, colorStops) {
michael@0 3034 var defaultGradient = factoryCtx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
michael@0 3035 for (var i = 0; i < colorStops.length; i++) {
michael@0 3036 defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
michael@0 3037 }
michael@0 3038 var fn = function createRadialGradient(ctx, colorTransform) {
michael@0 3039 var gradient = ctx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
michael@0 3040 for (var i = 0; i < colorStops.length; i++) {
michael@0 3041 colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
michael@0 3042 }
michael@0 3043 return gradient;
michael@0 3044 };
michael@0 3045 fn.defaultFillStyle = defaultGradient;
michael@0 3046 return fn;
michael@0 3047 }
michael@0 3048 function buildBitmapPatternFactory(img, repeat) {
michael@0 3049 var defaultPattern = factoryCtx.createPattern(img, repeat);
michael@0 3050 var cachedTransform, cachedTransformKey;
michael@0 3051 var fn = function createBitmapPattern(ctx, colorTransform) {
michael@0 3052 if (!colorTransform.mode) {
michael@0 3053 return defaultPattern;
michael@0 3054 }
michael@0 3055 var key = colorTransform.getTransformFingerprint();
michael@0 3056 if (key === cachedTransformKey) {
michael@0 3057 return cachedTransform;
michael@0 3058 }
michael@0 3059 var canvas = document.createElement('canvas');
michael@0 3060 canvas.width = img.width;
michael@0 3061 canvas.height = img.height;
michael@0 3062 var ctx = canvas.getContext('2d');
michael@0 3063 colorTransform.setAlpha(ctx, true);
michael@0 3064 ctx.drawImage(img, 0, 0);
michael@0 3065 cachedTransform = ctx.createPattern(canvas, repeat);
michael@0 3066 cachedTransformKey = key;
michael@0 3067 return cachedTransform;
michael@0 3068 };
michael@0 3069 fn.defaultFillStyle = defaultPattern;
michael@0 3070 return fn;
michael@0 3071 }
michael@0 3072 function initStyle(style, dictionaryResolved) {
michael@0 3073 if (style.type === undefined) {
michael@0 3074 return;
michael@0 3075 }
michael@0 3076 switch (style.type) {
michael@0 3077 case GRAPHICS_FILL_SOLID:
michael@0 3078 break;
michael@0 3079 case GRAPHICS_FILL_LINEAR_GRADIENT:
michael@0 3080 case GRAPHICS_FILL_RADIAL_GRADIENT:
michael@0 3081 case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT:
michael@0 3082 var records = style.records, colorStops = [];
michael@0 3083 for (var j = 0, n = records.length; j < n; j++) {
michael@0 3084 var record = records[j];
michael@0 3085 var colorStr = rgbaObjToStr(record.color);
michael@0 3086 colorStops.push({
michael@0 3087 ratio: record.ratio / 255,
michael@0 3088 color: colorStr
michael@0 3089 });
michael@0 3090 }
michael@0 3091 var gradientConstructor;
michael@0 3092 var isLinear = style.type === GRAPHICS_FILL_LINEAR_GRADIENT;
michael@0 3093 if (isLinear) {
michael@0 3094 gradientConstructor = buildLinearGradientFactory(colorStops);
michael@0 3095 } else {
michael@0 3096 gradientConstructor = buildRadialGradientFactory((style.focalPoint | 0) / 20, colorStops);
michael@0 3097 }
michael@0 3098 style.style = gradientConstructor;
michael@0 3099 break;
michael@0 3100 case GRAPHICS_FILL_REPEATING_BITMAP:
michael@0 3101 case GRAPHICS_FILL_CLIPPED_BITMAP:
michael@0 3102 case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
michael@0 3103 case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
michael@0 3104 var bitmap = dictionaryResolved[style.bitmapId];
michael@0 3105 var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP;
michael@0 3106 style.style = buildBitmapPatternFactory(bitmap.props.img, repeat ? 'repeat' : 'no-repeat');
michael@0 3107 break;
michael@0 3108 default:
michael@0 3109 fail('invalid fill style', 'shape');
michael@0 3110 }
michael@0 3111 }
michael@0 3112 var SOUND_SIZE_8_BIT = 0;
michael@0 3113 var SOUND_SIZE_16_BIT = 1;
michael@0 3114 var SOUND_TYPE_MONO = 0;
michael@0 3115 var SOUND_TYPE_STEREO = 1;
michael@0 3116 var SOUND_FORMAT_PCM_BE = 0;
michael@0 3117 var SOUND_FORMAT_ADPCM = 1;
michael@0 3118 var SOUND_FORMAT_MP3 = 2;
michael@0 3119 var SOUND_FORMAT_PCM_LE = 3;
michael@0 3120 var SOUND_FORMAT_NELLYMOSER_16 = 4;
michael@0 3121 var SOUND_FORMAT_NELLYMOSER_8 = 5;
michael@0 3122 var SOUND_FORMAT_NELLYMOSER = 6;
michael@0 3123 var SOUND_FORMAT_SPEEX = 11;
michael@0 3124 var SOUND_RATES = [
michael@0 3125 5512,
michael@0 3126 11250,
michael@0 3127 22500,
michael@0 3128 44100
michael@0 3129 ];
michael@0 3130 var WaveHeader = new Uint8Array([
michael@0 3131 82,
michael@0 3132 73,
michael@0 3133 70,
michael@0 3134 70,
michael@0 3135 0,
michael@0 3136 0,
michael@0 3137 0,
michael@0 3138 0,
michael@0 3139 87,
michael@0 3140 65,
michael@0 3141 86,
michael@0 3142 69,
michael@0 3143 102,
michael@0 3144 109,
michael@0 3145 116,
michael@0 3146 32,
michael@0 3147 16,
michael@0 3148 0,
michael@0 3149 0,
michael@0 3150 0,
michael@0 3151 1,
michael@0 3152 0,
michael@0 3153 2,
michael@0 3154 0,
michael@0 3155 68,
michael@0 3156 172,
michael@0 3157 0,
michael@0 3158 0,
michael@0 3159 16,
michael@0 3160 177,
michael@0 3161 2,
michael@0 3162 0,
michael@0 3163 4,
michael@0 3164 0,
michael@0 3165 16,
michael@0 3166 0,
michael@0 3167 100,
michael@0 3168 97,
michael@0 3169 116,
michael@0 3170 97,
michael@0 3171 0,
michael@0 3172 0,
michael@0 3173 0,
michael@0 3174 0
michael@0 3175 ]);
michael@0 3176 function packageWave(data, sampleRate, channels, size, swapBytes) {
michael@0 3177 var sizeInBytes = size >> 3;
michael@0 3178 var sizePerSecond = channels * sampleRate * sizeInBytes;
michael@0 3179 var sizePerSample = channels * sizeInBytes;
michael@0 3180 var dataLength = data.length + (data.length & 1);
michael@0 3181 var buffer = new ArrayBuffer(WaveHeader.length + dataLength);
michael@0 3182 var bytes = new Uint8Array(buffer);
michael@0 3183 bytes.set(WaveHeader);
michael@0 3184 if (swapBytes) {
michael@0 3185 for (var i = 0, j = WaveHeader.length; i < data.length; i += 2, j += 2) {
michael@0 3186 bytes[j] = data[i + 1];
michael@0 3187 bytes[j + 1] = data[i];
michael@0 3188 }
michael@0 3189 } else {
michael@0 3190 bytes.set(data, WaveHeader.length);
michael@0 3191 }
michael@0 3192 var view = new DataView(buffer);
michael@0 3193 view.setUint32(4, dataLength + 36, true);
michael@0 3194 view.setUint16(22, channels, true);
michael@0 3195 view.setUint32(24, sampleRate, true);
michael@0 3196 view.setUint32(28, sizePerSecond, true);
michael@0 3197 view.setUint16(32, sizePerSample, true);
michael@0 3198 view.setUint16(34, size, true);
michael@0 3199 view.setUint32(40, dataLength, true);
michael@0 3200 return {
michael@0 3201 data: bytes,
michael@0 3202 mimeType: 'audio/wav'
michael@0 3203 };
michael@0 3204 }
michael@0 3205 function defineSound(tag, dictionary) {
michael@0 3206 var channels = tag.soundType == SOUND_TYPE_STEREO ? 2 : 1;
michael@0 3207 var samplesCount = tag.samplesCount;
michael@0 3208 var sampleRate = SOUND_RATES[tag.soundRate];
michael@0 3209 var data = tag.soundData;
michael@0 3210 var pcm, packaged;
michael@0 3211 switch (tag.soundFormat) {
michael@0 3212 case SOUND_FORMAT_PCM_BE:
michael@0 3213 pcm = new Float32Array(samplesCount * channels);
michael@0 3214 if (tag.soundSize == SOUND_SIZE_16_BIT) {
michael@0 3215 for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
michael@0 3216 pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648;
michael@0 3217 packaged = packageWave(data, sampleRate, channels, 16, true);
michael@0 3218 } else {
michael@0 3219 for (var i = 0; i < pcm.length; i++)
michael@0 3220 pcm[i] = (data[i] - 128) / 128;
michael@0 3221 packaged = packageWave(data, sampleRate, channels, 8, false);
michael@0 3222 }
michael@0 3223 break;
michael@0 3224 case SOUND_FORMAT_PCM_LE:
michael@0 3225 pcm = new Float32Array(samplesCount * channels);
michael@0 3226 if (tag.soundSize == SOUND_SIZE_16_BIT) {
michael@0 3227 for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
michael@0 3228 pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648;
michael@0 3229 packaged = packageWave(data, sampleRate, channels, 16, false);
michael@0 3230 } else {
michael@0 3231 for (var i = 0; i < pcm.length; i++)
michael@0 3232 pcm[i] = (data[i] - 128) / 128;
michael@0 3233 packaged = packageWave(data, sampleRate, channels, 8, false);
michael@0 3234 }
michael@0 3235 break;
michael@0 3236 case SOUND_FORMAT_MP3:
michael@0 3237 packaged = {
michael@0 3238 data: new Uint8Array(data.subarray(2)),
michael@0 3239 mimeType: 'audio/mpeg'
michael@0 3240 };
michael@0 3241 break;
michael@0 3242 case SOUND_FORMAT_ADPCM:
michael@0 3243 var pcm16 = new Int16Array(samplesCount * channels);
michael@0 3244 decodeACPCMSoundData(data, pcm16, channels);
michael@0 3245 pcm = new Float32Array(samplesCount * channels);
michael@0 3246 for (var i = 0; i < pcm.length; i++)
michael@0 3247 pcm[i] = pcm16[i] / 32768;
michael@0 3248 packaged = packageWave(new Uint8Array(pcm16.buffer), sampleRate, channels, 16, !new Uint8Array(new Uint16Array([
michael@0 3249 1
michael@0 3250 ]).buffer)[0]);
michael@0 3251 break;
michael@0 3252 default:
michael@0 3253 throw new Error('Unsupported audio format: ' + tag.soundFormat);
michael@0 3254 }
michael@0 3255 var sound = {
michael@0 3256 type: 'sound',
michael@0 3257 id: tag.id,
michael@0 3258 sampleRate: sampleRate,
michael@0 3259 channels: channels,
michael@0 3260 pcm: pcm
michael@0 3261 };
michael@0 3262 if (packaged)
michael@0 3263 sound.packaged = packaged;
michael@0 3264 return sound;
michael@0 3265 }
michael@0 3266 var ACPCMIndexTables = [
michael@0 3267 [
michael@0 3268 -1,
michael@0 3269 2
michael@0 3270 ],
michael@0 3271 [
michael@0 3272 -1,
michael@0 3273 -1,
michael@0 3274 2,
michael@0 3275 4
michael@0 3276 ],
michael@0 3277 [
michael@0 3278 -1,
michael@0 3279 -1,
michael@0 3280 -1,
michael@0 3281 -1,
michael@0 3282 2,
michael@0 3283 4,
michael@0 3284 6,
michael@0 3285 8
michael@0 3286 ],
michael@0 3287 [
michael@0 3288 -1,
michael@0 3289 -1,
michael@0 3290 -1,
michael@0 3291 -1,
michael@0 3292 -1,
michael@0 3293 -1,
michael@0 3294 -1,
michael@0 3295 -1,
michael@0 3296 1,
michael@0 3297 2,
michael@0 3298 4,
michael@0 3299 6,
michael@0 3300 8,
michael@0 3301 10,
michael@0 3302 13,
michael@0 3303 16
michael@0 3304 ]
michael@0 3305 ];
michael@0 3306 var ACPCMStepSizeTable = [
michael@0 3307 7,
michael@0 3308 8,
michael@0 3309 9,
michael@0 3310 10,
michael@0 3311 11,
michael@0 3312 12,
michael@0 3313 13,
michael@0 3314 14,
michael@0 3315 16,
michael@0 3316 17,
michael@0 3317 19,
michael@0 3318 21,
michael@0 3319 23,
michael@0 3320 25,
michael@0 3321 28,
michael@0 3322 31,
michael@0 3323 34,
michael@0 3324 37,
michael@0 3325 41,
michael@0 3326 45,
michael@0 3327 50,
michael@0 3328 55,
michael@0 3329 60,
michael@0 3330 66,
michael@0 3331 73,
michael@0 3332 80,
michael@0 3333 88,
michael@0 3334 97,
michael@0 3335 107,
michael@0 3336 118,
michael@0 3337 130,
michael@0 3338 143,
michael@0 3339 157,
michael@0 3340 173,
michael@0 3341 190,
michael@0 3342 209,
michael@0 3343 230,
michael@0 3344 253,
michael@0 3345 279,
michael@0 3346 307,
michael@0 3347 337,
michael@0 3348 371,
michael@0 3349 408,
michael@0 3350 449,
michael@0 3351 494,
michael@0 3352 544,
michael@0 3353 598,
michael@0 3354 658,
michael@0 3355 724,
michael@0 3356 796,
michael@0 3357 876,
michael@0 3358 963,
michael@0 3359 1060,
michael@0 3360 1166,
michael@0 3361 1282,
michael@0 3362 1411,
michael@0 3363 1552,
michael@0 3364 1707,
michael@0 3365 1878,
michael@0 3366 2066,
michael@0 3367 2272,
michael@0 3368 2499,
michael@0 3369 2749,
michael@0 3370 3024,
michael@0 3371 3327,
michael@0 3372 3660,
michael@0 3373 4026,
michael@0 3374 4428,
michael@0 3375 4871,
michael@0 3376 5358,
michael@0 3377 5894,
michael@0 3378 6484,
michael@0 3379 7132,
michael@0 3380 7845,
michael@0 3381 8630,
michael@0 3382 9493,
michael@0 3383 10442,
michael@0 3384 11487,
michael@0 3385 12635,
michael@0 3386 13899,
michael@0 3387 15289,
michael@0 3388 16818,
michael@0 3389 18500,
michael@0 3390 20350,
michael@0 3391 22385,
michael@0 3392 24623,
michael@0 3393 27086,
michael@0 3394 29794,
michael@0 3395 32767
michael@0 3396 ];
michael@0 3397 function decodeACPCMSoundData(data, pcm16, channels) {
michael@0 3398 function readBits(n, signed) {
michael@0 3399 while (dataBufferLength < n) {
michael@0 3400 dataBuffer = dataBuffer << 8 | data[dataPosition++];
michael@0 3401 dataBufferLength += 8;
michael@0 3402 }
michael@0 3403 dataBufferLength -= n;
michael@0 3404 return dataBuffer >>> dataBufferLength & (1 << n) - 1;
michael@0 3405 }
michael@0 3406 var dataPosition = 0;
michael@0 3407 var dataBuffer = 0;
michael@0 3408 var dataBufferLength = 0;
michael@0 3409 var pcmPosition = 0;
michael@0 3410 var codeSize = readBits(2);
michael@0 3411 var indexTable = ACPCMIndexTables[codeSize];
michael@0 3412 while (pcmPosition < pcm16.length) {
michael@0 3413 var x = pcm16[pcmPosition++] = readBits(16) << 16 >> 16, x2;
michael@0 3414 var stepIndex = readBits(6), stepIndex2;
michael@0 3415 if (channels > 1) {
michael@0 3416 x2 = pcm16[pcmPosition++] = readBits(16) << 16 >> 16;
michael@0 3417 stepIndex2 = readBits(6);
michael@0 3418 }
michael@0 3419 var signMask = 1 << codeSize + 1;
michael@0 3420 for (var i = 0; i < 4095; i++) {
michael@0 3421 var nibble = readBits(codeSize + 2);
michael@0 3422 var step = ACPCMStepSizeTable[stepIndex];
michael@0 3423 var sum = 0;
michael@0 3424 for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) {
michael@0 3425 if (nibble & currentBit)
michael@0 3426 sum += step;
michael@0 3427 }
michael@0 3428 x += (nibble & signMask ? -1 : 1) * (sum + step);
michael@0 3429 pcm16[pcmPosition++] = x = x < -32768 ? -32768 : x > 32767 ? 32767 : x;
michael@0 3430 stepIndex += indexTable[nibble & ~signMask];
michael@0 3431 stepIndex = stepIndex < 0 ? 0 : stepIndex > 88 ? 88 : stepIndex;
michael@0 3432 if (channels > 1) {
michael@0 3433 nibble = readBits(codeSize + 2);
michael@0 3434 step = ACPCMStepSizeTable[stepIndex2];
michael@0 3435 sum = 0;
michael@0 3436 for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) {
michael@0 3437 if (nibble & currentBit)
michael@0 3438 sum += step;
michael@0 3439 }
michael@0 3440 x2 += (nibble & signMask ? -1 : 1) * (sum + step);
michael@0 3441 pcm16[pcmPosition++] = x2 = x2 < -32768 ? -32768 : x2 > 32767 ? 32767 : x2;
michael@0 3442 stepIndex2 += indexTable[nibble & ~signMask];
michael@0 3443 stepIndex2 = stepIndex2 < 0 ? 0 : stepIndex2 > 88 ? 88 : stepIndex2;
michael@0 3444 }
michael@0 3445 }
michael@0 3446 }
michael@0 3447 }
michael@0 3448 var nextSoundStreamId = 0;
michael@0 3449 function SwfSoundStream(samplesCount, sampleRate, channels) {
michael@0 3450 this.streamId = nextSoundStreamId++;
michael@0 3451 this.samplesCount = samplesCount;
michael@0 3452 this.sampleRate = sampleRate;
michael@0 3453 this.channels = channels;
michael@0 3454 this.format = null;
michael@0 3455 this.currentSample = 0;
michael@0 3456 }
michael@0 3457 SwfSoundStream.prototype = {
michael@0 3458 get info() {
michael@0 3459 return {
michael@0 3460 samplesCount: this.samplesCount,
michael@0 3461 sampleRate: this.sampleRate,
michael@0 3462 channels: this.channels,
michael@0 3463 format: this.format,
michael@0 3464 streamId: this.streamId
michael@0 3465 };
michael@0 3466 },
michael@0 3467 decode: function (data) {
michael@0 3468 throw new Error('SwfSoundStream.decode: not implemented');
michael@0 3469 }
michael@0 3470 };
michael@0 3471 function SwfSoundStream_decode_PCM(data) {
michael@0 3472 var pcm = new Float32Array(data.length);
michael@0 3473 for (var i = 0; i < pcm.length; i++)
michael@0 3474 pcm[i] = (data[i] - 128) / 128;
michael@0 3475 this.currentSample += pcm.length / this.channels;
michael@0 3476 return {
michael@0 3477 streamId: this.streamId,
michael@0 3478 samplesCount: pcm.length / this.channels,
michael@0 3479 pcm: pcm
michael@0 3480 };
michael@0 3481 }
michael@0 3482 function SwfSoundStream_decode_PCM_be(data) {
michael@0 3483 var pcm = new Float32Array(data.length / 2);
michael@0 3484 for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
michael@0 3485 pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648;
michael@0 3486 this.currentSample += pcm.length / this.channels;
michael@0 3487 return {
michael@0 3488 streamId: this.streamId,
michael@0 3489 samplesCount: pcm.length / this.channels,
michael@0 3490 pcm: pcm
michael@0 3491 };
michael@0 3492 }
michael@0 3493 function SwfSoundStream_decode_PCM_le(data) {
michael@0 3494 var pcm = new Float32Array(data.length / 2);
michael@0 3495 for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
michael@0 3496 pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648;
michael@0 3497 this.currentSample += pcm.length / this.channels;
michael@0 3498 return {
michael@0 3499 streamId: this.streamId,
michael@0 3500 samplesCount: pcm.length / this.channels,
michael@0 3501 pcm: pcm
michael@0 3502 };
michael@0 3503 }
michael@0 3504 function SwfSoundStream_decode_MP3(data) {
michael@0 3505 var samplesCount = data[1] << 8 | data[0];
michael@0 3506 var seek = data[3] << 8 | data[2];
michael@0 3507 this.currentSample += samplesCount;
michael@0 3508 return {
michael@0 3509 streamId: this.streamId,
michael@0 3510 samplesCount: samplesCount,
michael@0 3511 data: new Uint8Array(data.subarray(4)),
michael@0 3512 seek: seek
michael@0 3513 };
michael@0 3514 }
michael@0 3515 function createSoundStream(tag) {
michael@0 3516 var channels = tag.streamType == SOUND_TYPE_STEREO ? 2 : 1;
michael@0 3517 var samplesCount = tag.samplesCount;
michael@0 3518 var sampleRate = SOUND_RATES[tag.streamRate];
michael@0 3519 var stream = new SwfSoundStream(samplesCount, sampleRate, channels);
michael@0 3520 switch (tag.streamCompression) {
michael@0 3521 case SOUND_FORMAT_PCM_BE:
michael@0 3522 stream.format = 'wave';
michael@0 3523 if (tag.soundSize == SOUND_SIZE_16_BIT) {
michael@0 3524 stream.decode = SwfSoundStream_decode_PCM_be;
michael@0 3525 } else {
michael@0 3526 stream.decode = SwfSoundStream_decode_PCM;
michael@0 3527 }
michael@0 3528 break;
michael@0 3529 case SOUND_FORMAT_PCM_LE:
michael@0 3530 stream.format = 'wave';
michael@0 3531 if (tag.soundSize == SOUND_SIZE_16_BIT) {
michael@0 3532 stream.decode = SwfSoundStream_decode_PCM_le;
michael@0 3533 } else {
michael@0 3534 stream.decode = SwfSoundStream_decode_PCM;
michael@0 3535 }
michael@0 3536 break;
michael@0 3537 case SOUND_FORMAT_MP3:
michael@0 3538 stream.format = 'mp3';
michael@0 3539 stream.decode = SwfSoundStream_decode_MP3;
michael@0 3540 break;
michael@0 3541 default:
michael@0 3542 throw new Error('Unsupported audio format: ' + tag.soundFormat);
michael@0 3543 }
michael@0 3544 return stream;
michael@0 3545 }
michael@0 3546 function defineText(tag, dictionary) {
michael@0 3547 var dependencies = [];
michael@0 3548 if (tag.hasFont) {
michael@0 3549 var font = dictionary[tag.fontId];
michael@0 3550 tag.font = font.uniqueName;
michael@0 3551 dependencies.push(font.id);
michael@0 3552 }
michael@0 3553 var props = {
michael@0 3554 type: 'text',
michael@0 3555 id: tag.id,
michael@0 3556 variableName: tag.variableName,
michael@0 3557 tag: tag
michael@0 3558 };
michael@0 3559 if (dependencies.length)
michael@0 3560 props.require = dependencies;
michael@0 3561 return props;
michael@0 3562 }
michael@0 3563 var $RELEASE = false;
michael@0 3564 var isWorker = typeof window === 'undefined';
michael@0 3565 if (isWorker && !true) {
michael@0 3566 importScripts.apply(null, [
michael@0 3567 '../../lib/DataView.js/DataView.js',
michael@0 3568 '../flash/util.js',
michael@0 3569 'config.js',
michael@0 3570 'swf.js',
michael@0 3571 'types.js',
michael@0 3572 'structs.js',
michael@0 3573 'tags.js',
michael@0 3574 'inflate.js',
michael@0 3575 'stream.js',
michael@0 3576 'templates.js',
michael@0 3577 'generator.js',
michael@0 3578 'handlers.js',
michael@0 3579 'parser.js',
michael@0 3580 'bitmap.js',
michael@0 3581 'button.js',
michael@0 3582 'font.js',
michael@0 3583 'image.js',
michael@0 3584 'label.js',
michael@0 3585 'shape.js',
michael@0 3586 'sound.js',
michael@0 3587 'text.js'
michael@0 3588 ]);
michael@0 3589 }
michael@0 3590 function defineSymbol(swfTag, symbols) {
michael@0 3591 var symbol;
michael@0 3592 switch (swfTag.code) {
michael@0 3593 case SWF_TAG_CODE_DEFINE_BITS:
michael@0 3594 case SWF_TAG_CODE_DEFINE_BITS_JPEG2:
michael@0 3595 case SWF_TAG_CODE_DEFINE_BITS_JPEG3:
michael@0 3596 case SWF_TAG_CODE_DEFINE_BITS_JPEG4:
michael@0 3597 case SWF_TAG_CODE_JPEG_TABLES:
michael@0 3598 symbol = defineImage(swfTag, symbols);
michael@0 3599 break;
michael@0 3600 case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS:
michael@0 3601 case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2:
michael@0 3602 symbol = defineBitmap(swfTag);
michael@0 3603 break;
michael@0 3604 case SWF_TAG_CODE_DEFINE_BUTTON:
michael@0 3605 case SWF_TAG_CODE_DEFINE_BUTTON2:
michael@0 3606 symbol = defineButton(swfTag, symbols);
michael@0 3607 break;
michael@0 3608 case SWF_TAG_CODE_DEFINE_EDIT_TEXT:
michael@0 3609 symbol = defineText(swfTag, symbols);
michael@0 3610 break;
michael@0 3611 case SWF_TAG_CODE_DEFINE_FONT:
michael@0 3612 case SWF_TAG_CODE_DEFINE_FONT2:
michael@0 3613 case SWF_TAG_CODE_DEFINE_FONT3:
michael@0 3614 case SWF_TAG_CODE_DEFINE_FONT4:
michael@0 3615 symbol = defineFont(swfTag, symbols);
michael@0 3616 break;
michael@0 3617 case SWF_TAG_CODE_DEFINE_MORPH_SHAPE:
michael@0 3618 case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2:
michael@0 3619 case SWF_TAG_CODE_DEFINE_SHAPE:
michael@0 3620 case SWF_TAG_CODE_DEFINE_SHAPE2:
michael@0 3621 case SWF_TAG_CODE_DEFINE_SHAPE3:
michael@0 3622 case SWF_TAG_CODE_DEFINE_SHAPE4:
michael@0 3623 symbol = defineShape(swfTag, symbols);
michael@0 3624 break;
michael@0 3625 case SWF_TAG_CODE_DEFINE_SOUND:
michael@0 3626 symbol = defineSound(swfTag, symbols);
michael@0 3627 break;
michael@0 3628 case SWF_TAG_CODE_DEFINE_BINARY_DATA:
michael@0 3629 symbol = {
michael@0 3630 type: 'binary',
michael@0 3631 id: swfTag.id,
michael@0 3632 data: swfTag.data
michael@0 3633 };
michael@0 3634 break;
michael@0 3635 case SWF_TAG_CODE_DEFINE_SPRITE:
michael@0 3636 var depths = {};
michael@0 3637 var frame = {
michael@0 3638 type: 'frame'
michael@0 3639 };
michael@0 3640 var frames = [];
michael@0 3641 var tags = swfTag.tags;
michael@0 3642 var frameScripts = null;
michael@0 3643 var frameIndex = 0;
michael@0 3644 var soundStream = null;
michael@0 3645 for (var i = 0, n = tags.length; i < n; i++) {
michael@0 3646 var tag = tags[i];
michael@0 3647 switch (tag.code) {
michael@0 3648 case SWF_TAG_CODE_DO_ACTION:
michael@0 3649 if (!frameScripts)
michael@0 3650 frameScripts = [];
michael@0 3651 frameScripts.push(frameIndex);
michael@0 3652 frameScripts.push(tag.actionsData);
michael@0 3653 break;
michael@0 3654 case SWF_TAG_CODE_START_SOUND:
michael@0 3655 var startSounds = frame.startSounds || (frame.startSounds = []);
michael@0 3656 startSounds.push(tag);
michael@0 3657 break;
michael@0 3658 case SWF_TAG_CODE_SOUND_STREAM_HEAD:
michael@0 3659 try {
michael@0 3660 soundStream = createSoundStream(tag);
michael@0 3661 frame.soundStream = soundStream.info;
michael@0 3662 } catch (e) {
michael@0 3663 }
michael@0 3664 break;
michael@0 3665 case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
michael@0 3666 if (soundStream) {
michael@0 3667 frame.soundStreamBlock = soundStream.decode(tag.data);
michael@0 3668 }
michael@0 3669 break;
michael@0 3670 case SWF_TAG_CODE_FRAME_LABEL:
michael@0 3671 frame.labelName = tag.name;
michael@0 3672 break;
michael@0 3673 case SWF_TAG_CODE_PLACE_OBJECT:
michael@0 3674 case SWF_TAG_CODE_PLACE_OBJECT2:
michael@0 3675 case SWF_TAG_CODE_PLACE_OBJECT3:
michael@0 3676 depths[tag.depth] = tag;
michael@0 3677 break;
michael@0 3678 case SWF_TAG_CODE_REMOVE_OBJECT:
michael@0 3679 case SWF_TAG_CODE_REMOVE_OBJECT2:
michael@0 3680 depths[tag.depth] = null;
michael@0 3681 break;
michael@0 3682 case SWF_TAG_CODE_SHOW_FRAME:
michael@0 3683 frameIndex += tag.repeat;
michael@0 3684 frame.repeat = tag.repeat;
michael@0 3685 frame.depths = depths;
michael@0 3686 frames.push(frame);
michael@0 3687 depths = {};
michael@0 3688 frame = {
michael@0 3689 type: 'frame'
michael@0 3690 };
michael@0 3691 break;
michael@0 3692 }
michael@0 3693 }
michael@0 3694 symbol = {
michael@0 3695 type: 'sprite',
michael@0 3696 id: swfTag.id,
michael@0 3697 frameCount: swfTag.frameCount,
michael@0 3698 frames: frames,
michael@0 3699 frameScripts: frameScripts
michael@0 3700 };
michael@0 3701 break;
michael@0 3702 case SWF_TAG_CODE_DEFINE_TEXT:
michael@0 3703 case SWF_TAG_CODE_DEFINE_TEXT2:
michael@0 3704 symbol = defineLabel(swfTag, symbols);
michael@0 3705 break;
michael@0 3706 }
michael@0 3707 if (!symbol) {
michael@0 3708 return {
michael@0 3709 command: 'error',
michael@0 3710 message: 'unknown symbol type: ' + swfTag.code
michael@0 3711 };
michael@0 3712 }
michael@0 3713 symbol.isSymbol = true;
michael@0 3714 symbols[swfTag.id] = symbol;
michael@0 3715 return symbol;
michael@0 3716 }
michael@0 3717 function createParsingContext(commitData) {
michael@0 3718 var depths = {};
michael@0 3719 var symbols = {};
michael@0 3720 var frame = {
michael@0 3721 type: 'frame'
michael@0 3722 };
michael@0 3723 var tagsProcessed = 0;
michael@0 3724 var soundStream = null;
michael@0 3725 var lastProgressSent = 0;
michael@0 3726 return {
michael@0 3727 onstart: function (result) {
michael@0 3728 commitData({
michael@0 3729 command: 'init',
michael@0 3730 result: result
michael@0 3731 });
michael@0 3732 },
michael@0 3733 onprogress: function (result) {
michael@0 3734 if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) {
michael@0 3735 commitData({
michael@0 3736 command: 'progress',
michael@0 3737 result: {
michael@0 3738 bytesLoaded: result.bytesLoaded,
michael@0 3739 bytesTotal: result.bytesTotal
michael@0 3740 }
michael@0 3741 });
michael@0 3742 lastProgressSent = Date.now();
michael@0 3743 }
michael@0 3744 var tags = result.tags;
michael@0 3745 for (var n = tags.length; tagsProcessed < n; tagsProcessed++) {
michael@0 3746 var tag = tags[tagsProcessed];
michael@0 3747 if ('id' in tag) {
michael@0 3748 var symbol = defineSymbol(tag, symbols);
michael@0 3749 commitData(symbol, symbol.transferables);
michael@0 3750 continue;
michael@0 3751 }
michael@0 3752 switch (tag.code) {
michael@0 3753 case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA:
michael@0 3754 frame.sceneData = tag;
michael@0 3755 break;
michael@0 3756 case SWF_TAG_CODE_DEFINE_SCALING_GRID:
michael@0 3757 var symbolUpdate = {
michael@0 3758 isSymbol: true,
michael@0 3759 id: tag.symbolId,
michael@0 3760 updates: {
michael@0 3761 scale9Grid: tag.splitter
michael@0 3762 }
michael@0 3763 };
michael@0 3764 commitData(symbolUpdate);
michael@0 3765 break;
michael@0 3766 case SWF_TAG_CODE_DO_ABC:
michael@0 3767 case SWF_TAG_CODE_DO_ABC_:
michael@0 3768 var abcBlocks = frame.abcBlocks;
michael@0 3769 if (abcBlocks)
michael@0 3770 abcBlocks.push({
michael@0 3771 data: tag.data,
michael@0 3772 flags: tag.flags
michael@0 3773 });
michael@0 3774 else
michael@0 3775 frame.abcBlocks = [
michael@0 3776 {
michael@0 3777 data: tag.data,
michael@0 3778 flags: tag.flags
michael@0 3779 }
michael@0 3780 ];
michael@0 3781 break;
michael@0 3782 case SWF_TAG_CODE_DO_ACTION:
michael@0 3783 var actionBlocks = frame.actionBlocks;
michael@0 3784 if (actionBlocks)
michael@0 3785 actionBlocks.push(tag.actionsData);
michael@0 3786 else
michael@0 3787 frame.actionBlocks = [
michael@0 3788 tag.actionsData
michael@0 3789 ];
michael@0 3790 break;
michael@0 3791 case SWF_TAG_CODE_DO_INIT_ACTION:
michael@0 3792 var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []);
michael@0 3793 initActionBlocks.push({
michael@0 3794 spriteId: tag.spriteId,
michael@0 3795 actionsData: tag.actionsData
michael@0 3796 });
michael@0 3797 break;
michael@0 3798 case SWF_TAG_CODE_START_SOUND:
michael@0 3799 var startSounds = frame.startSounds;
michael@0 3800 if (!startSounds)
michael@0 3801 frame.startSounds = startSounds = [];
michael@0 3802 startSounds.push(tag);
michael@0 3803 break;
michael@0 3804 case SWF_TAG_CODE_SOUND_STREAM_HEAD:
michael@0 3805 try {
michael@0 3806 soundStream = createSoundStream(tag);
michael@0 3807 frame.soundStream = soundStream.info;
michael@0 3808 } catch (e) {
michael@0 3809 }
michael@0 3810 break;
michael@0 3811 case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
michael@0 3812 if (soundStream) {
michael@0 3813 frame.soundStreamBlock = soundStream.decode(tag.data);
michael@0 3814 }
michael@0 3815 break;
michael@0 3816 case SWF_TAG_CODE_EXPORT_ASSETS:
michael@0 3817 var exports = frame.exports;
michael@0 3818 if (exports)
michael@0 3819 frame.exports = exports.concat(tag.exports);
michael@0 3820 else
michael@0 3821 frame.exports = tag.exports.slice(0);
michael@0 3822 break;
michael@0 3823 case SWF_TAG_CODE_SYMBOL_CLASS:
michael@0 3824 var symbolClasses = frame.symbolClasses;
michael@0 3825 if (symbolClasses)
michael@0 3826 frame.symbolClasses = symbolClasses.concat(tag.exports);
michael@0 3827 else
michael@0 3828 frame.symbolClasses = tag.exports.slice(0);
michael@0 3829 break;
michael@0 3830 case SWF_TAG_CODE_FRAME_LABEL:
michael@0 3831 frame.labelName = tag.name;
michael@0 3832 break;
michael@0 3833 case SWF_TAG_CODE_PLACE_OBJECT:
michael@0 3834 case SWF_TAG_CODE_PLACE_OBJECT2:
michael@0 3835 case SWF_TAG_CODE_PLACE_OBJECT3:
michael@0 3836 depths[tag.depth] = tag;
michael@0 3837 break;
michael@0 3838 case SWF_TAG_CODE_REMOVE_OBJECT:
michael@0 3839 case SWF_TAG_CODE_REMOVE_OBJECT2:
michael@0 3840 depths[tag.depth] = null;
michael@0 3841 break;
michael@0 3842 case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
michael@0 3843 frame.bgcolor = tag.color;
michael@0 3844 break;
michael@0 3845 case SWF_TAG_CODE_SHOW_FRAME:
michael@0 3846 frame.repeat = tag.repeat;
michael@0 3847 frame.depths = depths;
michael@0 3848 frame.complete = !(!tag.finalTag);
michael@0 3849 commitData(frame);
michael@0 3850 depths = {};
michael@0 3851 frame = {
michael@0 3852 type: 'frame'
michael@0 3853 };
michael@0 3854 break;
michael@0 3855 }
michael@0 3856 }
michael@0 3857 },
michael@0 3858 oncomplete: function (result) {
michael@0 3859 commitData(result);
michael@0 3860 var stats;
michael@0 3861 if (typeof result.swfVersion === 'number') {
michael@0 3862 var bbox = result.bbox;
michael@0 3863 stats = {
michael@0 3864 topic: 'parseInfo',
michael@0 3865 parseTime: result.parseTime,
michael@0 3866 bytesTotal: result.bytesTotal,
michael@0 3867 swfVersion: result.swfVersion,
michael@0 3868 frameRate: result.frameRate,
michael@0 3869 width: (bbox.xMax - bbox.xMin) / 20,
michael@0 3870 height: (bbox.yMax - bbox.yMin) / 20,
michael@0 3871 isAvm2: !(!result.fileAttributes.doAbc)
michael@0 3872 };
michael@0 3873 }
michael@0 3874 commitData({
michael@0 3875 command: 'complete',
michael@0 3876 stats: stats
michael@0 3877 });
michael@0 3878 },
michael@0 3879 onexception: function (e) {
michael@0 3880 commitData({
michael@0 3881 type: 'exception',
michael@0 3882 message: e.message,
michael@0 3883 stack: e.stack
michael@0 3884 });
michael@0 3885 }
michael@0 3886 };
michael@0 3887 }
michael@0 3888 function parseBytes(bytes, commitData) {
michael@0 3889 SWF.parse(bytes, createParsingContext(commitData));
michael@0 3890 }
michael@0 3891 function ResourceLoader(scope) {
michael@0 3892 this.subscription = null;
michael@0 3893 var self = this;
michael@0 3894 if (!isWorker) {
michael@0 3895 this.messenger = {
michael@0 3896 postMessage: function (data) {
michael@0 3897 self.onmessage({
michael@0 3898 data: data
michael@0 3899 });
michael@0 3900 }
michael@0 3901 };
michael@0 3902 } else {
michael@0 3903 this.messenger = scope;
michael@0 3904 scope.onmessage = function (event) {
michael@0 3905 self.listener(event.data);
michael@0 3906 };
michael@0 3907 }
michael@0 3908 }
michael@0 3909 ResourceLoader.prototype = {
michael@0 3910 terminate: function () {
michael@0 3911 this.messenger = null;
michael@0 3912 this.listener = null;
michael@0 3913 },
michael@0 3914 onmessage: function (event) {
michael@0 3915 this.listener(event.data);
michael@0 3916 },
michael@0 3917 postMessage: function (data) {
michael@0 3918 this.listener && this.listener(data);
michael@0 3919 },
michael@0 3920 listener: function (data) {
michael@0 3921 if (this.subscription) {
michael@0 3922 this.subscription.callback(data.data, data.progress);
michael@0 3923 } else if (data === 'pipe:') {
michael@0 3924 this.subscription = {
michael@0 3925 subscribe: function (callback) {
michael@0 3926 this.callback = callback;
michael@0 3927 }
michael@0 3928 };
michael@0 3929 this.parseLoadedData(this.messenger, this.subscription);
michael@0 3930 } else {
michael@0 3931 this.parseLoadedData(this.messenger, data);
michael@0 3932 }
michael@0 3933 },
michael@0 3934 parseLoadedData: function (loader, request, context) {
michael@0 3935 function commitData(data, transferables) {
michael@0 3936 try {
michael@0 3937 loader.postMessage(data, transferables);
michael@0 3938 } catch (ex) {
michael@0 3939 if (ex != 'DataCloneError') {
michael@0 3940 throw ex;
michael@0 3941 }
michael@0 3942 loader.postMessage(data);
michael@0 3943 }
michael@0 3944 }
michael@0 3945 if (request instanceof ArrayBuffer) {
michael@0 3946 parseBytes(request, commitData);
michael@0 3947 } else if ('subscribe' in request) {
michael@0 3948 var pipe = SWF.parseAsync(createParsingContext(commitData));
michael@0 3949 request.subscribe(function (data, progress) {
michael@0 3950 if (data) {
michael@0 3951 pipe.push(data, progress);
michael@0 3952 } else {
michael@0 3953 pipe.close();
michael@0 3954 }
michael@0 3955 });
michael@0 3956 } else if (typeof FileReaderSync !== 'undefined') {
michael@0 3957 var reader = new FileReaderSync();
michael@0 3958 var buffer = reader.readAsArrayBuffer(request);
michael@0 3959 parseBytes(buffer, commitData);
michael@0 3960 } else {
michael@0 3961 var reader = new FileReader();
michael@0 3962 reader.onload = function () {
michael@0 3963 parseBytes(this.result, commitData);
michael@0 3964 };
michael@0 3965 reader.readAsArrayBuffer(request);
michael@0 3966 }
michael@0 3967 }
michael@0 3968 };
michael@0 3969 if (isWorker) {
michael@0 3970 var loader = new ResourceLoader(this);
michael@0 3971 }
michael@0 3972 var codeLengthOrder = [
michael@0 3973 16,
michael@0 3974 17,
michael@0 3975 18,
michael@0 3976 0,
michael@0 3977 8,
michael@0 3978 7,
michael@0 3979 9,
michael@0 3980 6,
michael@0 3981 10,
michael@0 3982 5,
michael@0 3983 11,
michael@0 3984 4,
michael@0 3985 12,
michael@0 3986 3,
michael@0 3987 13,
michael@0 3988 2,
michael@0 3989 14,
michael@0 3990 1,
michael@0 3991 15
michael@0 3992 ];
michael@0 3993 var distanceCodes = [];
michael@0 3994 var distanceExtraBits = [];
michael@0 3995 for (var i = 0, j = 0, code = 1; i < 30; ++i) {
michael@0 3996 distanceCodes[i] = code;
michael@0 3997 code += 1 << (distanceExtraBits[i] = ~(~((j += i > 2 ? 1 : 0) / 2)));
michael@0 3998 }
michael@0 3999 var bitLengths = [];
michael@0 4000 for (var i = 0; i < 32; ++i)
michael@0 4001 bitLengths[i] = 5;
michael@0 4002 var fixedDistanceTable = makeHuffmanTable(bitLengths);
michael@0 4003 var lengthCodes = [];
michael@0 4004 var lengthExtraBits = [];
michael@0 4005 for (var i = 0, j = 0, code = 3; i < 29; ++i) {
michael@0 4006 lengthCodes[i] = code - (i == 28 ? 1 : 0);
michael@0 4007 code += 1 << (lengthExtraBits[i] = ~(~((j += i > 4 ? 1 : 0) / 4 % 6)));
michael@0 4008 }
michael@0 4009 for (var i = 0; i < 288; ++i)
michael@0 4010 bitLengths[i] = i < 144 || i > 279 ? 8 : i < 256 ? 9 : 7;
michael@0 4011 var fixedLiteralTable = makeHuffmanTable(bitLengths);
michael@0 4012 function makeHuffmanTable(bitLengths) {
michael@0 4013 var maxBits = Math.max.apply(null, bitLengths);
michael@0 4014 var numLengths = bitLengths.length;
michael@0 4015 var size = 1 << maxBits;
michael@0 4016 var codes = new Uint32Array(size);
michael@0 4017 for (var code = 0, len = 1, skip = 2; len <= maxBits; code <<= 1, ++len, skip <<= 1) {
michael@0 4018 for (var val = 0; val < numLengths; ++val) {
michael@0 4019 if (bitLengths[val] === len) {
michael@0 4020 var lsb = 0;
michael@0 4021 for (var i = 0; i < len; ++i)
michael@0 4022 lsb = lsb * 2 + (code >> i & 1);
michael@0 4023 for (var i = lsb; i < size; i += skip)
michael@0 4024 codes[i] = len << 16 | val;
michael@0 4025 ++code;
michael@0 4026 }
michael@0 4027 }
michael@0 4028 }
michael@0 4029 return {
michael@0 4030 codes: codes,
michael@0 4031 maxBits: maxBits
michael@0 4032 };
michael@0 4033 }
michael@0 4034 function verifyDeflateHeader(bytes) {
michael@0 4035 var header = bytes[0] << 8 | bytes[1];
michael@0 4036 }
michael@0 4037 function createInflatedStream(bytes, outputLength) {
michael@0 4038 verifyDeflateHeader(bytes);
michael@0 4039 var stream = new Stream(bytes, 2);
michael@0 4040 var output = {
michael@0 4041 data: new Uint8Array(outputLength),
michael@0 4042 available: 0,
michael@0 4043 completed: false
michael@0 4044 };
michael@0 4045 var state = {
michael@0 4046 header: null,
michael@0 4047 distanceTable: null,
michael@0 4048 literalTable: null,
michael@0 4049 sym: null,
michael@0 4050 len: null,
michael@0 4051 sym2: null
michael@0 4052 };
michael@0 4053 do {
michael@0 4054 inflateBlock(stream, output, state);
michael@0 4055 } while (!output.completed && stream.pos < stream.end);
michael@0 4056 return new Stream(output.data, 0, output.available);
michael@0 4057 }
michael@0 4058 var InflateNoDataError = {};
michael@0 4059 function inflateBlock(stream, output, state) {
michael@0 4060 var header = state.header !== null ? state.header : state.header = readBits(stream.bytes, stream, 3);
michael@0 4061 switch (header >> 1) {
michael@0 4062 case 0:
michael@0 4063 stream.align();
michael@0 4064 var pos = stream.pos;
michael@0 4065 if (stream.end - pos < 4) {
michael@0 4066 throw InflateNoDataError;
michael@0 4067 }
michael@0 4068 var len = stream.getUint16(pos, true);
michael@0 4069 var nlen = stream.getUint16(pos + 2, true);
michael@0 4070 if (stream.end - pos < 4 + len) {
michael@0 4071 throw InflateNoDataError;
michael@0 4072 }
michael@0 4073 var begin = pos + 4;
michael@0 4074 var end = stream.pos = begin + len;
michael@0 4075 var sbytes = stream.bytes, dbytes = output.data;
michael@0 4076 dbytes.set(sbytes.subarray(begin, end), output.available);
michael@0 4077 output.available += len;
michael@0 4078 break;
michael@0 4079 case 1:
michael@0 4080 inflate(stream, output, fixedLiteralTable, fixedDistanceTable, state);
michael@0 4081 break;
michael@0 4082 case 2:
michael@0 4083 var distanceTable, literalTable;
michael@0 4084 if (state.distanceTable !== null) {
michael@0 4085 distanceTable = state.distanceTable;
michael@0 4086 literalTable = state.literalTable;
michael@0 4087 } else {
michael@0 4088 var sbytes = stream.bytes;
michael@0 4089 var savedBufferPos = stream.pos;
michael@0 4090 var savedBitBuffer = stream.bitBuffer;
michael@0 4091 var savedBitLength = stream.bitLength;
michael@0 4092 var bitLengths = [];
michael@0 4093 var numLiteralCodes, numDistanceCodes;
michael@0 4094 try {
michael@0 4095 numLiteralCodes = readBits(sbytes, stream, 5) + 257;
michael@0 4096 numDistanceCodes = readBits(sbytes, stream, 5) + 1;
michael@0 4097 var numCodes = numLiteralCodes + numDistanceCodes;
michael@0 4098 var numLengthCodes = readBits(sbytes, stream, 4) + 4;
michael@0 4099 for (var i = 0; i < 19; ++i)
michael@0 4100 bitLengths[codeLengthOrder[i]] = i < numLengthCodes ? readBits(sbytes, stream, 3) : 0;
michael@0 4101 var codeLengthTable = makeHuffmanTable(bitLengths);
michael@0 4102 bitLengths = [];
michael@0 4103 var i = 0;
michael@0 4104 var prev = 0;
michael@0 4105 while (i < numCodes) {
michael@0 4106 var j = 1;
michael@0 4107 var sym = readCode(sbytes, stream, codeLengthTable);
michael@0 4108 switch (sym) {
michael@0 4109 case 16:
michael@0 4110 j = readBits(sbytes, stream, 2) + 3;
michael@0 4111 sym = prev;
michael@0 4112 break;
michael@0 4113 case 17:
michael@0 4114 j = readBits(sbytes, stream, 3) + 3;
michael@0 4115 sym = 0;
michael@0 4116 break;
michael@0 4117 case 18:
michael@0 4118 j = readBits(sbytes, stream, 7) + 11;
michael@0 4119 sym = 0;
michael@0 4120 break;
michael@0 4121 default:
michael@0 4122 prev = sym;
michael@0 4123 }
michael@0 4124 while (j--)
michael@0 4125 bitLengths[i++] = sym;
michael@0 4126 }
michael@0 4127 } catch (e) {
michael@0 4128 stream.pos = savedBufferPos;
michael@0 4129 stream.bitBuffer = savedBitBuffer;
michael@0 4130 stream.bitLength = savedBitLength;
michael@0 4131 throw e;
michael@0 4132 }
michael@0 4133 distanceTable = state.distanceTable = makeHuffmanTable(bitLengths.splice(numLiteralCodes, numDistanceCodes));
michael@0 4134 literalTable = state.literalTable = makeHuffmanTable(bitLengths);
michael@0 4135 }
michael@0 4136 inflate(stream, output, literalTable, distanceTable, state);
michael@0 4137 state.distanceTable = null;
michael@0 4138 state.literalTable = null;
michael@0 4139 break;
michael@0 4140 default:
michael@0 4141 fail('unknown block type', 'inflate');
michael@0 4142 }
michael@0 4143 state.header = null;
michael@0 4144 output.completed = !(!(header & 1));
michael@0 4145 }
michael@0 4146 function readBits(bytes, stream, size) {
michael@0 4147 var bitBuffer = stream.bitBuffer;
michael@0 4148 var bitLength = stream.bitLength;
michael@0 4149 if (size > bitLength) {
michael@0 4150 var pos = stream.pos;
michael@0 4151 var end = stream.end;
michael@0 4152 do {
michael@0 4153 if (pos >= end) {
michael@0 4154 stream.pos = pos;
michael@0 4155 stream.bitBuffer = bitBuffer;
michael@0 4156 stream.bitLength = bitLength;
michael@0 4157 throw InflateNoDataError;
michael@0 4158 }
michael@0 4159 bitBuffer |= bytes[pos++] << bitLength;
michael@0 4160 bitLength += 8;
michael@0 4161 } while (size > bitLength);
michael@0 4162 stream.pos = pos;
michael@0 4163 }
michael@0 4164 stream.bitBuffer = bitBuffer >>> size;
michael@0 4165 stream.bitLength = bitLength - size;
michael@0 4166 return bitBuffer & (1 << size) - 1;
michael@0 4167 }
michael@0 4168 function inflate(stream, output, literalTable, distanceTable, state) {
michael@0 4169 var pos = output.available;
michael@0 4170 var dbytes = output.data;
michael@0 4171 var sbytes = stream.bytes;
michael@0 4172 var sym = state.sym !== null ? state.sym : readCode(sbytes, stream, literalTable);
michael@0 4173 while (sym !== 256) {
michael@0 4174 if (sym < 256) {
michael@0 4175 dbytes[pos++] = sym;
michael@0 4176 } else {
michael@0 4177 state.sym = sym;
michael@0 4178 sym -= 257;
michael@0 4179 var len = state.len !== null ? state.len : state.len = lengthCodes[sym] + readBits(sbytes, stream, lengthExtraBits[sym]);
michael@0 4180 var sym2 = state.sym2 !== null ? state.sym2 : state.sym2 = readCode(sbytes, stream, distanceTable);
michael@0 4181 var distance = distanceCodes[sym2] + readBits(sbytes, stream, distanceExtraBits[sym2]);
michael@0 4182 var i = pos - distance;
michael@0 4183 while (len--)
michael@0 4184 dbytes[pos++] = dbytes[i++];
michael@0 4185 state.sym2 = null;
michael@0 4186 state.len = null;
michael@0 4187 state.sym = null;
michael@0 4188 }
michael@0 4189 output.available = pos;
michael@0 4190 sym = readCode(sbytes, stream, literalTable);
michael@0 4191 }
michael@0 4192 }
michael@0 4193 function readCode(bytes, stream, codeTable) {
michael@0 4194 var bitBuffer = stream.bitBuffer;
michael@0 4195 var bitLength = stream.bitLength;
michael@0 4196 var maxBits = codeTable.maxBits;
michael@0 4197 if (maxBits > bitLength) {
michael@0 4198 var pos = stream.pos;
michael@0 4199 var end = stream.end;
michael@0 4200 do {
michael@0 4201 if (pos >= end) {
michael@0 4202 stream.pos = pos;
michael@0 4203 stream.bitBuffer = bitBuffer;
michael@0 4204 stream.bitLength = bitLength;
michael@0 4205 throw InflateNoDataError;
michael@0 4206 }
michael@0 4207 bitBuffer |= bytes[pos++] << bitLength;
michael@0 4208 bitLength += 8;
michael@0 4209 } while (maxBits > bitLength);
michael@0 4210 stream.pos = pos;
michael@0 4211 }
michael@0 4212 var code = codeTable.codes[bitBuffer & (1 << maxBits) - 1];
michael@0 4213 var len = code >> 16;
michael@0 4214 stream.bitBuffer = bitBuffer >>> len;
michael@0 4215 stream.bitLength = bitLength - len;
michael@0 4216 return code & 65535;
michael@0 4217 }
michael@0 4218 (function (global) {
michael@0 4219 global['createInflatedStream'] = createInflatedStream;
michael@0 4220 }(this));
michael@0 4221 var StreamNoDataError = {};
michael@0 4222 var Stream = function StreamClosure() {
michael@0 4223 function Stream_align() {
michael@0 4224 this.bitBuffer = this.bitLength = 0;
michael@0 4225 }
michael@0 4226 function Stream_ensure(size) {
michael@0 4227 if (this.pos + size > this.end) {
michael@0 4228 throw StreamNoDataError;
michael@0 4229 }
michael@0 4230 }
michael@0 4231 function Stream_remaining() {
michael@0 4232 return this.end - this.pos;
michael@0 4233 }
michael@0 4234 function Stream_substream(begin, end) {
michael@0 4235 var stream = new Stream(this.bytes);
michael@0 4236 stream.pos = begin;
michael@0 4237 stream.end = end;
michael@0 4238 return stream;
michael@0 4239 }
michael@0 4240 function Stream_push(data) {
michael@0 4241 var bytes = this.bytes;
michael@0 4242 var newBytesLength = this.end + data.length;
michael@0 4243 if (newBytesLength > bytes.length) {
michael@0 4244 throw 'stream buffer overfow';
michael@0 4245 }
michael@0 4246 bytes.set(data, this.end);
michael@0 4247 this.end = newBytesLength;
michael@0 4248 }
michael@0 4249 function Stream(buffer, offset, length, maxLength) {
michael@0 4250 if (offset === undefined)
michael@0 4251 offset = 0;
michael@0 4252 if (buffer.buffer instanceof ArrayBuffer) {
michael@0 4253 offset += buffer.byteOffset;
michael@0 4254 buffer = buffer.buffer;
michael@0 4255 }
michael@0 4256 if (length === undefined)
michael@0 4257 length = buffer.byteLength - offset;
michael@0 4258 if (maxLength === undefined)
michael@0 4259 maxLength = length;
michael@0 4260 var bytes = new Uint8Array(buffer, offset, maxLength);
michael@0 4261 var stream = new DataView(buffer, offset, maxLength);
michael@0 4262 stream.bytes = bytes;
michael@0 4263 stream.pos = 0;
michael@0 4264 stream.end = length;
michael@0 4265 stream.bitBuffer = 0;
michael@0 4266 stream.bitLength = 0;
michael@0 4267 stream.align = Stream_align;
michael@0 4268 stream.ensure = Stream_ensure;
michael@0 4269 stream.remaining = Stream_remaining;
michael@0 4270 stream.substream = Stream_substream;
michael@0 4271 stream.push = Stream_push;
michael@0 4272 return stream;
michael@0 4273 }
michael@0 4274 return Stream;
michael@0 4275 }();
michael@0 4276 (function (global) {
michael@0 4277 global['Stream'] = Stream;
michael@0 4278 }(this));
michael@0 4279 function readSi8($bytes, $stream) {
michael@0 4280 return $stream.getInt8($stream.pos++);
michael@0 4281 }
michael@0 4282 function readSi16($bytes, $stream) {
michael@0 4283 return $stream.getInt16($stream.pos, $stream.pos += 2);
michael@0 4284 }
michael@0 4285 function readSi32($bytes, $stream) {
michael@0 4286 return $stream.getInt32($stream.pos, $stream.pos += 4);
michael@0 4287 }
michael@0 4288 function readUi8($bytes, $stream) {
michael@0 4289 return $bytes[$stream.pos++];
michael@0 4290 }
michael@0 4291 function readUi16($bytes, $stream) {
michael@0 4292 return $stream.getUint16($stream.pos, $stream.pos += 2);
michael@0 4293 }
michael@0 4294 function readUi32($bytes, $stream) {
michael@0 4295 return $stream.getUint32($stream.pos, $stream.pos += 4);
michael@0 4296 }
michael@0 4297 function readFixed($bytes, $stream) {
michael@0 4298 return $stream.getInt32($stream.pos, $stream.pos += 4) / 65536;
michael@0 4299 }
michael@0 4300 function readFixed8($bytes, $stream) {
michael@0 4301 return $stream.getInt16($stream.pos, $stream.pos += 2) / 256;
michael@0 4302 }
michael@0 4303 function readFloat16($bytes, $stream) {
michael@0 4304 var ui16 = $stream.getUint16($stream.pos);
michael@0 4305 $stream.pos += 2;
michael@0 4306 var sign = ui16 >> 15 ? -1 : 1;
michael@0 4307 var exponent = (ui16 & 31744) >> 10;
michael@0 4308 var fraction = ui16 & 1023;
michael@0 4309 if (!exponent)
michael@0 4310 return sign * pow(2, -14) * (fraction / 1024);
michael@0 4311 if (exponent === 31)
michael@0 4312 return fraction ? NaN : sign * Infinity;
michael@0 4313 return sign * pow(2, exponent - 15) * (1 + fraction / 1024);
michael@0 4314 }
michael@0 4315 function readFloat($bytes, $stream) {
michael@0 4316 return $stream.getFloat32($stream.pos, $stream.pos += 4);
michael@0 4317 }
michael@0 4318 function readDouble($bytes, $stream) {
michael@0 4319 return $stream.getFloat64($stream.pos, $stream.pos += 8);
michael@0 4320 }
michael@0 4321 function readEncodedU32($bytes, $stream) {
michael@0 4322 var val = $bytes[$stream.pos++];
michael@0 4323 if (!(val & 128))
michael@0 4324 return val;
michael@0 4325 val |= $bytes[$stream.pos++] << 7;
michael@0 4326 if (!(val & 16384))
michael@0 4327 return val;
michael@0 4328 val |= $bytes[$stream.pos++] << 14;
michael@0 4329 if (!(val & 2097152))
michael@0 4330 return val;
michael@0 4331 val |= $bytes[$stream.pos++] << 21;
michael@0 4332 if (!(val & 268435456))
michael@0 4333 return val;
michael@0 4334 return val | $bytes[$stream.pos++] << 28;
michael@0 4335 }
michael@0 4336 function readBool($bytes, $stream) {
michael@0 4337 return !(!$bytes[$stream.pos++]);
michael@0 4338 }
michael@0 4339 function align($bytes, $stream) {
michael@0 4340 $stream.align();
michael@0 4341 }
michael@0 4342 function readSb($bytes, $stream, size) {
michael@0 4343 return readUb($bytes, $stream, size) << 32 - size >> 32 - size;
michael@0 4344 }
michael@0 4345 var masks = new Uint32Array(33);
michael@0 4346 for (var i = 1, mask = 0; i <= 32; ++i)
michael@0 4347 masks[i] = mask = mask << 1 | 1;
michael@0 4348 function readUb($bytes, $stream, size) {
michael@0 4349 var buffer = $stream.bitBuffer;
michael@0 4350 var bitlen = $stream.bitLength;
michael@0 4351 while (size > bitlen) {
michael@0 4352 buffer = buffer << 8 | $bytes[$stream.pos++];
michael@0 4353 bitlen += 8;
michael@0 4354 }
michael@0 4355 bitlen -= size;
michael@0 4356 var val = buffer >>> bitlen & masks[size];
michael@0 4357 $stream.bitBuffer = buffer;
michael@0 4358 $stream.bitLength = bitlen;
michael@0 4359 return val;
michael@0 4360 }
michael@0 4361 function readFb($bytes, $stream, size) {
michael@0 4362 return readSb($bytes, $stream, size) / 65536;
michael@0 4363 }
michael@0 4364 function readString($bytes, $stream, length) {
michael@0 4365 var codes = [];
michael@0 4366 var pos = $stream.pos;
michael@0 4367 if (length) {
michael@0 4368 codes = slice.call($bytes, pos, pos += length);
michael@0 4369 } else {
michael@0 4370 length = 0;
michael@0 4371 for (var code; code = $bytes[pos++]; length++)
michael@0 4372 codes[length] = code;
michael@0 4373 }
michael@0 4374 $stream.pos = pos;
michael@0 4375 var numChunks = length / 65536;
michael@0 4376 var str = '';
michael@0 4377 for (var i = 0; i < numChunks; ++i) {
michael@0 4378 var begin = i * 65536;
michael@0 4379 var end = begin + 65536;
michael@0 4380 var chunk = codes.slice(begin, end);
michael@0 4381 str += fromCharCode.apply(null, chunk);
michael@0 4382 }
michael@0 4383 return decodeURIComponent(escape(str.replace('\0', '', 'g')));
michael@0 4384 }
michael@0 4385 function readBinary($bytes, $stream, size) {
michael@0 4386 return $bytes.subarray($stream.pos, $stream.pos = size ? $stream.pos + size : $stream.end);
michael@0 4387 }
michael@0 4388 (function (global) {
michael@0 4389 global['readSi8'] = readSi8;
michael@0 4390 global['readUi16'] = readUi16;
michael@0 4391 global['readUi32'] = readUi32;
michael@0 4392 }(this));
michael@0 4393 var tagHandler = function (global) {
michael@0 4394 function defineShape($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4395 $ || ($ = {});
michael@0 4396 $.id = readUi16($bytes, $stream);
michael@0 4397 var $0 = $.bbox = {};
michael@0 4398 bbox($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4399 var isMorph = $.isMorph = tagCode === 46 || tagCode === 84;
michael@0 4400 if (isMorph) {
michael@0 4401 var $1 = $.bboxMorph = {};
michael@0 4402 bbox($bytes, $stream, $1, swfVersion, tagCode);
michael@0 4403 }
michael@0 4404 var hasStrokes = $.hasStrokes = tagCode === 83 || tagCode === 84;
michael@0 4405 if (hasStrokes) {
michael@0 4406 var $2 = $.strokeBbox = {};
michael@0 4407 bbox($bytes, $stream, $2, swfVersion, tagCode);
michael@0 4408 if (isMorph) {
michael@0 4409 var $3 = $.strokeBboxMorph = {};
michael@0 4410 bbox($bytes, $stream, $3, swfVersion, tagCode);
michael@0 4411 }
michael@0 4412 var reserved = readUb($bytes, $stream, 5);
michael@0 4413 $.fillWinding = readUb($bytes, $stream, 1);
michael@0 4414 $.nonScalingStrokes = readUb($bytes, $stream, 1);
michael@0 4415 $.scalingStrokes = readUb($bytes, $stream, 1);
michael@0 4416 }
michael@0 4417 if (isMorph) {
michael@0 4418 $.offsetMorph = readUi32($bytes, $stream);
michael@0 4419 morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 4420 } else {
michael@0 4421 shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 4422 }
michael@0 4423 return $;
michael@0 4424 }
michael@0 4425 function placeObject($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4426 var flags, hasEvents, clip, hasName, hasRatio, hasCxform, hasMatrix, place;
michael@0 4427 var move, hasBackgroundColor, hasVisibility, hasImage, hasClassName, cache;
michael@0 4428 var blend, hasFilters, eoe;
michael@0 4429 $ || ($ = {});
michael@0 4430 if (tagCode > 4) {
michael@0 4431 if (tagCode > 26) {
michael@0 4432 flags = readUi16($bytes, $stream);
michael@0 4433 } else {
michael@0 4434 flags = readUi8($bytes, $stream);
michael@0 4435 }
michael@0 4436 hasEvents = $.hasEvents = flags >> 7 & 1;
michael@0 4437 clip = $.clip = flags >> 6 & 1;
michael@0 4438 hasName = $.hasName = flags >> 5 & 1;
michael@0 4439 hasRatio = $.hasRatio = flags >> 4 & 1;
michael@0 4440 hasCxform = $.hasCxform = flags >> 3 & 1;
michael@0 4441 hasMatrix = $.hasMatrix = flags >> 2 & 1;
michael@0 4442 place = $.place = flags >> 1 & 1;
michael@0 4443 move = $.move = flags & 1;
michael@0 4444 if (tagCode === 70) {
michael@0 4445 hasBackgroundColor = $.hasBackgroundColor = flags >> 15 & 1;
michael@0 4446 hasVisibility = $.hasVisibility = flags >> 14 & 1;
michael@0 4447 hasImage = $.hasImage = flags >> 12 & 1;
michael@0 4448 hasClassName = $.hasClassName = flags >> 11 & 1;
michael@0 4449 cache = $.cache = flags >> 10 & 1;
michael@0 4450 blend = $.blend = flags >> 9 & 1;
michael@0 4451 hasFilters = $.hasFilters = flags >> 8 & 1;
michael@0 4452 } else {
michael@0 4453 cache = $.cache = 0;
michael@0 4454 blend = $.blend = 0;
michael@0 4455 hasFilters = $.hasFilters = 0;
michael@0 4456 }
michael@0 4457 $.depth = readUi16($bytes, $stream);
michael@0 4458 if (hasClassName) {
michael@0 4459 $.className = readString($bytes, $stream, 0);
michael@0 4460 }
michael@0 4461 if (place) {
michael@0 4462 $.symbolId = readUi16($bytes, $stream);
michael@0 4463 }
michael@0 4464 if (hasMatrix) {
michael@0 4465 var $0 = $.matrix = {};
michael@0 4466 matrix($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4467 }
michael@0 4468 if (hasCxform) {
michael@0 4469 var $1 = $.cxform = {};
michael@0 4470 cxform($bytes, $stream, $1, swfVersion, tagCode);
michael@0 4471 }
michael@0 4472 if (hasRatio) {
michael@0 4473 $.ratio = readUi16($bytes, $stream);
michael@0 4474 }
michael@0 4475 if (hasName) {
michael@0 4476 $.name = readString($bytes, $stream, 0);
michael@0 4477 }
michael@0 4478 if (clip) {
michael@0 4479 $.clipDepth = readUi16($bytes, $stream);
michael@0 4480 }
michael@0 4481 if (hasFilters) {
michael@0 4482 var count = readUi8($bytes, $stream);
michael@0 4483 var $2 = $.filters = [];
michael@0 4484 var $3 = count;
michael@0 4485 while ($3--) {
michael@0 4486 var $4 = {};
michael@0 4487 anyFilter($bytes, $stream, $4, swfVersion, tagCode);
michael@0 4488 $2.push($4);
michael@0 4489 }
michael@0 4490 }
michael@0 4491 if (blend) {
michael@0 4492 $.blendMode = readUi8($bytes, $stream);
michael@0 4493 }
michael@0 4494 if (cache) {
michael@0 4495 $.bmpCache = readUi8($bytes, $stream);
michael@0 4496 }
michael@0 4497 if (hasEvents) {
michael@0 4498 var reserved = readUi16($bytes, $stream);
michael@0 4499 if (swfVersion >= 6) {
michael@0 4500 var allFlags = readUi32($bytes, $stream);
michael@0 4501 } else {
michael@0 4502 var allFlags = readUi16($bytes, $stream);
michael@0 4503 }
michael@0 4504 var $28 = $.events = [];
michael@0 4505 do {
michael@0 4506 var $29 = {};
michael@0 4507 var temp = events($bytes, $stream, $29, swfVersion, tagCode);
michael@0 4508 eoe = temp.eoe;
michael@0 4509 $28.push($29);
michael@0 4510 } while (!eoe);
michael@0 4511 }
michael@0 4512 if (hasBackgroundColor) {
michael@0 4513 var $126 = $.backgroundColor = {};
michael@0 4514 argb($bytes, $stream, $126, swfVersion, tagCode);
michael@0 4515 }
michael@0 4516 if (hasVisibility) {
michael@0 4517 $.visibility = readUi8($bytes, $stream);
michael@0 4518 }
michael@0 4519 } else {
michael@0 4520 $.place = 1;
michael@0 4521 $.symbolId = readUi16($bytes, $stream);
michael@0 4522 $.depth = readUi16($bytes, $stream);
michael@0 4523 $.hasMatrix = 1;
michael@0 4524 var $30 = $.matrix = {};
michael@0 4525 matrix($bytes, $stream, $30, swfVersion, tagCode);
michael@0 4526 if ($stream.remaining()) {
michael@0 4527 $.hasCxform = 1;
michael@0 4528 var $31 = $.cxform = {};
michael@0 4529 cxform($bytes, $stream, $31, swfVersion, tagCode);
michael@0 4530 }
michael@0 4531 }
michael@0 4532 return $;
michael@0 4533 }
michael@0 4534 function removeObject($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4535 $ || ($ = {});
michael@0 4536 if (tagCode === 5) {
michael@0 4537 $.symbolId = readUi16($bytes, $stream);
michael@0 4538 }
michael@0 4539 $.depth = readUi16($bytes, $stream);
michael@0 4540 return $;
michael@0 4541 }
michael@0 4542 function defineImage($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4543 var imgData;
michael@0 4544 $ || ($ = {});
michael@0 4545 $.id = readUi16($bytes, $stream);
michael@0 4546 if (tagCode > 21) {
michael@0 4547 var alphaDataOffset = readUi32($bytes, $stream);
michael@0 4548 if (tagCode === 90) {
michael@0 4549 $.deblock = readFixed8($bytes, $stream);
michael@0 4550 }
michael@0 4551 imgData = $.imgData = readBinary($bytes, $stream, alphaDataOffset);
michael@0 4552 $.alphaData = readBinary($bytes, $stream, 0);
michael@0 4553 } else {
michael@0 4554 imgData = $.imgData = readBinary($bytes, $stream, 0);
michael@0 4555 }
michael@0 4556 switch (imgData[0] << 8 | imgData[1]) {
michael@0 4557 case 65496:
michael@0 4558 case 65497:
michael@0 4559 $.mimeType = 'image/jpeg';
michael@0 4560 break;
michael@0 4561 case 35152:
michael@0 4562 $.mimeType = 'image/png';
michael@0 4563 break;
michael@0 4564 case 18249:
michael@0 4565 $.mimeType = 'image/gif';
michael@0 4566 break;
michael@0 4567 default:
michael@0 4568 $.mimeType = 'application/octet-stream';
michael@0 4569 }
michael@0 4570 if (tagCode === 6) {
michael@0 4571 $.incomplete = 1;
michael@0 4572 }
michael@0 4573 return $;
michael@0 4574 }
michael@0 4575 function defineButton($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4576 var eob, hasFilters, count, blend;
michael@0 4577 $ || ($ = {});
michael@0 4578 $.id = readUi16($bytes, $stream);
michael@0 4579 if (tagCode == 7) {
michael@0 4580 var $0 = $.characters = [];
michael@0 4581 do {
michael@0 4582 var $1 = {};
michael@0 4583 var temp = button($bytes, $stream, $1, swfVersion, tagCode);
michael@0 4584 eob = temp.eob;
michael@0 4585 $0.push($1);
michael@0 4586 } while (!eob);
michael@0 4587 $.actionsData = readBinary($bytes, $stream, 0);
michael@0 4588 } else {
michael@0 4589 var trackFlags = readUi8($bytes, $stream);
michael@0 4590 $.trackAsMenu = trackFlags >> 7 & 1;
michael@0 4591 var actionOffset = readUi16($bytes, $stream);
michael@0 4592 var $28 = $.characters = [];
michael@0 4593 do {
michael@0 4594 var $29 = {};
michael@0 4595 var flags = readUi8($bytes, $stream);
michael@0 4596 var eob = $29.eob = !flags;
michael@0 4597 if (swfVersion >= 8) {
michael@0 4598 blend = $29.blend = flags >> 5 & 1;
michael@0 4599 hasFilters = $29.hasFilters = flags >> 4 & 1;
michael@0 4600 } else {
michael@0 4601 blend = $29.blend = 0;
michael@0 4602 hasFilters = $29.hasFilters = 0;
michael@0 4603 }
michael@0 4604 $29.stateHitTest = flags >> 3 & 1;
michael@0 4605 $29.stateDown = flags >> 2 & 1;
michael@0 4606 $29.stateOver = flags >> 1 & 1;
michael@0 4607 $29.stateUp = flags & 1;
michael@0 4608 if (!eob) {
michael@0 4609 $29.symbolId = readUi16($bytes, $stream);
michael@0 4610 $29.depth = readUi16($bytes, $stream);
michael@0 4611 var $30 = $29.matrix = {};
michael@0 4612 matrix($bytes, $stream, $30, swfVersion, tagCode);
michael@0 4613 if (tagCode === 34) {
michael@0 4614 var $31 = $29.cxform = {};
michael@0 4615 cxform($bytes, $stream, $31, swfVersion, tagCode);
michael@0 4616 }
michael@0 4617 if (hasFilters) {
michael@0 4618 var count = readUi8($bytes, $stream);
michael@0 4619 var $2 = $.filters = [];
michael@0 4620 var $3 = count;
michael@0 4621 while ($3--) {
michael@0 4622 var $4 = {};
michael@0 4623 anyFilter($bytes, $stream, $4, swfVersion, tagCode);
michael@0 4624 $2.push($4);
michael@0 4625 }
michael@0 4626 }
michael@0 4627 if (blend) {
michael@0 4628 $29.blendMode = readUi8($bytes, $stream);
michael@0 4629 }
michael@0 4630 }
michael@0 4631 $28.push($29);
michael@0 4632 } while (!eob);
michael@0 4633 if (!(!actionOffset)) {
michael@0 4634 var $56 = $.buttonActions = [];
michael@0 4635 do {
michael@0 4636 var $57 = {};
michael@0 4637 buttonCondAction($bytes, $stream, $57, swfVersion, tagCode);
michael@0 4638 $56.push($57);
michael@0 4639 } while ($stream.remaining() > 0);
michael@0 4640 }
michael@0 4641 }
michael@0 4642 return $;
michael@0 4643 }
michael@0 4644 function defineJPEGTables($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4645 $ || ($ = {});
michael@0 4646 $.id = 0;
michael@0 4647 $.imgData = readBinary($bytes, $stream, 0);
michael@0 4648 $.mimeType = 'application/octet-stream';
michael@0 4649 return $;
michael@0 4650 }
michael@0 4651 function setBackgroundColor($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4652 $ || ($ = {});
michael@0 4653 var $0 = $.color = {};
michael@0 4654 rgb($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4655 return $;
michael@0 4656 }
michael@0 4657 function defineBinaryData($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4658 $ || ($ = {});
michael@0 4659 $.id = readUi16($bytes, $stream);
michael@0 4660 var reserved = readUi32($bytes, $stream);
michael@0 4661 $.data = readBinary($bytes, $stream, 0);
michael@0 4662 return $;
michael@0 4663 }
michael@0 4664 function defineFont($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4665 $ || ($ = {});
michael@0 4666 $.id = readUi16($bytes, $stream);
michael@0 4667 var firstOffset = readUi16($bytes, $stream);
michael@0 4668 var glyphCount = $.glyphCount = firstOffset / 2;
michael@0 4669 var restOffsets = [];
michael@0 4670 var $0 = glyphCount - 1;
michael@0 4671 while ($0--) {
michael@0 4672 restOffsets.push(readUi16($bytes, $stream));
michael@0 4673 }
michael@0 4674 $.offsets = [
michael@0 4675 firstOffset
michael@0 4676 ].concat(restOffsets);
michael@0 4677 var $1 = $.glyphs = [];
michael@0 4678 var $2 = glyphCount;
michael@0 4679 while ($2--) {
michael@0 4680 var $3 = {};
michael@0 4681 shape($bytes, $stream, $3, swfVersion, tagCode);
michael@0 4682 $1.push($3);
michael@0 4683 }
michael@0 4684 return $;
michael@0 4685 }
michael@0 4686 function defineLabel($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4687 var eot;
michael@0 4688 $ || ($ = {});
michael@0 4689 $.id = readUi16($bytes, $stream);
michael@0 4690 var $0 = $.bbox = {};
michael@0 4691 bbox($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4692 var $1 = $.matrix = {};
michael@0 4693 matrix($bytes, $stream, $1, swfVersion, tagCode);
michael@0 4694 var glyphBits = $.glyphBits = readUi8($bytes, $stream);
michael@0 4695 var advanceBits = $.advanceBits = readUi8($bytes, $stream);
michael@0 4696 var $2 = $.records = [];
michael@0 4697 do {
michael@0 4698 var $3 = {};
michael@0 4699 var temp = textRecord($bytes, $stream, $3, swfVersion, tagCode, glyphBits, advanceBits);
michael@0 4700 eot = temp.eot;
michael@0 4701 $2.push($3);
michael@0 4702 } while (!eot);
michael@0 4703 return $;
michael@0 4704 }
michael@0 4705 function doAction($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4706 $ || ($ = {});
michael@0 4707 if (tagCode === 59) {
michael@0 4708 $.spriteId = readUi16($bytes, $stream);
michael@0 4709 }
michael@0 4710 $.actionsData = readBinary($bytes, $stream, 0);
michael@0 4711 return $;
michael@0 4712 }
michael@0 4713 function defineSound($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4714 $ || ($ = {});
michael@0 4715 $.id = readUi16($bytes, $stream);
michael@0 4716 var soundFlags = readUi8($bytes, $stream);
michael@0 4717 $.soundFormat = soundFlags >> 4 & 15;
michael@0 4718 $.soundRate = soundFlags >> 2 & 3;
michael@0 4719 $.soundSize = soundFlags >> 1 & 1;
michael@0 4720 $.soundType = soundFlags & 1;
michael@0 4721 $.samplesCount = readUi32($bytes, $stream);
michael@0 4722 $.soundData = readBinary($bytes, $stream, 0);
michael@0 4723 return $;
michael@0 4724 }
michael@0 4725 function startSound($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4726 $ || ($ = {});
michael@0 4727 if (tagCode == 15) {
michael@0 4728 $.soundId = readUi16($bytes, $stream);
michael@0 4729 }
michael@0 4730 if (tagCode == 89) {
michael@0 4731 $.soundClassName = readString($bytes, $stream, 0);
michael@0 4732 }
michael@0 4733 var $0 = $.soundInfo = {};
michael@0 4734 soundInfo($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4735 return $;
michael@0 4736 }
michael@0 4737 function soundStreamHead($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4738 $ || ($ = {});
michael@0 4739 var playbackFlags = readUi8($bytes, $stream);
michael@0 4740 $.playbackRate = playbackFlags >> 2 & 3;
michael@0 4741 $.playbackSize = playbackFlags >> 1 & 1;
michael@0 4742 $.playbackType = playbackFlags & 1;
michael@0 4743 var streamFlags = readUi8($bytes, $stream);
michael@0 4744 var streamCompression = $.streamCompression = streamFlags >> 4 & 15;
michael@0 4745 $.streamRate = streamFlags >> 2 & 3;
michael@0 4746 $.streamSize = streamFlags >> 1 & 1;
michael@0 4747 $.streamType = streamFlags & 1;
michael@0 4748 $.samplesCount = readUi32($bytes, $stream);
michael@0 4749 if (streamCompression == 2) {
michael@0 4750 $.latencySeek = readSi16($bytes, $stream);
michael@0 4751 }
michael@0 4752 return $;
michael@0 4753 }
michael@0 4754 function soundStreamBlock($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4755 $ || ($ = {});
michael@0 4756 $.data = readBinary($bytes, $stream, 0);
michael@0 4757 return $;
michael@0 4758 }
michael@0 4759 function defineBitmap($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4760 $ || ($ = {});
michael@0 4761 $.id = readUi16($bytes, $stream);
michael@0 4762 var format = $.format = readUi8($bytes, $stream);
michael@0 4763 $.width = readUi16($bytes, $stream);
michael@0 4764 $.height = readUi16($bytes, $stream);
michael@0 4765 $.hasAlpha = tagCode === 36;
michael@0 4766 if (format === 3) {
michael@0 4767 $.colorTableSize = readUi8($bytes, $stream);
michael@0 4768 }
michael@0 4769 $.bmpData = readBinary($bytes, $stream, 0);
michael@0 4770 return $;
michael@0 4771 }
michael@0 4772 function defineText($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4773 $ || ($ = {});
michael@0 4774 $.id = readUi16($bytes, $stream);
michael@0 4775 var $0 = $.bbox = {};
michael@0 4776 bbox($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4777 var flags = readUi16($bytes, $stream);
michael@0 4778 var hasText = $.hasText = flags >> 7 & 1;
michael@0 4779 $.wordWrap = flags >> 6 & 1;
michael@0 4780 $.multiline = flags >> 5 & 1;
michael@0 4781 $.password = flags >> 4 & 1;
michael@0 4782 $.readonly = flags >> 3 & 1;
michael@0 4783 var hasColor = $.hasColor = flags >> 2 & 1;
michael@0 4784 var hasMaxLength = $.hasMaxLength = flags >> 1 & 1;
michael@0 4785 var hasFont = $.hasFont = flags & 1;
michael@0 4786 var hasFontClass = $.hasFontClass = flags >> 15 & 1;
michael@0 4787 $.autoSize = flags >> 14 & 1;
michael@0 4788 var hasLayout = $.hasLayout = flags >> 13 & 1;
michael@0 4789 $.noSelect = flags >> 12 & 1;
michael@0 4790 $.border = flags >> 11 & 1;
michael@0 4791 $.wasStatic = flags >> 10 & 1;
michael@0 4792 $.html = flags >> 9 & 1;
michael@0 4793 $.useOutlines = flags >> 8 & 1;
michael@0 4794 if (hasFont) {
michael@0 4795 $.fontId = readUi16($bytes, $stream);
michael@0 4796 }
michael@0 4797 if (hasFontClass) {
michael@0 4798 $.fontClass = readString($bytes, $stream, 0);
michael@0 4799 }
michael@0 4800 if (hasFont) {
michael@0 4801 $.fontHeight = readUi16($bytes, $stream);
michael@0 4802 }
michael@0 4803 if (hasColor) {
michael@0 4804 var $1 = $.color = {};
michael@0 4805 rgba($bytes, $stream, $1, swfVersion, tagCode);
michael@0 4806 }
michael@0 4807 if (hasMaxLength) {
michael@0 4808 $.maxLength = readUi16($bytes, $stream);
michael@0 4809 }
michael@0 4810 if (hasLayout) {
michael@0 4811 $.align = readUi8($bytes, $stream);
michael@0 4812 $.leftMargin = readUi16($bytes, $stream);
michael@0 4813 $.rightMargin = readUi16($bytes, $stream);
michael@0 4814 $.indent = readSi16($bytes, $stream);
michael@0 4815 $.leading = readSi16($bytes, $stream);
michael@0 4816 }
michael@0 4817 $.variableName = readString($bytes, $stream, 0);
michael@0 4818 if (hasText) {
michael@0 4819 $.initialText = readString($bytes, $stream, 0);
michael@0 4820 }
michael@0 4821 return $;
michael@0 4822 }
michael@0 4823 function frameLabel($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4824 $ || ($ = {});
michael@0 4825 $.name = readString($bytes, $stream, 0);
michael@0 4826 return $;
michael@0 4827 }
michael@0 4828 function defineFont2($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4829 $ || ($ = {});
michael@0 4830 $.id = readUi16($bytes, $stream);
michael@0 4831 var hasLayout = $.hasLayout = readUb($bytes, $stream, 1);
michael@0 4832 if (swfVersion > 5) {
michael@0 4833 $.shiftJis = readUb($bytes, $stream, 1);
michael@0 4834 } else {
michael@0 4835 var reserved = readUb($bytes, $stream, 1);
michael@0 4836 }
michael@0 4837 $.smallText = readUb($bytes, $stream, 1);
michael@0 4838 $.ansi = readUb($bytes, $stream, 1);
michael@0 4839 var wideOffset = $.wideOffset = readUb($bytes, $stream, 1);
michael@0 4840 var wide = $.wide = readUb($bytes, $stream, 1);
michael@0 4841 $.italic = readUb($bytes, $stream, 1);
michael@0 4842 $.bold = readUb($bytes, $stream, 1);
michael@0 4843 if (swfVersion > 5) {
michael@0 4844 $.language = readUi8($bytes, $stream);
michael@0 4845 } else {
michael@0 4846 var reserved = readUi8($bytes, $stream);
michael@0 4847 $.language = 0;
michael@0 4848 }
michael@0 4849 var nameLength = readUi8($bytes, $stream);
michael@0 4850 $.name = readString($bytes, $stream, nameLength);
michael@0 4851 if (tagCode === 75) {
michael@0 4852 $.resolution = 20;
michael@0 4853 }
michael@0 4854 var glyphCount = $.glyphCount = readUi16($bytes, $stream);
michael@0 4855 if (wideOffset) {
michael@0 4856 var $0 = $.offsets = [];
michael@0 4857 var $1 = glyphCount;
michael@0 4858 while ($1--) {
michael@0 4859 $0.push(readUi32($bytes, $stream));
michael@0 4860 }
michael@0 4861 $.mapOffset = readUi32($bytes, $stream);
michael@0 4862 } else {
michael@0 4863 var $2 = $.offsets = [];
michael@0 4864 var $3 = glyphCount;
michael@0 4865 while ($3--) {
michael@0 4866 $2.push(readUi16($bytes, $stream));
michael@0 4867 }
michael@0 4868 $.mapOffset = readUi16($bytes, $stream);
michael@0 4869 }
michael@0 4870 var $4 = $.glyphs = [];
michael@0 4871 var $5 = glyphCount;
michael@0 4872 while ($5--) {
michael@0 4873 var $6 = {};
michael@0 4874 shape($bytes, $stream, $6, swfVersion, tagCode);
michael@0 4875 $4.push($6);
michael@0 4876 }
michael@0 4877 if (wide) {
michael@0 4878 var $47 = $.codes = [];
michael@0 4879 var $48 = glyphCount;
michael@0 4880 while ($48--) {
michael@0 4881 $47.push(readUi16($bytes, $stream));
michael@0 4882 }
michael@0 4883 } else {
michael@0 4884 var $49 = $.codes = [];
michael@0 4885 var $50 = glyphCount;
michael@0 4886 while ($50--) {
michael@0 4887 $49.push(readUi8($bytes, $stream));
michael@0 4888 }
michael@0 4889 }
michael@0 4890 if (hasLayout) {
michael@0 4891 $.ascent = readUi16($bytes, $stream);
michael@0 4892 $.descent = readUi16($bytes, $stream);
michael@0 4893 $.leading = readSi16($bytes, $stream);
michael@0 4894 var $51 = $.advance = [];
michael@0 4895 var $52 = glyphCount;
michael@0 4896 while ($52--) {
michael@0 4897 $51.push(readSi16($bytes, $stream));
michael@0 4898 }
michael@0 4899 var $53 = $.bbox = [];
michael@0 4900 var $54 = glyphCount;
michael@0 4901 while ($54--) {
michael@0 4902 var $55 = {};
michael@0 4903 bbox($bytes, $stream, $55, swfVersion, tagCode);
michael@0 4904 $53.push($55);
michael@0 4905 }
michael@0 4906 var kerningCount = readUi16($bytes, $stream);
michael@0 4907 var $56 = $.kerning = [];
michael@0 4908 var $57 = kerningCount;
michael@0 4909 while ($57--) {
michael@0 4910 var $58 = {};
michael@0 4911 kerning($bytes, $stream, $58, swfVersion, tagCode, wide);
michael@0 4912 $56.push($58);
michael@0 4913 }
michael@0 4914 }
michael@0 4915 return $;
michael@0 4916 }
michael@0 4917 function fileAttributes($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4918 $ || ($ = {});
michael@0 4919 var reserved = readUb($bytes, $stream, 1);
michael@0 4920 $.useDirectBlit = readUb($bytes, $stream, 1);
michael@0 4921 $.useGpu = readUb($bytes, $stream, 1);
michael@0 4922 $.hasMetadata = readUb($bytes, $stream, 1);
michael@0 4923 $.doAbc = readUb($bytes, $stream, 1);
michael@0 4924 $.noCrossDomainCaching = readUb($bytes, $stream, 1);
michael@0 4925 $.relativeUrls = readUb($bytes, $stream, 1);
michael@0 4926 $.network = readUb($bytes, $stream, 1);
michael@0 4927 var pad = readUb($bytes, $stream, 24);
michael@0 4928 return $;
michael@0 4929 }
michael@0 4930 function doABC($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4931 $ || ($ = {});
michael@0 4932 if (tagCode === 82) {
michael@0 4933 $.flags = readUi32($bytes, $stream);
michael@0 4934 } else {
michael@0 4935 $.flags = 0;
michael@0 4936 }
michael@0 4937 if (tagCode === 82) {
michael@0 4938 $.name = readString($bytes, $stream, 0);
michael@0 4939 } else {
michael@0 4940 $.name = '';
michael@0 4941 }
michael@0 4942 $.data = readBinary($bytes, $stream, 0);
michael@0 4943 return $;
michael@0 4944 }
michael@0 4945 function exportAssets($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4946 $ || ($ = {});
michael@0 4947 var exportsCount = readUi16($bytes, $stream);
michael@0 4948 var $0 = $.exports = [];
michael@0 4949 var $1 = exportsCount;
michael@0 4950 while ($1--) {
michael@0 4951 var $2 = {};
michael@0 4952 $2.symbolId = readUi16($bytes, $stream);
michael@0 4953 $2.className = readString($bytes, $stream, 0);
michael@0 4954 $0.push($2);
michael@0 4955 }
michael@0 4956 return $;
michael@0 4957 }
michael@0 4958 function symbolClass($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4959 $ || ($ = {});
michael@0 4960 var symbolCount = readUi16($bytes, $stream);
michael@0 4961 var $0 = $.exports = [];
michael@0 4962 var $1 = symbolCount;
michael@0 4963 while ($1--) {
michael@0 4964 var $2 = {};
michael@0 4965 $2.symbolId = readUi16($bytes, $stream);
michael@0 4966 $2.className = readString($bytes, $stream, 0);
michael@0 4967 $0.push($2);
michael@0 4968 }
michael@0 4969 return $;
michael@0 4970 }
michael@0 4971 function defineScalingGrid($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4972 $ || ($ = {});
michael@0 4973 $.symbolId = readUi16($bytes, $stream);
michael@0 4974 var $0 = $.splitter = {};
michael@0 4975 bbox($bytes, $stream, $0, swfVersion, tagCode);
michael@0 4976 return $;
michael@0 4977 }
michael@0 4978 function defineScene($bytes, $stream, $, swfVersion, tagCode) {
michael@0 4979 $ || ($ = {});
michael@0 4980 var sceneCount = readEncodedU32($bytes, $stream);
michael@0 4981 var $0 = $.scenes = [];
michael@0 4982 var $1 = sceneCount;
michael@0 4983 while ($1--) {
michael@0 4984 var $2 = {};
michael@0 4985 $2.offset = readEncodedU32($bytes, $stream);
michael@0 4986 $2.name = readString($bytes, $stream, 0);
michael@0 4987 $0.push($2);
michael@0 4988 }
michael@0 4989 var labelCount = readEncodedU32($bytes, $stream);
michael@0 4990 var $3 = $.labels = [];
michael@0 4991 var $4 = labelCount;
michael@0 4992 while ($4--) {
michael@0 4993 var $5 = {};
michael@0 4994 $5.frame = readEncodedU32($bytes, $stream);
michael@0 4995 $5.name = readString($bytes, $stream, 0);
michael@0 4996 $3.push($5);
michael@0 4997 }
michael@0 4998 return $;
michael@0 4999 }
michael@0 5000 function bbox($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5001 align($bytes, $stream);
michael@0 5002 var bits = readUb($bytes, $stream, 5);
michael@0 5003 var xMin = readSb($bytes, $stream, bits);
michael@0 5004 var xMax = readSb($bytes, $stream, bits);
michael@0 5005 var yMin = readSb($bytes, $stream, bits);
michael@0 5006 var yMax = readSb($bytes, $stream, bits);
michael@0 5007 $.xMin = xMin;
michael@0 5008 $.xMax = xMax;
michael@0 5009 $.yMin = yMin;
michael@0 5010 $.yMax = yMax;
michael@0 5011 align($bytes, $stream);
michael@0 5012 }
michael@0 5013 function rgb($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5014 $.red = readUi8($bytes, $stream);
michael@0 5015 $.green = readUi8($bytes, $stream);
michael@0 5016 $.blue = readUi8($bytes, $stream);
michael@0 5017 $.alpha = 255;
michael@0 5018 return;
michael@0 5019 }
michael@0 5020 function rgba($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5021 $.red = readUi8($bytes, $stream);
michael@0 5022 $.green = readUi8($bytes, $stream);
michael@0 5023 $.blue = readUi8($bytes, $stream);
michael@0 5024 $.alpha = readUi8($bytes, $stream);
michael@0 5025 return;
michael@0 5026 }
michael@0 5027 function argb($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5028 $.alpha = readUi8($bytes, $stream);
michael@0 5029 $.red = readUi8($bytes, $stream);
michael@0 5030 $.green = readUi8($bytes, $stream);
michael@0 5031 $.blue = readUi8($bytes, $stream);
michael@0 5032 }
michael@0 5033 function fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph) {
michael@0 5034 if (tagCode > 22 || isMorph) {
michael@0 5035 var $125 = $.color = {};
michael@0 5036 rgba($bytes, $stream, $125, swfVersion, tagCode);
michael@0 5037 } else {
michael@0 5038 var $126 = $.color = {};
michael@0 5039 rgb($bytes, $stream, $126, swfVersion, tagCode);
michael@0 5040 }
michael@0 5041 if (isMorph) {
michael@0 5042 var $127 = $.colorMorph = {};
michael@0 5043 rgba($bytes, $stream, $127, swfVersion, tagCode);
michael@0 5044 }
michael@0 5045 return;
michael@0 5046 }
michael@0 5047 function matrix($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5048 align($bytes, $stream);
michael@0 5049 var hasScale = readUb($bytes, $stream, 1);
michael@0 5050 if (hasScale) {
michael@0 5051 var bits = readUb($bytes, $stream, 5);
michael@0 5052 $.a = readFb($bytes, $stream, bits);
michael@0 5053 $.d = readFb($bytes, $stream, bits);
michael@0 5054 } else {
michael@0 5055 $.a = 1;
michael@0 5056 $.d = 1;
michael@0 5057 }
michael@0 5058 var hasRotate = readUb($bytes, $stream, 1);
michael@0 5059 if (hasRotate) {
michael@0 5060 var bits = readUb($bytes, $stream, 5);
michael@0 5061 $.b = readFb($bytes, $stream, bits);
michael@0 5062 $.c = readFb($bytes, $stream, bits);
michael@0 5063 } else {
michael@0 5064 $.b = 0;
michael@0 5065 $.c = 0;
michael@0 5066 }
michael@0 5067 var bits = readUb($bytes, $stream, 5);
michael@0 5068 var e = readSb($bytes, $stream, bits);
michael@0 5069 var f = readSb($bytes, $stream, bits);
michael@0 5070 $.tx = e;
michael@0 5071 $.ty = f;
michael@0 5072 align($bytes, $stream);
michael@0 5073 }
michael@0 5074 function cxform($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5075 align($bytes, $stream);
michael@0 5076 var hasOffsets = readUb($bytes, $stream, 1);
michael@0 5077 var hasMultipliers = readUb($bytes, $stream, 1);
michael@0 5078 var bits = readUb($bytes, $stream, 4);
michael@0 5079 if (hasMultipliers) {
michael@0 5080 $.redMultiplier = readSb($bytes, $stream, bits);
michael@0 5081 $.greenMultiplier = readSb($bytes, $stream, bits);
michael@0 5082 $.blueMultiplier = readSb($bytes, $stream, bits);
michael@0 5083 if (tagCode > 4) {
michael@0 5084 $.alphaMultiplier = readSb($bytes, $stream, bits);
michael@0 5085 } else {
michael@0 5086 $.alphaMultiplier = 256;
michael@0 5087 }
michael@0 5088 } else {
michael@0 5089 $.redMultiplier = 256;
michael@0 5090 $.greenMultiplier = 256;
michael@0 5091 $.blueMultiplier = 256;
michael@0 5092 $.alphaMultiplier = 256;
michael@0 5093 }
michael@0 5094 if (hasOffsets) {
michael@0 5095 $.redOffset = readSb($bytes, $stream, bits);
michael@0 5096 $.greenOffset = readSb($bytes, $stream, bits);
michael@0 5097 $.blueOffset = readSb($bytes, $stream, bits);
michael@0 5098 if (tagCode > 4) {
michael@0 5099 $.alphaOffset = readSb($bytes, $stream, bits);
michael@0 5100 } else {
michael@0 5101 $.alphaOffset = 0;
michael@0 5102 }
michael@0 5103 } else {
michael@0 5104 $.redOffset = 0;
michael@0 5105 $.greenOffset = 0;
michael@0 5106 $.blueOffset = 0;
michael@0 5107 $.alphaOffset = 0;
michael@0 5108 }
michael@0 5109 align($bytes, $stream);
michael@0 5110 }
michael@0 5111 function fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
michael@0 5112 var $128 = $.matrix = {};
michael@0 5113 matrix($bytes, $stream, $128, swfVersion, tagCode);
michael@0 5114 if (isMorph) {
michael@0 5115 var $129 = $.matrixMorph = {};
michael@0 5116 matrix($bytes, $stream, $129, swfVersion, tagCode);
michael@0 5117 }
michael@0 5118 gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
michael@0 5119 }
michael@0 5120 function gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
michael@0 5121 if (tagCode === 83) {
michael@0 5122 $.spreadMode = readUb($bytes, $stream, 2);
michael@0 5123 $.interpolationMode = readUb($bytes, $stream, 2);
michael@0 5124 } else {
michael@0 5125 var pad = readUb($bytes, $stream, 4);
michael@0 5126 }
michael@0 5127 var count = $.count = readUb($bytes, $stream, 4);
michael@0 5128 var $130 = $.records = [];
michael@0 5129 var $131 = count;
michael@0 5130 while ($131--) {
michael@0 5131 var $132 = {};
michael@0 5132 gradientRecord($bytes, $stream, $132, swfVersion, tagCode, isMorph);
michael@0 5133 $130.push($132);
michael@0 5134 }
michael@0 5135 if (type === 19) {
michael@0 5136 $.focalPoint = readFixed8($bytes, $stream);
michael@0 5137 if (isMorph) {
michael@0 5138 $.focalPointMorph = readFixed8($bytes, $stream);
michael@0 5139 }
michael@0 5140 }
michael@0 5141 }
michael@0 5142 function gradientRecord($bytes, $stream, $, swfVersion, tagCode, isMorph) {
michael@0 5143 $.ratio = readUi8($bytes, $stream);
michael@0 5144 if (tagCode > 22) {
michael@0 5145 var $133 = $.color = {};
michael@0 5146 rgba($bytes, $stream, $133, swfVersion, tagCode);
michael@0 5147 } else {
michael@0 5148 var $134 = $.color = {};
michael@0 5149 rgb($bytes, $stream, $134, swfVersion, tagCode);
michael@0 5150 }
michael@0 5151 if (isMorph) {
michael@0 5152 $.ratioMorph = readUi8($bytes, $stream);
michael@0 5153 var $135 = $.colorMorph = {};
michael@0 5154 rgba($bytes, $stream, $135, swfVersion, tagCode);
michael@0 5155 }
michael@0 5156 }
michael@0 5157 function morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
michael@0 5158 var eos, bits;
michael@0 5159 var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 5160 var lineBits = temp.lineBits;
michael@0 5161 var fillBits = temp.fillBits;
michael@0 5162 var $160 = $.records = [];
michael@0 5163 do {
michael@0 5164 var $161 = {};
michael@0 5165 var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
michael@0 5166 var eos = temp.eos;
michael@0 5167 var flags = temp.flags;
michael@0 5168 var type = temp.type;
michael@0 5169 var fillBits = temp.fillBits;
michael@0 5170 var lineBits = temp.lineBits;
michael@0 5171 var bits = temp.bits;
michael@0 5172 $160.push($161);
michael@0 5173 } while (!eos);
michael@0 5174 var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
michael@0 5175 var fillBits = temp.fillBits;
michael@0 5176 var lineBits = temp.lineBits;
michael@0 5177 var $162 = $.recordsMorph = [];
michael@0 5178 do {
michael@0 5179 var $163 = {};
michael@0 5180 var temp = shapeRecord($bytes, $stream, $163, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
michael@0 5181 eos = temp.eos;
michael@0 5182 var flags = temp.flags;
michael@0 5183 var type = temp.type;
michael@0 5184 var fillBits = temp.fillBits;
michael@0 5185 var lineBits = temp.lineBits;
michael@0 5186 bits = temp.bits;
michael@0 5187 $162.push($163);
michael@0 5188 } while (!eos);
michael@0 5189 }
michael@0 5190 function shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
michael@0 5191 var eos;
michael@0 5192 var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 5193 var fillBits = temp.fillBits;
michael@0 5194 var lineBits = temp.lineBits;
michael@0 5195 var $160 = $.records = [];
michael@0 5196 do {
michael@0 5197 var $161 = {};
michael@0 5198 var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
michael@0 5199 eos = temp.eos;
michael@0 5200 var flags = temp.flags;
michael@0 5201 var type = temp.type;
michael@0 5202 var fillBits = temp.fillBits;
michael@0 5203 var lineBits = temp.lineBits;
michael@0 5204 var bits = temp.bits;
michael@0 5205 $160.push($161);
michael@0 5206 } while (!eos);
michael@0 5207 }
michael@0 5208 function shapeRecord($bytes, $stream, $, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits) {
michael@0 5209 var type = $.type = readUb($bytes, $stream, 1);
michael@0 5210 var flags = readUb($bytes, $stream, 5);
michael@0 5211 var eos = $.eos = !(type || flags);
michael@0 5212 if (type) {
michael@0 5213 var temp = shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits);
michael@0 5214 var bits = temp.bits;
michael@0 5215 } else {
michael@0 5216 var temp = shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits);
michael@0 5217 var fillBits = temp.fillBits;
michael@0 5218 var lineBits = temp.lineBits;
michael@0 5219 var bits = temp.bits;
michael@0 5220 }
michael@0 5221 return {
michael@0 5222 type: type,
michael@0 5223 flags: flags,
michael@0 5224 eos: eos,
michael@0 5225 fillBits: fillBits,
michael@0 5226 lineBits: lineBits,
michael@0 5227 bits: bits
michael@0 5228 };
michael@0 5229 }
michael@0 5230 function shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits) {
michael@0 5231 var isStraight = 0, tmp = 0, bits = 0, isGeneral = 0, isVertical = 0;
michael@0 5232 isStraight = $.isStraight = flags >> 4;
michael@0 5233 tmp = flags & 15;
michael@0 5234 bits = tmp + 2;
michael@0 5235 if (isStraight) {
michael@0 5236 isGeneral = $.isGeneral = readUb($bytes, $stream, 1);
michael@0 5237 if (isGeneral) {
michael@0 5238 $.deltaX = readSb($bytes, $stream, bits);
michael@0 5239 $.deltaY = readSb($bytes, $stream, bits);
michael@0 5240 } else {
michael@0 5241 isVertical = $.isVertical = readUb($bytes, $stream, 1);
michael@0 5242 if (isVertical) {
michael@0 5243 $.deltaY = readSb($bytes, $stream, bits);
michael@0 5244 } else {
michael@0 5245 $.deltaX = readSb($bytes, $stream, bits);
michael@0 5246 }
michael@0 5247 }
michael@0 5248 } else {
michael@0 5249 $.controlDeltaX = readSb($bytes, $stream, bits);
michael@0 5250 $.controlDeltaY = readSb($bytes, $stream, bits);
michael@0 5251 $.anchorDeltaX = readSb($bytes, $stream, bits);
michael@0 5252 $.anchorDeltaY = readSb($bytes, $stream, bits);
michael@0 5253 }
michael@0 5254 return {
michael@0 5255 bits: bits
michael@0 5256 };
michael@0 5257 }
michael@0 5258 function shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits) {
michael@0 5259 var hasNewStyles = 0, hasLineStyle = 0, hasFillStyle1 = 0;
michael@0 5260 var hasFillStyle0 = 0, move = 0;
michael@0 5261 if (tagCode > 2) {
michael@0 5262 hasNewStyles = $.hasNewStyles = flags >> 4;
michael@0 5263 } else {
michael@0 5264 hasNewStyles = $.hasNewStyles = 0;
michael@0 5265 }
michael@0 5266 hasLineStyle = $.hasLineStyle = flags >> 3 & 1;
michael@0 5267 hasFillStyle1 = $.hasFillStyle1 = flags >> 2 & 1;
michael@0 5268 hasFillStyle0 = $.hasFillStyle0 = flags >> 1 & 1;
michael@0 5269 move = $.move = flags & 1;
michael@0 5270 if (move) {
michael@0 5271 bits = readUb($bytes, $stream, 5);
michael@0 5272 $.moveX = readSb($bytes, $stream, bits);
michael@0 5273 $.moveY = readSb($bytes, $stream, bits);
michael@0 5274 }
michael@0 5275 if (hasFillStyle0) {
michael@0 5276 $.fillStyle0 = readUb($bytes, $stream, fillBits);
michael@0 5277 }
michael@0 5278 if (hasFillStyle1) {
michael@0 5279 $.fillStyle1 = readUb($bytes, $stream, fillBits);
michael@0 5280 }
michael@0 5281 if (hasLineStyle) {
michael@0 5282 $.lineStyle = readUb($bytes, $stream, lineBits);
michael@0 5283 }
michael@0 5284 if (hasNewStyles) {
michael@0 5285 var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 5286 var lineBits = temp.lineBits;
michael@0 5287 var fillBits = temp.fillBits;
michael@0 5288 }
michael@0 5289 return {
michael@0 5290 lineBits: lineBits,
michael@0 5291 fillBits: fillBits,
michael@0 5292 bits: bits
michael@0 5293 };
michael@0 5294 }
michael@0 5295 function styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
michael@0 5296 fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph);
michael@0 5297 lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 5298 var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
michael@0 5299 var fillBits = temp.fillBits;
michael@0 5300 var lineBits = temp.lineBits;
michael@0 5301 return {
michael@0 5302 fillBits: fillBits,
michael@0 5303 lineBits: lineBits
michael@0 5304 };
michael@0 5305 }
michael@0 5306 function fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph) {
michael@0 5307 var count;
michael@0 5308 var tmp = readUi8($bytes, $stream);
michael@0 5309 if (tagCode > 2 && tmp === 255) {
michael@0 5310 count = readUi16($bytes, $stream);
michael@0 5311 } else {
michael@0 5312 count = tmp;
michael@0 5313 }
michael@0 5314 var $4 = $.fillStyles = [];
michael@0 5315 var $5 = count;
michael@0 5316 while ($5--) {
michael@0 5317 var $6 = {};
michael@0 5318 fillStyle($bytes, $stream, $6, swfVersion, tagCode, isMorph);
michael@0 5319 $4.push($6);
michael@0 5320 }
michael@0 5321 }
michael@0 5322 function lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
michael@0 5323 var count;
michael@0 5324 var tmp = readUi8($bytes, $stream);
michael@0 5325 if (tagCode > 2 && tmp === 255) {
michael@0 5326 count = readUi16($bytes, $stream);
michael@0 5327 } else {
michael@0 5328 count = tmp;
michael@0 5329 }
michael@0 5330 var $138 = $.lineStyles = [];
michael@0 5331 var $139 = count;
michael@0 5332 while ($139--) {
michael@0 5333 var $140 = {};
michael@0 5334 lineStyle($bytes, $stream, $140, swfVersion, tagCode, isMorph, hasStrokes);
michael@0 5335 $138.push($140);
michael@0 5336 }
michael@0 5337 }
michael@0 5338 function styleBits($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5339 align($bytes, $stream);
michael@0 5340 var fillBits = readUb($bytes, $stream, 4);
michael@0 5341 var lineBits = readUb($bytes, $stream, 4);
michael@0 5342 return {
michael@0 5343 fillBits: fillBits,
michael@0 5344 lineBits: lineBits
michael@0 5345 };
michael@0 5346 }
michael@0 5347 function fillStyle($bytes, $stream, $, swfVersion, tagCode, isMorph) {
michael@0 5348 var type = $.type = readUi8($bytes, $stream);
michael@0 5349 switch (type) {
michael@0 5350 case 0:
michael@0 5351 fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph);
michael@0 5352 break;
michael@0 5353 case 16:
michael@0 5354 case 18:
michael@0 5355 case 19:
michael@0 5356 fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
michael@0 5357 break;
michael@0 5358 case 64:
michael@0 5359 case 65:
michael@0 5360 case 66:
michael@0 5361 case 67:
michael@0 5362 fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
michael@0 5363 break;
michael@0 5364 default:
michael@0 5365 }
michael@0 5366 }
michael@0 5367 function lineStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
michael@0 5368 $.width = readUi16($bytes, $stream);
michael@0 5369 if (isMorph) {
michael@0 5370 $.widthMorph = readUi16($bytes, $stream);
michael@0 5371 }
michael@0 5372 if (hasStrokes) {
michael@0 5373 align($bytes, $stream);
michael@0 5374 $.startCapStyle = readUb($bytes, $stream, 2);
michael@0 5375 var joinStyle = $.joinStyle = readUb($bytes, $stream, 2);
michael@0 5376 var hasFill = $.hasFill = readUb($bytes, $stream, 1);
michael@0 5377 $.noHscale = readUb($bytes, $stream, 1);
michael@0 5378 $.noVscale = readUb($bytes, $stream, 1);
michael@0 5379 $.pixelHinting = readUb($bytes, $stream, 1);
michael@0 5380 var reserved = readUb($bytes, $stream, 5);
michael@0 5381 $.noClose = readUb($bytes, $stream, 1);
michael@0 5382 $.endCapStyle = readUb($bytes, $stream, 2);
michael@0 5383 if (joinStyle === 2) {
michael@0 5384 $.miterLimitFactor = readFixed8($bytes, $stream);
michael@0 5385 }
michael@0 5386 if (hasFill) {
michael@0 5387 var $141 = $.fillStyle = {};
michael@0 5388 fillStyle($bytes, $stream, $141, swfVersion, tagCode, isMorph);
michael@0 5389 } else {
michael@0 5390 var $155 = $.color = {};
michael@0 5391 rgba($bytes, $stream, $155, swfVersion, tagCode);
michael@0 5392 if (isMorph) {
michael@0 5393 var $156 = $.colorMorph = {};
michael@0 5394 rgba($bytes, $stream, $156, swfVersion, tagCode);
michael@0 5395 }
michael@0 5396 }
michael@0 5397 } else {
michael@0 5398 if (tagCode > 22) {
michael@0 5399 var $157 = $.color = {};
michael@0 5400 rgba($bytes, $stream, $157, swfVersion, tagCode);
michael@0 5401 } else {
michael@0 5402 var $158 = $.color = {};
michael@0 5403 rgb($bytes, $stream, $158, swfVersion, tagCode);
michael@0 5404 }
michael@0 5405 if (isMorph) {
michael@0 5406 var $159 = $.colorMorph = {};
michael@0 5407 rgba($bytes, $stream, $159, swfVersion, tagCode);
michael@0 5408 }
michael@0 5409 }
michael@0 5410 }
michael@0 5411 function fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
michael@0 5412 $.bitmapId = readUi16($bytes, $stream);
michael@0 5413 var $18 = $.matrix = {};
michael@0 5414 matrix($bytes, $stream, $18, swfVersion, tagCode);
michael@0 5415 if (isMorph) {
michael@0 5416 var $19 = $.matrixMorph = {};
michael@0 5417 matrix($bytes, $stream, $19, swfVersion, tagCode);
michael@0 5418 }
michael@0 5419 $.condition = type === 64 || type === 67;
michael@0 5420 }
michael@0 5421 function filterGlow($bytes, $stream, $, swfVersion, tagCode, type) {
michael@0 5422 var count;
michael@0 5423 if (type === 4 || type === 7) {
michael@0 5424 count = readUi8($bytes, $stream);
michael@0 5425 } else {
michael@0 5426 count = 1;
michael@0 5427 }
michael@0 5428 var $5 = $.colors = [];
michael@0 5429 var $6 = count;
michael@0 5430 while ($6--) {
michael@0 5431 var $7 = {};
michael@0 5432 rgba($bytes, $stream, $7, swfVersion, tagCode);
michael@0 5433 $5.push($7);
michael@0 5434 }
michael@0 5435 if (type === 3) {
michael@0 5436 var $8 = $.higlightColor = {};
michael@0 5437 rgba($bytes, $stream, $8, swfVersion, tagCode);
michael@0 5438 }
michael@0 5439 if (type === 4 || type === 7) {
michael@0 5440 var $9 = $.ratios = [];
michael@0 5441 var $10 = count;
michael@0 5442 while ($10--) {
michael@0 5443 $9.push(readUi8($bytes, $stream));
michael@0 5444 }
michael@0 5445 }
michael@0 5446 $.blurX = readFixed($bytes, $stream);
michael@0 5447 $.blurY = readFixed($bytes, $stream);
michael@0 5448 if (type !== 2) {
michael@0 5449 $.angle = readFixed($bytes, $stream);
michael@0 5450 $.distance = readFixed($bytes, $stream);
michael@0 5451 }
michael@0 5452 $.strength = readFixed8($bytes, $stream);
michael@0 5453 $.innerShadow = readUb($bytes, $stream, 1);
michael@0 5454 $.knockout = readUb($bytes, $stream, 1);
michael@0 5455 $.compositeSource = readUb($bytes, $stream, 1);
michael@0 5456 if (type === 3) {
michael@0 5457 $.onTop = readUb($bytes, $stream, 1);
michael@0 5458 } else {
michael@0 5459 var reserved = readUb($bytes, $stream, 1);
michael@0 5460 }
michael@0 5461 if (type === 4 || type === 7) {
michael@0 5462 $.passes = readUb($bytes, $stream, 4);
michael@0 5463 } else {
michael@0 5464 var reserved = readUb($bytes, $stream, 4);
michael@0 5465 }
michael@0 5466 }
michael@0 5467 function filterBlur($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5468 $.blurX = readFixed($bytes, $stream);
michael@0 5469 $.blurY = readFixed($bytes, $stream);
michael@0 5470 $.passes = readUb($bytes, $stream, 5);
michael@0 5471 var reserved = readUb($bytes, $stream, 3);
michael@0 5472 }
michael@0 5473 function filterConvolution($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5474 var columns = $.columns = readUi8($bytes, $stream);
michael@0 5475 var rows = $.rows = readUi8($bytes, $stream);
michael@0 5476 $.divisor = readFloat($bytes, $stream);
michael@0 5477 $.bias = readFloat($bytes, $stream);
michael@0 5478 var $17 = $.weights = [];
michael@0 5479 var $18 = columns * rows;
michael@0 5480 while ($18--) {
michael@0 5481 $17.push(readFloat($bytes, $stream));
michael@0 5482 }
michael@0 5483 var $19 = $.defaultColor = {};
michael@0 5484 rgba($bytes, $stream, $19, swfVersion, tagCode);
michael@0 5485 var reserved = readUb($bytes, $stream, 6);
michael@0 5486 $.clamp = readUb($bytes, $stream, 1);
michael@0 5487 $.preserveAlpha = readUb($bytes, $stream, 1);
michael@0 5488 }
michael@0 5489 function filterColorMatrix($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5490 var $20 = $.matrix = [];
michael@0 5491 var $21 = 20;
michael@0 5492 while ($21--) {
michael@0 5493 $20.push(readFloat($bytes, $stream));
michael@0 5494 }
michael@0 5495 }
michael@0 5496 function anyFilter($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5497 var type = $.type = readUi8($bytes, $stream);
michael@0 5498 switch (type) {
michael@0 5499 case 0:
michael@0 5500 case 2:
michael@0 5501 case 3:
michael@0 5502 case 4:
michael@0 5503 case 7:
michael@0 5504 filterGlow($bytes, $stream, $, swfVersion, tagCode, type);
michael@0 5505 break;
michael@0 5506 case 1:
michael@0 5507 filterBlur($bytes, $stream, $, swfVersion, tagCode);
michael@0 5508 break;
michael@0 5509 case 5:
michael@0 5510 filterConvolution($bytes, $stream, $, swfVersion, tagCode);
michael@0 5511 break;
michael@0 5512 case 6:
michael@0 5513 filterColorMatrix($bytes, $stream, $, swfVersion, tagCode);
michael@0 5514 break;
michael@0 5515 default:
michael@0 5516 }
michael@0 5517 }
michael@0 5518 function events($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5519 var flags, keyPress;
michael@0 5520 if (swfVersion >= 6) {
michael@0 5521 flags = readUi32($bytes, $stream);
michael@0 5522 } else {
michael@0 5523 flags = readUi16($bytes, $stream);
michael@0 5524 }
michael@0 5525 var eoe = $.eoe = !flags;
michael@0 5526 $.onKeyUp = flags >> 7 & 1;
michael@0 5527 $.onKeyDown = flags >> 6 & 1;
michael@0 5528 $.onMouseUp = flags >> 5 & 1;
michael@0 5529 $.onMouseDown = flags >> 4 & 1;
michael@0 5530 $.onMouseMove = flags >> 3 & 1;
michael@0 5531 $.onUnload = flags >> 2 & 1;
michael@0 5532 $.onEnterFrame = flags >> 1 & 1;
michael@0 5533 $.onLoad = flags & 1;
michael@0 5534 if (swfVersion >= 6) {
michael@0 5535 $.onDragOver = flags >> 15 & 1;
michael@0 5536 $.onRollOut = flags >> 14 & 1;
michael@0 5537 $.onRollOver = flags >> 13 & 1;
michael@0 5538 $.onReleaseOutside = flags >> 12 & 1;
michael@0 5539 $.onRelease = flags >> 11 & 1;
michael@0 5540 $.onPress = flags >> 10 & 1;
michael@0 5541 $.onInitialize = flags >> 9 & 1;
michael@0 5542 $.onData = flags >> 8 & 1;
michael@0 5543 if (swfVersion >= 7) {
michael@0 5544 $.onConstruct = flags >> 18 & 1;
michael@0 5545 } else {
michael@0 5546 $.onConstruct = 0;
michael@0 5547 }
michael@0 5548 keyPress = $.keyPress = flags >> 17 & 1;
michael@0 5549 $.onDragOut = flags >> 16 & 1;
michael@0 5550 }
michael@0 5551 if (!eoe) {
michael@0 5552 var length = $.length = readUi32($bytes, $stream);
michael@0 5553 if (keyPress) {
michael@0 5554 $.keyCode = readUi8($bytes, $stream);
michael@0 5555 }
michael@0 5556 $.actionsData = readBinary($bytes, $stream, length - (keyPress ? 1 : 0));
michael@0 5557 }
michael@0 5558 return {
michael@0 5559 eoe: eoe
michael@0 5560 };
michael@0 5561 }
michael@0 5562 function kerning($bytes, $stream, $, swfVersion, tagCode, wide) {
michael@0 5563 if (wide) {
michael@0 5564 $.code1 = readUi16($bytes, $stream);
michael@0 5565 $.code2 = readUi16($bytes, $stream);
michael@0 5566 } else {
michael@0 5567 $.code1 = readUi8($bytes, $stream);
michael@0 5568 $.code2 = readUi8($bytes, $stream);
michael@0 5569 }
michael@0 5570 $.adjustment = readUi16($bytes, $stream);
michael@0 5571 }
michael@0 5572 function textEntry($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) {
michael@0 5573 $.glyphIndex = readUb($bytes, $stream, glyphBits);
michael@0 5574 $.advance = readSb($bytes, $stream, advanceBits);
michael@0 5575 }
michael@0 5576 function textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags) {
michael@0 5577 var hasFont = $.hasFont = flags >> 3 & 1;
michael@0 5578 var hasColor = $.hasColor = flags >> 2 & 1;
michael@0 5579 var hasMoveY = $.hasMoveY = flags >> 1 & 1;
michael@0 5580 var hasMoveX = $.hasMoveX = flags & 1;
michael@0 5581 if (hasFont) {
michael@0 5582 $.fontId = readUi16($bytes, $stream);
michael@0 5583 }
michael@0 5584 if (hasColor) {
michael@0 5585 if (tagCode === 33) {
michael@0 5586 var $4 = $.color = {};
michael@0 5587 rgba($bytes, $stream, $4, swfVersion, tagCode);
michael@0 5588 } else {
michael@0 5589 var $5 = $.color = {};
michael@0 5590 rgb($bytes, $stream, $5, swfVersion, tagCode);
michael@0 5591 }
michael@0 5592 }
michael@0 5593 if (hasMoveX) {
michael@0 5594 $.moveX = readSi16($bytes, $stream);
michael@0 5595 }
michael@0 5596 if (hasMoveY) {
michael@0 5597 $.moveY = readSi16($bytes, $stream);
michael@0 5598 }
michael@0 5599 if (hasFont) {
michael@0 5600 $.fontHeight = readUi16($bytes, $stream);
michael@0 5601 }
michael@0 5602 }
michael@0 5603 function textRecord($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) {
michael@0 5604 var glyphCount;
michael@0 5605 align($bytes, $stream);
michael@0 5606 var flags = readUb($bytes, $stream, 8);
michael@0 5607 var eot = $.eot = !flags;
michael@0 5608 textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags);
michael@0 5609 if (!eot) {
michael@0 5610 var tmp = readUi8($bytes, $stream);
michael@0 5611 if (swfVersion > 6) {
michael@0 5612 glyphCount = $.glyphCount = tmp;
michael@0 5613 } else {
michael@0 5614 glyphCount = $.glyphCount = tmp & 127;
michael@0 5615 }
michael@0 5616 var $6 = $.entries = [];
michael@0 5617 var $7 = glyphCount;
michael@0 5618 while ($7--) {
michael@0 5619 var $8 = {};
michael@0 5620 textEntry($bytes, $stream, $8, swfVersion, tagCode, glyphBits, advanceBits);
michael@0 5621 $6.push($8);
michael@0 5622 }
michael@0 5623 }
michael@0 5624 return {
michael@0 5625 eot: eot
michael@0 5626 };
michael@0 5627 }
michael@0 5628 function soundEnvelope($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5629 $.pos44 = readUi32($bytes, $stream);
michael@0 5630 $.volumeLeft = readUi16($bytes, $stream);
michael@0 5631 $.volumeRight = readUi16($bytes, $stream);
michael@0 5632 }
michael@0 5633 function soundInfo($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5634 var reserved = readUb($bytes, $stream, 2);
michael@0 5635 $.stop = readUb($bytes, $stream, 1);
michael@0 5636 $.noMultiple = readUb($bytes, $stream, 1);
michael@0 5637 var hasEnvelope = $.hasEnvelope = readUb($bytes, $stream, 1);
michael@0 5638 var hasLoops = $.hasLoops = readUb($bytes, $stream, 1);
michael@0 5639 var hasOutPoint = $.hasOutPoint = readUb($bytes, $stream, 1);
michael@0 5640 var hasInPoint = $.hasInPoint = readUb($bytes, $stream, 1);
michael@0 5641 if (hasInPoint) {
michael@0 5642 $.inPoint = readUi32($bytes, $stream);
michael@0 5643 }
michael@0 5644 if (hasOutPoint) {
michael@0 5645 $.outPoint = readUi32($bytes, $stream);
michael@0 5646 }
michael@0 5647 if (hasLoops) {
michael@0 5648 $.loopCount = readUi16($bytes, $stream);
michael@0 5649 }
michael@0 5650 if (hasEnvelope) {
michael@0 5651 var envelopeCount = $.envelopeCount = readUi8($bytes, $stream);
michael@0 5652 var $1 = $.envelopes = [];
michael@0 5653 var $2 = envelopeCount;
michael@0 5654 while ($2--) {
michael@0 5655 var $3 = {};
michael@0 5656 soundEnvelope($bytes, $stream, $3, swfVersion, tagCode);
michael@0 5657 $1.push($3);
michael@0 5658 }
michael@0 5659 }
michael@0 5660 }
michael@0 5661 function button($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5662 var hasFilters, blend;
michael@0 5663 var flags = readUi8($bytes, $stream);
michael@0 5664 var eob = $.eob = !flags;
michael@0 5665 if (swfVersion >= 8) {
michael@0 5666 blend = $.blend = flags >> 5 & 1;
michael@0 5667 hasFilters = $.hasFilters = flags >> 4 & 1;
michael@0 5668 } else {
michael@0 5669 blend = $.blend = 0;
michael@0 5670 hasFilters = $.hasFilters = 0;
michael@0 5671 }
michael@0 5672 $.stateHitTest = flags >> 3 & 1;
michael@0 5673 $.stateDown = flags >> 2 & 1;
michael@0 5674 $.stateOver = flags >> 1 & 1;
michael@0 5675 $.stateUp = flags & 1;
michael@0 5676 if (!eob) {
michael@0 5677 $.symbolId = readUi16($bytes, $stream);
michael@0 5678 $.depth = readUi16($bytes, $stream);
michael@0 5679 var $2 = $.matrix = {};
michael@0 5680 matrix($bytes, $stream, $2, swfVersion, tagCode);
michael@0 5681 if (tagCode === 34) {
michael@0 5682 var $3 = $.cxform = {};
michael@0 5683 cxform($bytes, $stream, $3, swfVersion, tagCode);
michael@0 5684 }
michael@0 5685 if (hasFilters) {
michael@0 5686 $.filterCount = readUi8($bytes, $stream);
michael@0 5687 var $4 = $.filters = {};
michael@0 5688 anyFilter($bytes, $stream, $4, swfVersion, tagCode);
michael@0 5689 }
michael@0 5690 if (blend) {
michael@0 5691 $.blendMode = readUi8($bytes, $stream);
michael@0 5692 }
michael@0 5693 }
michael@0 5694 return {
michael@0 5695 eob: eob
michael@0 5696 };
michael@0 5697 }
michael@0 5698 function buttonCondAction($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5699 var buttonCondSize = readUi16($bytes, $stream);
michael@0 5700 var buttonConditions = readUi16($bytes, $stream);
michael@0 5701 $.idleToOverDown = buttonConditions >> 7 & 1;
michael@0 5702 $.outDownToIdle = buttonConditions >> 6 & 1;
michael@0 5703 $.outDownToOverDown = buttonConditions >> 5 & 1;
michael@0 5704 $.overDownToOutDown = buttonConditions >> 4 & 1;
michael@0 5705 $.overDownToOverUp = buttonConditions >> 3 & 1;
michael@0 5706 $.overUpToOverDown = buttonConditions >> 2 & 1;
michael@0 5707 $.overUpToIdle = buttonConditions >> 1 & 1;
michael@0 5708 $.idleToOverUp = buttonConditions & 1;
michael@0 5709 $.mouseEventFlags = buttonConditions & 511;
michael@0 5710 $.keyPress = buttonConditions >> 9 & 127;
michael@0 5711 $.overDownToIdle = buttonConditions >> 8 & 1;
michael@0 5712 if (!buttonCondSize) {
michael@0 5713 $.actionsData = readBinary($bytes, $stream, 0);
michael@0 5714 } else {
michael@0 5715 $.actionsData = readBinary($bytes, $stream, buttonCondSize - 4);
michael@0 5716 }
michael@0 5717 }
michael@0 5718 function shape($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5719 var eos;
michael@0 5720 var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
michael@0 5721 var fillBits = temp.fillBits;
michael@0 5722 var lineBits = temp.lineBits;
michael@0 5723 var $4 = $.records = [];
michael@0 5724 do {
michael@0 5725 var $5 = {};
michael@0 5726 var isMorph = false;
michael@0 5727 var hasStrokes = false;
michael@0 5728 var temp = shapeRecord($bytes, $stream, $5, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
michael@0 5729 eos = temp.eos;
michael@0 5730 var fillBits = temp.fillBits;
michael@0 5731 var lineBits = temp.lineBits;
michael@0 5732 var bits = bits;
michael@0 5733 $4.push($5);
michael@0 5734 } while (!eos);
michael@0 5735 }
michael@0 5736 return {
michael@0 5737 0: undefined,
michael@0 5738 1: undefined,
michael@0 5739 2: defineShape,
michael@0 5740 4: placeObject,
michael@0 5741 5: removeObject,
michael@0 5742 6: defineImage,
michael@0 5743 7: defineButton,
michael@0 5744 8: defineJPEGTables,
michael@0 5745 9: setBackgroundColor,
michael@0 5746 10: defineFont,
michael@0 5747 11: defineLabel,
michael@0 5748 12: doAction,
michael@0 5749 13: undefined,
michael@0 5750 14: defineSound,
michael@0 5751 15: startSound,
michael@0 5752 17: undefined,
michael@0 5753 18: soundStreamHead,
michael@0 5754 19: soundStreamBlock,
michael@0 5755 20: defineBitmap,
michael@0 5756 21: defineImage,
michael@0 5757 22: defineShape,
michael@0 5758 23: undefined,
michael@0 5759 24: undefined,
michael@0 5760 26: placeObject,
michael@0 5761 28: removeObject,
michael@0 5762 32: defineShape,
michael@0 5763 33: defineLabel,
michael@0 5764 34: defineButton,
michael@0 5765 35: defineImage,
michael@0 5766 36: defineBitmap,
michael@0 5767 37: defineText,
michael@0 5768 39: undefined,
michael@0 5769 43: frameLabel,
michael@0 5770 45: soundStreamHead,
michael@0 5771 46: defineShape,
michael@0 5772 48: defineFont2,
michael@0 5773 56: exportAssets,
michael@0 5774 57: undefined,
michael@0 5775 58: undefined,
michael@0 5776 59: doAction,
michael@0 5777 60: undefined,
michael@0 5778 61: undefined,
michael@0 5779 62: undefined,
michael@0 5780 64: undefined,
michael@0 5781 65: undefined,
michael@0 5782 66: undefined,
michael@0 5783 69: fileAttributes,
michael@0 5784 70: placeObject,
michael@0 5785 71: undefined,
michael@0 5786 72: doABC,
michael@0 5787 73: undefined,
michael@0 5788 74: undefined,
michael@0 5789 75: defineFont2,
michael@0 5790 76: symbolClass,
michael@0 5791 77: undefined,
michael@0 5792 78: defineScalingGrid,
michael@0 5793 82: doABC,
michael@0 5794 83: defineShape,
michael@0 5795 84: defineShape,
michael@0 5796 86: defineScene,
michael@0 5797 87: defineBinaryData,
michael@0 5798 88: undefined,
michael@0 5799 89: startSound,
michael@0 5800 90: defineImage,
michael@0 5801 91: undefined
michael@0 5802 };
michael@0 5803 }(this);
michael@0 5804 var readHeader = function readHeader($bytes, $stream, $, swfVersion, tagCode) {
michael@0 5805 $ || ($ = {});
michael@0 5806 var $0 = $.bbox = {};
michael@0 5807 align($bytes, $stream);
michael@0 5808 var bits = readUb($bytes, $stream, 5);
michael@0 5809 var xMin = readSb($bytes, $stream, bits);
michael@0 5810 var xMax = readSb($bytes, $stream, bits);
michael@0 5811 var yMin = readSb($bytes, $stream, bits);
michael@0 5812 var yMax = readSb($bytes, $stream, bits);
michael@0 5813 $0.xMin = xMin;
michael@0 5814 $0.xMax = xMax;
michael@0 5815 $0.yMin = yMin;
michael@0 5816 $0.yMax = yMax;
michael@0 5817 align($bytes, $stream);
michael@0 5818 var frameRateFraction = readUi8($bytes, $stream);
michael@0 5819 $.frameRate = readUi8($bytes, $stream) + frameRateFraction / 256;
michael@0 5820 $.frameCount = readUi16($bytes, $stream);
michael@0 5821 return $;
michael@0 5822 };
michael@0 5823 (function (global) {
michael@0 5824 global['tagHandler'] = tagHandler;
michael@0 5825 global['readHeader'] = readHeader;
michael@0 5826 }(this));
michael@0 5827 function readTags(context, stream, swfVersion, final, onprogress, onexception) {
michael@0 5828 var tags = context.tags;
michael@0 5829 var bytes = stream.bytes;
michael@0 5830 var lastSuccessfulPosition;
michael@0 5831 var tag = null;
michael@0 5832 if (context._readTag) {
michael@0 5833 tag = context._readTag;
michael@0 5834 context._readTag = null;
michael@0 5835 }
michael@0 5836 try {
michael@0 5837 while (stream.pos < stream.end) {
michael@0 5838 lastSuccessfulPosition = stream.pos;
michael@0 5839 stream.ensure(2);
michael@0 5840 var tagCodeAndLength = readUi16(bytes, stream);
michael@0 5841 if (!tagCodeAndLength) {
michael@0 5842 final = true;
michael@0 5843 break;
michael@0 5844 }
michael@0 5845 var tagCode = tagCodeAndLength >> 6;
michael@0 5846 var length = tagCodeAndLength & 63;
michael@0 5847 if (length === 63) {
michael@0 5848 stream.ensure(4);
michael@0 5849 length = readUi32(bytes, stream);
michael@0 5850 }
michael@0 5851 if (tag) {
michael@0 5852 if (tagCode === 1 && tag.code === 1) {
michael@0 5853 tag.repeat++;
michael@0 5854 stream.pos += length;
michael@0 5855 continue;
michael@0 5856 }
michael@0 5857 tags.push(tag);
michael@0 5858 if (onprogress && tag.id !== undefined) {
michael@0 5859 onprogress(context);
michael@0 5860 }
michael@0 5861 tag = null;
michael@0 5862 }
michael@0 5863 stream.ensure(length);
michael@0 5864 var substream = stream.substream(stream.pos, stream.pos += length);
michael@0 5865 var subbytes = substream.bytes;
michael@0 5866 var nextTag = {
michael@0 5867 code: tagCode
michael@0 5868 };
michael@0 5869 if (tagCode === 39) {
michael@0 5870 nextTag.type = 'sprite';
michael@0 5871 nextTag.id = readUi16(subbytes, substream);
michael@0 5872 nextTag.frameCount = readUi16(subbytes, substream);
michael@0 5873 nextTag.tags = [];
michael@0 5874 readTags(nextTag, substream, swfVersion, true);
michael@0 5875 } else if (tagCode === 1) {
michael@0 5876 nextTag.repeat = 1;
michael@0 5877 } else {
michael@0 5878 var handler = tagHandler[tagCode];
michael@0 5879 if (handler) {
michael@0 5880 handler(subbytes, substream, nextTag, swfVersion, tagCode);
michael@0 5881 }
michael@0 5882 }
michael@0 5883 tag = nextTag;
michael@0 5884 }
michael@0 5885 if (tag && final) {
michael@0 5886 tag.finalTag = true;
michael@0 5887 tags.push(tag);
michael@0 5888 if (onprogress) {
michael@0 5889 onprogress(context);
michael@0 5890 }
michael@0 5891 } else {
michael@0 5892 context._readTag = tag;
michael@0 5893 }
michael@0 5894 } catch (e) {
michael@0 5895 if (e !== StreamNoDataError) {
michael@0 5896 onexception && onexception(e);
michael@0 5897 throw e;
michael@0 5898 }
michael@0 5899 stream.pos = lastSuccessfulPosition;
michael@0 5900 context._readTag = tag;
michael@0 5901 }
michael@0 5902 }
michael@0 5903 function HeadTailBuffer(defaultSize) {
michael@0 5904 this.bufferSize = defaultSize || 16;
michael@0 5905 this.buffer = new Uint8Array(this.bufferSize);
michael@0 5906 this.pos = 0;
michael@0 5907 }
michael@0 5908 HeadTailBuffer.prototype = {
michael@0 5909 push: function (data, need) {
michael@0 5910 var bufferLengthNeed = this.pos + data.length;
michael@0 5911 if (this.bufferSize < bufferLengthNeed) {
michael@0 5912 var newBufferSize = this.bufferSize;
michael@0 5913 while (newBufferSize < bufferLengthNeed) {
michael@0 5914 newBufferSize <<= 1;
michael@0 5915 }
michael@0 5916 var newBuffer = new Uint8Array(newBufferSize);
michael@0 5917 if (this.bufferSize > 0) {
michael@0 5918 newBuffer.set(this.buffer);
michael@0 5919 }
michael@0 5920 this.buffer = newBuffer;
michael@0 5921 this.bufferSize = newBufferSize;
michael@0 5922 }
michael@0 5923 this.buffer.set(data, this.pos);
michael@0 5924 this.pos += data.length;
michael@0 5925 if (need)
michael@0 5926 return this.pos >= need;
michael@0 5927 },
michael@0 5928 getHead: function (size) {
michael@0 5929 return this.buffer.subarray(0, size);
michael@0 5930 },
michael@0 5931 getTail: function (offset) {
michael@0 5932 return this.buffer.subarray(offset, this.pos);
michael@0 5933 },
michael@0 5934 removeHead: function (size) {
michael@0 5935 var tail = this.getTail(size);
michael@0 5936 this.buffer = new Uint8Array(this.bufferSize);
michael@0 5937 this.buffer.set(tail);
michael@0 5938 this.pos = tail.length;
michael@0 5939 },
michael@0 5940 get arrayBuffer() {
michael@0 5941 return this.buffer.buffer;
michael@0 5942 },
michael@0 5943 get length() {
michael@0 5944 return this.pos;
michael@0 5945 },
michael@0 5946 createStream: function () {
michael@0 5947 return new Stream(this.arrayBuffer, 0, this.length);
michael@0 5948 }
michael@0 5949 };
michael@0 5950 function CompressedPipe(target, length) {
michael@0 5951 this.target = target;
michael@0 5952 this.length = length;
michael@0 5953 this.initialize = true;
michael@0 5954 this.buffer = new HeadTailBuffer(8096);
michael@0 5955 this.state = {
michael@0 5956 bitBuffer: 0,
michael@0 5957 bitLength: 0,
michael@0 5958 compression: {
michael@0 5959 header: null,
michael@0 5960 distanceTable: null,
michael@0 5961 literalTable: null,
michael@0 5962 sym: null,
michael@0 5963 len: null,
michael@0 5964 sym2: null
michael@0 5965 }
michael@0 5966 };
michael@0 5967 this.output = {
michael@0 5968 data: new Uint8Array(length),
michael@0 5969 available: 0,
michael@0 5970 completed: false
michael@0 5971 };
michael@0 5972 }
michael@0 5973 CompressedPipe.prototype = {
michael@0 5974 push: function (data, progressInfo) {
michael@0 5975 var buffer = this.buffer;
michael@0 5976 if (this.initialize) {
michael@0 5977 if (!buffer.push(data, 2))
michael@0 5978 return;
michael@0 5979 var headerBytes = buffer.getHead(2);
michael@0 5980 verifyDeflateHeader(headerBytes);
michael@0 5981 buffer.removeHead(2);
michael@0 5982 this.initialize = false;
michael@0 5983 } else {
michael@0 5984 buffer.push(data);
michael@0 5985 }
michael@0 5986 var stream = buffer.createStream();
michael@0 5987 stream.bitBuffer = this.state.bitBuffer;
michael@0 5988 stream.bitLength = this.state.bitLength;
michael@0 5989 var output = this.output;
michael@0 5990 var lastAvailable = output.available;
michael@0 5991 try {
michael@0 5992 do {
michael@0 5993 inflateBlock(stream, output, this.state.compression);
michael@0 5994 } while (stream.pos < buffer.length && !output.completed);
michael@0 5995 } catch (e) {
michael@0 5996 if (e !== InflateNoDataError)
michael@0 5997 throw e;
michael@0 5998 } finally {
michael@0 5999 this.state.bitBuffer = stream.bitBuffer;
michael@0 6000 this.state.bitLength = stream.bitLength;
michael@0 6001 }
michael@0 6002 buffer.removeHead(stream.pos);
michael@0 6003 this.target.push(output.data.subarray(lastAvailable, output.available), progressInfo);
michael@0 6004 }
michael@0 6005 };
michael@0 6006 function BodyParser(swfVersion, length, options) {
michael@0 6007 this.swf = {
michael@0 6008 swfVersion: swfVersion,
michael@0 6009 parseTime: 0
michael@0 6010 };
michael@0 6011 this.buffer = new HeadTailBuffer(32768);
michael@0 6012 this.initialize = true;
michael@0 6013 this.totalRead = 0;
michael@0 6014 this.length = length;
michael@0 6015 this.options = options;
michael@0 6016 }
michael@0 6017 BodyParser.prototype = {
michael@0 6018 push: function (data, progressInfo) {
michael@0 6019 if (data.length === 0)
michael@0 6020 return;
michael@0 6021 var swf = this.swf;
michael@0 6022 var swfVersion = swf.swfVersion;
michael@0 6023 var buffer = this.buffer;
michael@0 6024 var options = this.options;
michael@0 6025 var stream;
michael@0 6026 if (this.initialize) {
michael@0 6027 var PREFETCH_SIZE = 27;
michael@0 6028 if (!buffer.push(data, PREFETCH_SIZE))
michael@0 6029 return;
michael@0 6030 stream = buffer.createStream();
michael@0 6031 var bytes = stream.bytes;
michael@0 6032 readHeader(bytes, stream, swf);
michael@0 6033 var nextTagHeader = readUi16(bytes, stream);
michael@0 6034 var FILE_ATTRIBUTES_LENGTH = 4;
michael@0 6035 if (nextTagHeader == (SWF_TAG_CODE_FILE_ATTRIBUTES << 6 | FILE_ATTRIBUTES_LENGTH)) {
michael@0 6036 stream.ensure(FILE_ATTRIBUTES_LENGTH);
michael@0 6037 var substream = stream.substream(stream.pos, stream.pos += FILE_ATTRIBUTES_LENGTH);
michael@0 6038 var handler = tagHandler[SWF_TAG_CODE_FILE_ATTRIBUTES];
michael@0 6039 var fileAttributesTag = {
michael@0 6040 code: SWF_TAG_CODE_FILE_ATTRIBUTES
michael@0 6041 };
michael@0 6042 handler(substream.bytes, substream, fileAttributesTag, swfVersion, SWF_TAG_CODE_FILE_ATTRIBUTES);
michael@0 6043 swf.fileAttributes = fileAttributesTag;
michael@0 6044 } else {
michael@0 6045 stream.pos -= 2;
michael@0 6046 swf.fileAttributes = {};
michael@0 6047 }
michael@0 6048 if (options.onstart)
michael@0 6049 options.onstart(swf);
michael@0 6050 swf.tags = [];
michael@0 6051 this.initialize = false;
michael@0 6052 } else {
michael@0 6053 buffer.push(data);
michael@0 6054 stream = buffer.createStream();
michael@0 6055 }
michael@0 6056 var finalBlock = false;
michael@0 6057 if (progressInfo) {
michael@0 6058 swf.bytesLoaded = progressInfo.bytesLoaded;
michael@0 6059 swf.bytesTotal = progressInfo.bytesTotal;
michael@0 6060 finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal;
michael@0 6061 }
michael@0 6062 var readStartTime = performance.now();
michael@0 6063 readTags(swf, stream, swfVersion, finalBlock, options.onprogress, options.onexception);
michael@0 6064 swf.parseTime += performance.now() - readStartTime;
michael@0 6065 var read = stream.pos;
michael@0 6066 buffer.removeHead(read);
michael@0 6067 this.totalRead += read;
michael@0 6068 if (options.oncomplete && swf.tags[swf.tags.length - 1].finalTag) {
michael@0 6069 options.oncomplete(swf);
michael@0 6070 }
michael@0 6071 }
michael@0 6072 };
michael@0 6073 SWF.parseAsync = function swf_parseAsync(options) {
michael@0 6074 var buffer = new HeadTailBuffer();
michael@0 6075 var pipe = {
michael@0 6076 push: function (data, progressInfo) {
michael@0 6077 if (this.target !== undefined) {
michael@0 6078 return this.target.push(data, progressInfo);
michael@0 6079 }
michael@0 6080 if (!buffer.push(data, 8)) {
michael@0 6081 return null;
michael@0 6082 }
michael@0 6083 var bytes = buffer.getHead(8);
michael@0 6084 var magic1 = bytes[0];
michael@0 6085 var magic2 = bytes[1];
michael@0 6086 var magic3 = bytes[2];
michael@0 6087 if ((magic1 === 70 || magic1 === 67) && magic2 === 87 && magic3 === 83) {
michael@0 6088 var swfVersion = bytes[3];
michael@0 6089 var compressed = magic1 === 67;
michael@0 6090 parseSWF(compressed, swfVersion, progressInfo);
michael@0 6091 buffer = null;
michael@0 6092 return;
michael@0 6093 }
michael@0 6094 var isImage = false;
michael@0 6095 var imageType;
michael@0 6096 if (magic1 === 255 && magic2 === 216 && magic3 === 255) {
michael@0 6097 isImage = true;
michael@0 6098 imageType = 'image/jpeg';
michael@0 6099 } else if (magic1 === 137 && magic2 === 80 && magic3 === 78) {
michael@0 6100 isImage = true;
michael@0 6101 imageType = 'image/png';
michael@0 6102 }
michael@0 6103 if (isImage) {
michael@0 6104 parseImage(data, progressInfo.bytesTotal, imageType);
michael@0 6105 }
michael@0 6106 buffer = null;
michael@0 6107 },
michael@0 6108 close: function () {
michael@0 6109 if (buffer) {
michael@0 6110 var symbol = {
michael@0 6111 command: 'empty',
michael@0 6112 data: buffer.buffer.subarray(0, buffer.pos)
michael@0 6113 };
michael@0 6114 options.oncomplete && options.oncomplete(symbol);
michael@0 6115 }
michael@0 6116 if (this.target !== undefined && this.target.close) {
michael@0 6117 this.target.close();
michael@0 6118 }
michael@0 6119 }
michael@0 6120 };
michael@0 6121 function parseSWF(compressed, swfVersion, progressInfo) {
michael@0 6122 var stream = buffer.createStream();
michael@0 6123 stream.pos += 4;
michael@0 6124 var fileLength = readUi32(null, stream);
michael@0 6125 var bodyLength = fileLength - 8;
michael@0 6126 var target = new BodyParser(swfVersion, bodyLength, options);
michael@0 6127 if (compressed) {
michael@0 6128 target = new CompressedPipe(target, bodyLength);
michael@0 6129 }
michael@0 6130 target.push(buffer.getTail(8), progressInfo);
michael@0 6131 pipe['target'] = target;
michael@0 6132 }
michael@0 6133 function parseImage(data, bytesTotal, type) {
michael@0 6134 var buffer = new Uint8Array(bytesTotal);
michael@0 6135 buffer.set(data);
michael@0 6136 var bufferPos = data.length;
michael@0 6137 pipe['target'] = {
michael@0 6138 push: function (data) {
michael@0 6139 buffer.set(data, bufferPos);
michael@0 6140 bufferPos += data.length;
michael@0 6141 },
michael@0 6142 close: function () {
michael@0 6143 var props = {};
michael@0 6144 var chunks;
michael@0 6145 if (type == 'image/jpeg') {
michael@0 6146 chunks = parseJpegChunks(props, buffer);
michael@0 6147 } else {
michael@0 6148 chunks = [
michael@0 6149 buffer
michael@0 6150 ];
michael@0 6151 }
michael@0 6152 var symbol = {
michael@0 6153 type: 'image',
michael@0 6154 props: props,
michael@0 6155 data: new Blob(chunks, {
michael@0 6156 type: type
michael@0 6157 })
michael@0 6158 };
michael@0 6159 options.oncomplete && options.oncomplete(symbol);
michael@0 6160 }
michael@0 6161 };
michael@0 6162 }
michael@0 6163 return pipe;
michael@0 6164 };
michael@0 6165 SWF.parse = function (buffer, options) {
michael@0 6166 if (!options)
michael@0 6167 options = {};
michael@0 6168 var pipe = SWF.parseAsync(options);
michael@0 6169 var bytes = new Uint8Array(buffer);
michael@0 6170 var progressInfo = {
michael@0 6171 bytesLoaded: bytes.length,
michael@0 6172 bytesTotal: bytes.length
michael@0 6173 };
michael@0 6174 pipe.push(bytes, progressInfo);
michael@0 6175 pipe.close();
michael@0 6176 };
michael@0 6177 (function (global) {
michael@0 6178 global['SWF']['parse'] = SWF.parse;
michael@0 6179 global['SWF']['parseAsync'] = SWF.parseAsync;
michael@0 6180 }(this));

mercurial