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