diff --git a/utilities.ts b/utilities.ts index 77b0ab5d..88180c6f 100644 --- a/utilities.ts +++ b/utilities.ts @@ -441,197 +441,6 @@ module J2ME { return array; } - export class ArrayWriter { - _u8: Uint8Array; - _u16: Uint16Array; - _i32: Int32Array; - _f32: Float32Array; - _u32: Uint32Array; - _offset: number; - - constructor(initialCapacity: number = 16) { - this._u8 = null; - this._u16 = null; - this._i32 = null; - this._f32 = null; - this._offset = 0; - this.ensureCapacity(initialCapacity); - } - - public reset() { - this._offset = 0; - } - - public get offset (): number { - return this._offset; - } - - getIndex(size: number) { - release || assert (size === 1 || size === 2 || size === 4 || size === 8 || size === 16); - var index = this._offset / size; - release || assert ((index | 0) === index); - return index; - } - - ensureAdditionalCapacity(size) { - this.ensureCapacity(this._offset + size); - } - - ensureCapacity(minCapacity: number) { - if (!this._u8) { - this._u8 = new Uint8Array(minCapacity); - } else if (this._u8.length > minCapacity) { - return; - } - var oldCapacity = this._u8.length; - // var newCapacity = (((oldCapacity * 3) >> 1) + 8) & ~0x7; - var newCapacity = oldCapacity * 2; - if (newCapacity < minCapacity) { - newCapacity = minCapacity; - } - var u8 = new Uint8Array(newCapacity); - u8.set(this._u8, 0); - this._u8 = u8; - this._u16 = new Uint16Array(u8.buffer); - this._i32 = new Int32Array(u8.buffer); - this._f32 = new Float32Array(u8.buffer); - } - - writeInt(v: number) { - release || assert ((this._offset & 0x3) === 0); - this.ensureCapacity(this._offset + 4); - this.writeIntUnsafe(v); - } - - writeIntAt(v: number, offset: number) { - release || assert (offset >= 0 && offset <= this._offset); - release || assert ((offset & 0x3) === 0); - this.ensureCapacity(offset + 4); - var index = offset >> 2; - this._i32[index] = v; - } - - writeIntUnsafe(v: number) { - var index = this._offset >> 2; - this._i32[index] = v; - this._offset += 4; - } - - writeFloat(v: number) { - release || assert ((this._offset & 0x3) === 0); - this.ensureCapacity(this._offset + 4); - this.writeFloatUnsafe(v); - } - - writeFloatUnsafe(v: number) { - var index = this._offset >> 2; - this._f32[index] = v; - this._offset += 4; - } - - write4Floats(a: number, b: number, c: number, d: number) { - release || assert ((this._offset & 0x3) === 0); - this.ensureCapacity(this._offset + 16); - this.write4FloatsUnsafe(a, b, c, d); - } - - write4FloatsUnsafe(a: number, b: number, c: number, d: number) { - var index = this._offset >> 2; - this._f32[index + 0] = a; - this._f32[index + 1] = b; - this._f32[index + 2] = c; - this._f32[index + 3] = d; - this._offset += 16; - } - - write6Floats(a: number, b: number, c: number, d: number, e: number, f: number) { - release || assert ((this._offset & 0x3) === 0); - this.ensureCapacity(this._offset + 24); - this.write6FloatsUnsafe(a, b, c, d, e, f); - } - - write6FloatsUnsafe(a: number, b: number, c: number, d: number, e: number, f: number) { - var index = this._offset >> 2; - this._f32[index + 0] = a; - this._f32[index + 1] = b; - this._f32[index + 2] = c; - this._f32[index + 3] = d; - this._f32[index + 4] = e; - this._f32[index + 5] = f; - this._offset += 24; - } - - subF32View(): Float32Array { - return this._f32.subarray(0, this._offset >> 2); - } - - subI32View(): Int32Array { - return this._i32.subarray(0, this._offset >> 2); - } - - subU16View(): Uint16Array { - return this._u16.subarray(0, this._offset >> 1); - } - - subU8View(): Uint8Array { - return this._u8.subarray(0, this._offset); - } - - hashWords(hash: number, offset: number, length: number) { - var i32 = this._i32; - for (var i = 0; i < length; i++) { - hash = (((31 * hash) | 0) + i32[i]) | 0; - } - return hash; - } - - reserve(size: number) { - size = (size + 3) & ~0x3; // Round up to multiple of 4. - this.ensureCapacity(this._offset + size); - this._offset += size; - } - } - } - - export class ArrayReader { - _u8: Uint8Array; - _u16: Uint16Array; - _i32: Int32Array; - _f32: Float32Array; - _u32: Uint32Array; - _offset: number; - - constructor(buffer: ArrayBuffer) { - this._u8 = new Uint8Array(buffer); - this._u16 = new Uint16Array(buffer); - this._i32 = new Int32Array(buffer); - this._f32 = new Float32Array(buffer); - this._offset = 0; - } - - public get offset (): number { - return this._offset; - } - - public isEmpty (): boolean { - return this._offset === this._u8.length; - } - - readInt(): number { - release || Debug.assert ((this._offset & 0x3) === 0); - release || Debug.assert (this._offset <= this._u8.length - 4); - var v = this._i32[this._offset >> 2]; - this._offset += 4; - return v; - } - - readFloat(): number { - release || Debug.assert ((this._offset & 0x3) === 0); - release || Debug.assert (this._offset <= this._u8.length - 4); - var v = this._f32[this._offset >> 2]; - this._offset += 4; - return v; - } } export module ObjectUtilities { @@ -1343,111 +1152,6 @@ module J2ME { return Random.next(); }; - function polyfillWeakMap() { - if (typeof jsGlobal.WeakMap === 'function') { - return; // weak map is supported - } - var id = 0; - function WeakMap() { - this.id = '$weakmap' + (id++); - }; - WeakMap.prototype = { - has: function(obj) { - return obj.hasOwnProperty(this.id); - }, - get: function(obj, defaultValue) { - return obj.hasOwnProperty(this.id) ? obj[this.id] : defaultValue; - }, - set: function(obj, value) { - Object.defineProperty(obj, this.id, { - value: value, - enumerable: false, - configurable: true - }); - } - }; - jsGlobal.WeakMap = WeakMap; - } - - polyfillWeakMap(); - - declare var netscape; - declare var Components; - - export interface IReferenceCountable { - _referenceCount: number; - _addReference(); - _removeReference(); - } - - var useReferenceCounting = true; - - export class WeakList { - private _map: WeakMap; - private _list: T []; - constructor() { - if (typeof netscape !== "undefined" && netscape.security.PrivilegeManager) { - this._map = new WeakMap(); - } else { - this._list = []; - } - } - clear() { - if (this._map) { - this._map.clear(); - } else { - this._list.length = 0; - } - } - push(value: T) { - if (this._map) { - this._map.set(value, null); - } else { - this._list.push(value); - } - } - forEach(callback: (value: T) => void) { - if (this._map) { - if (typeof netscape !== "undefined") { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - } - Components.utils.nondeterministicGetWeakMapKeys(this._map).forEach(function (value: T) { - if (value._referenceCount !== 0) { - callback(value); - } - }); - return; - } - var list = this._list; - var zeroCount = 0; - for (var i = 0; i < list.length; i++) { - var value = list[i]; - if (useReferenceCounting && value._referenceCount === 0) { - zeroCount++; - } else { - callback(value); - } - } - if (zeroCount > 16 && zeroCount > (list.length >> 2)) { - var newList = []; - for (var i = 0; i < list.length; i++) { - if (list[i]._referenceCount > 0) { - newList.push(list[i]); - } - } - this._list = newList; - } - } - get length(): number { - if (this._map) { - // TODO: Implement this. - return -1; - } else { - return this._list.length; - } - } - } - export module NumberUtilities { export function pow2(exponent: number): number { if (exponent === (exponent | 0)) { @@ -1634,79 +1338,6 @@ module J2ME { } } - export module GeometricUtilities { - /** - * Crossing numeber tests to check if a point is inside a polygon. The polygon is given as - * an array of n + 1 float pairs where the last is equal to the first. - * - * http://geomalgorithms.com/a03-_inclusion.html - */ - export function pointInPolygon(x: number, y: number, polygon: Float32Array): boolean { - // release || assert (((polygon.length & 1) === 0) && polygon.length >= 8); - // release || assert (polygon[0] === polygon[polygon.length - 2] && - // polygon[1] === polygon[polygon.length - 1], "First and last points should be equal."); - var crosses = 0; - var n = polygon.length - 2; - var p = polygon; - - for (var i = 0; i < n; i += 2) { - var x0 = p[i + 0]; - var y0 = p[i + 1]; - var x1 = p[i + 2]; - var y1 = p[i + 3]; - if (((y0 <= y) && (y1 > y)) || ((y0 > y) && (y1 <= y))) { - var t = (y - y0) / (y1 - y0); - if (x < x0 + t * (x1 - x0)) { - crosses ++; - } - } - } - return (crosses & 1) === 1; - } - - /** - * Signed area of a triangle. If zero then points are collinear, if < 0 then points - * are clockwise otherwise counter-clockwise. - */ - export function signedArea(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): number { - return (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0); - } - - export function counterClockwise(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): boolean { - return signedArea(x0, y0, x1, y1, x2, y2) > 0; - } - - export function clockwise(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number): boolean { - return signedArea(x0, y0, x1, y1, x2, y2) < 0; - } - - export function pointInPolygonInt32(x: number, y: number, polygon: Int32Array): boolean { - // release || assert (((polygon.length & 1) === 0) && polygon.length >= 8); - // release || assert (polygon[0] === polygon[polygon.length - 2] && - // polygon[1] === polygon[polygon.length - 1], "First and last points should be equal."); - x = x | 0; - y = y | 0; - var crosses = 0; - var n = polygon.length - 2; - var p = polygon; - - for (var i = 0; i < n; i += 2) { - var x0 = p[i + 0]; - var y0 = p[i + 1]; - var x1 = p[i + 2]; - var y1 = p[i + 3]; - if (((y0 <= y) && (y1 > y)) || ((y0 > y) && (y1 <= y))) { - var t = (y - y0) / (y1 - y0); - if (x < x0 + t * (x1 - x0)) { - crosses ++; - } - - } - } - return (crosses & 1) === 1; - } - } - export enum LogLevel { Error = 0x1, Warn = 0x2, @@ -2021,59 +1652,6 @@ module J2ME { } } - export class CircularBuffer { - index: number; - start: number; - array: ArrayBufferView; - _size: number; - _mask: number; - constructor(Type, sizeInBits: number = 12) { - this.index = 0; - this.start = 0; - this._size = 1 << sizeInBits; - this._mask = this._size - 1; - this.array = new Type(this._size); - } - public get (i) { - return this.array[i]; - } - - public forEachInReverse(visitor) { - if (this.isEmpty()) { - return; - } - var i = this.index === 0 ? this._size - 1 : this.index - 1; - var end = (this.start - 1) & this._mask; - while (i !== end) { - if (visitor(this.array[i], i)) { - break; - } - i = i === 0 ? this._size - 1 : i - 1; - } - } - - public write(value) { - this.array[this.index] = value; - this.index = (this.index + 1) & this._mask; - if (this.index === this.start) { - this.start = (this.start + 1) & this._mask; - } - } - - public isFull(): boolean { - return ((this.index + 1) & this._mask) === this.start; - } - - public isEmpty(): boolean { - return this.index === this.start; - } - - public reset() { - this.index = 0; - this.start = 0; - } - } - export module BitSets { import assert = Debug.assert; @@ -2587,618 +2165,6 @@ module J2ME { } } - export interface UntypedBounds { - xMin: number; - yMin: number; - xMax: number; - yMax: number; - } - - export interface ASRectangle { - x: number; - y: number; - width: number; - height: number; - } - - /** - * Faster release version of bounds. - */ - export class Bounds { - xMin: number; - yMin: number; - xMax: number; - yMax: number; - constructor (xMin: number, yMin: number, xMax: number, yMax: number) { - this.xMin = xMin|0; - this.yMin = yMin|0; - this.xMax = xMax|0; - this.yMax = yMax|0; - } - - static FromUntyped (source: UntypedBounds): Bounds { - return new Bounds(source.xMin, source.yMin, source.xMax, source.yMax); - } - - static FromRectangle (source: ASRectangle): Bounds { - return new Bounds(source.x * 20|0, source.y * 20|0, (source.x + source.width) * 20|0, - (source.y + source.height) * 20|0); - } - - setElements (xMin: number, yMin: number, xMax: number, yMax: number): void { - this.xMin = xMin; - this.yMin = yMin; - this.xMax = xMax; - this.yMax = yMax; - } - - copyFrom (source: Bounds): void { - this.setElements(source.xMin, source.yMin, source.xMax, source.yMax); - } - - contains (x: number, y: number): boolean { - return x < this.xMin !== x < this.xMax && - y < this.yMin !== y < this.yMax; - } - - unionInPlace (other: Bounds): void { - this.xMin = Math.min(this.xMin, other.xMin); - this.yMin = Math.min(this.yMin, other.yMin); - this.xMax = Math.max(this.xMax, other.xMax); - this.yMax = Math.max(this.yMax, other.yMax); - } - - extendByPoint (x: number, y: number): void { - this.extendByX(x); - this.extendByY(y); - } - - extendByX (x: number): void { - // Exclude default values. - if (this.xMin === 0x8000000) { - this.xMin = this.xMax = x; - return; - } - this.xMin = Math.min(this.xMin, x); - this.xMax = Math.max(this.xMax, x); - } - - extendByY (y: number): void { - // Exclude default values. - if (this.yMin === 0x8000000) { - this.yMin = this.yMax = y; - return; - } - this.yMin = Math.min(this.yMin, y); - this.yMax = Math.max(this.yMax, y); - } - - public intersects(toIntersect: Bounds): boolean { - return this.contains(toIntersect.xMin, toIntersect.yMin) || - this.contains(toIntersect.xMax, toIntersect.yMax); - } - - isEmpty (): boolean { - return this.xMax <= this.xMin || this.yMax <= this.yMin; - } - - get width(): number { - return this.xMax - this.xMin; - } - - set width(value: number) { - this.xMax = this.xMin + value; - } - - get height(): number { - return this.yMax - this.yMin; - } - - set height(value: number) { - this.yMax = this.yMin + value; - } - - public getBaseWidth(angle: number): number { - var u = Math.abs(Math.cos(angle)); - var v = Math.abs(Math.sin(angle)); - return u * (this.xMax - this.xMin) + v * (this.yMax - this.yMin); - } - - public getBaseHeight(angle: number): number { - var u = Math.abs(Math.cos(angle)); - var v = Math.abs(Math.sin(angle)); - return v * (this.xMax - this.xMin) + u * (this.yMax - this.yMin); - } - - setEmpty (): void { - this.xMin = this.yMin = this.xMax = this.yMax = 0; - } - - /** - * Set all fields to the sentinel value 0x8000000. - * - * This is what Flash uses to indicate uninitialized bounds. Important for bounds calculation - * in `Graphics` instances, which start out with empty bounds but must not just extend them - * from an 0,0 origin. - */ - setToSentinels (): void { - this.xMin = this.yMin = this.xMax = this.yMax = 0x8000000; - } - - clone (): Bounds { - return new Bounds(this.xMin, this.yMin, this.xMax, this.yMax); - } - - toString(): string { - return "{ " + - "xMin: " + this.xMin + ", " + - "xMin: " + this.yMin + ", " + - "xMax: " + this.xMax + ", " + - "xMax: " + this.yMax + - " }"; - } - } - - /** - * Slower debug version of bounds, makes sure that all points have integer coordinates. - */ - export class DebugBounds { - private _xMin: number; - private _yMin: number; - private _xMax: number; - private _yMax: number; - - constructor (xMin: number, yMin: number, xMax: number, yMax: number) { - Debug.assert(isInteger(xMin)); - Debug.assert(isInteger(yMin)); - Debug.assert(isInteger(xMax)); - Debug.assert(isInteger(yMax)); - this._xMin = xMin|0; - this._yMin = yMin|0; - this._xMax = xMax|0; - this._yMax = yMax|0; - this.assertValid(); - } - - static FromUntyped (source: UntypedBounds): DebugBounds { - return new DebugBounds(source.xMin, source.yMin, source.xMax, source.yMax); - } - - static FromRectangle (source: ASRectangle): DebugBounds { - return new DebugBounds(source.x * 20|0, source.y * 20|0, (source.x + source.width) * 20|0, - (source.y + source.height) * 20|0); - } - - setElements (xMin: number, yMin: number, xMax: number, yMax: number): void { - this.xMin = xMin; - this.yMin = yMin; - this.xMax = xMax; - this.yMax = yMax; - } - - copyFrom (source: DebugBounds): void { - this.setElements(source.xMin, source.yMin, source.xMax, source.yMax); - } - - contains (x: number, y: number): boolean { - return x < this.xMin !== x < this.xMax && - y < this.yMin !== y < this.yMax; - } - - unionWith (other: DebugBounds): void { - this._xMin = Math.min(this._xMin, other._xMin); - this._yMin = Math.min(this._yMin, other._yMin); - this._xMax = Math.max(this._xMax, other._xMax); - this._yMax = Math.max(this._yMax, other._yMax); - } - - extendByPoint (x: number, y: number): void { - this.extendByX(x); - this.extendByY(y); - } - - extendByX (x: number): void { - if (this.xMin === 0x8000000) { - this.xMin = this.xMax = x; - return; - } - this.xMin = Math.min(this.xMin, x); - this.xMax = Math.max(this.xMax, x); - } - - extendByY (y: number): void { - if (this.yMin === 0x8000000) { - this.yMin = this.yMax = y; - return; - } - this.yMin = Math.min(this.yMin, y); - this.yMax = Math.max(this.yMax, y); - } - - public intersects(toIntersect: DebugBounds): boolean { - return this.contains(toIntersect._xMin, toIntersect._yMin) || - this.contains(toIntersect._xMax, toIntersect._yMax); - } - - isEmpty (): boolean { - return this._xMax <= this._xMin || this._yMax <= this._yMin; - } - - set xMin(value: number) { - Debug.assert(isInteger(value)); - this._xMin = value; - this.assertValid(); - } - - get xMin(): number { - return this._xMin; - } - - set yMin(value: number) { - Debug.assert(isInteger(value)); - this._yMin = value|0; - this.assertValid(); - } - - get yMin(): number { - return this._yMin; - } - - set xMax(value: number) { - Debug.assert(isInteger(value)); - this._xMax = value|0; - this.assertValid(); - } - - get xMax(): number { - return this._xMax; - } - - get width(): number { - return this._xMax - this._xMin; - } - - set yMax(value: number) { - Debug.assert(isInteger(value)); - this._yMax = value|0; - this.assertValid(); - } - - get yMax(): number { - return this._yMax; - } - - get height(): number { - return this._yMax - this._yMin; - } - - public getBaseWidth(angle: number): number { - var u = Math.abs(Math.cos(angle)); - var v = Math.abs(Math.sin(angle)); - return u * (this._xMax - this._xMin) + v * (this._yMax - this._yMin); - } - - public getBaseHeight(angle: number): number { - var u = Math.abs(Math.cos(angle)); - var v = Math.abs(Math.sin(angle)); - return v * (this._xMax - this._xMin) + u * (this._yMax - this._yMin); - } - - setEmpty (): void { - this._xMin = this._yMin = this._xMax = this._yMax = 0; - } - - clone (): DebugBounds { - return new DebugBounds(this.xMin, this.yMin, this.xMax, this.yMax); - } - - toString(): string { - return "{ " + - "xMin: " + this._xMin + ", " + - "xMin: " + this._yMin + ", " + - "xMax: " + this._xMax + ", " + - "yMax: " + this._yMax + - " }"; - } - - private assertValid(): void { -// release || assert(this._xMax >= this._xMin); -// release || assert(this._yMax >= this._yMin); - } - } - - /** - * Override Bounds with a slower by safer version, don't do this in release mode. - */ - // C4.Bounds = DebugBounds; - - export class Color { - public r: number; - public g: number; - public b: number; - public a: number; - constructor(r: number, g: number, b: number, a: number) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - static FromARGB(argb: number) { - return new Color ( - (argb >> 16 & 0xFF) / 255, - (argb >> 8 & 0xFF) / 255, - (argb >> 0 & 0xFF) / 255, - (argb >> 24 & 0xFF) / 255 - ); - } - static FromRGBA(rgba: number) { - return Color.FromARGB(ColorUtilities.RGBAToARGB(rgba)); - } - public toRGBA() { - return (this.r * 255) << 24 | (this.g * 255) << 16 | (this.b * 255) << 8 | (this.a * 255) - } - public toCSSStyle() { - return ColorUtilities.rgbaToCSSStyle(this.toRGBA()); - } - set (other: Color) { - this.r = other.r; - this.g = other.g; - this.b = other.b; - this.a = other.a; - } - public static Red = new Color(1, 0, 0, 1); - public static Green = new Color(0, 1, 0, 1); - public static Blue = new Color(0, 0, 1, 1); - public static None = new Color(0, 0, 0, 0); - public static White = new Color(1, 1, 1, 1); - public static Black = new Color(0, 0, 0, 1); - private static colorCache: { [color: string]: Color } = {}; - public static randomColor(alpha: number = 1): Color { - return new Color(Math.random(), Math.random(), Math.random(), alpha); - } - public static parseColor(color: string) { - if (!Color.colorCache) { - Color.colorCache = Object.create(null); - } - if (Color.colorCache[color]) { - return Color.colorCache[color]; - } - // TODO: Obviously slow, but it will do for now. - var span = document.createElement('span'); - document.body.appendChild(span); - span.style.backgroundColor = color; - var rgb = getComputedStyle(span).backgroundColor; - document.body.removeChild(span); - var m = /^rgb\((\d+), (\d+), (\d+)\)$/.exec(rgb); - if (!m) m = /^rgba\((\d+), (\d+), (\d+), ([\d.]+)\)$/.exec(rgb); - var result = new Color(0, 0, 0, 0); - result.r = parseFloat(m[1]) / 255; - result.g = parseFloat(m[2]) / 255; - result.b = parseFloat(m[3]) / 255; - result.a = m[4] ? parseFloat(m[4]) / 255 : 1; - return Color.colorCache[color] = result; - } - } - - export module ColorUtilities { - export function RGBAToARGB(rgba: number): number { - return ((rgba >> 8) & 0x00ffffff) | ((rgba & 0xff) << 24); - } - - export function ARGBToRGBA(argb: number): number { - return argb << 8 | ((argb >> 24) & 0xff); - } - - export function rgbaToCSSStyle(color: number): string { - return StringUtilities.concat9('rgba(', color >> 24 & 0xff, ',', color >> 16 & 0xff, ',', color >> 8 & 0xff, ',', (color & 0xff) / 0xff, ')'); - } - - export function cssStyleToRGBA(style: string) { - if (style[0] === "#") { - if (style.length === 7) { - var value = parseInt(style.substring(1), 16); - return (value << 8) | 0xff; - } - } else if (style[0] === "r") { - // We don't parse all types of rgba(....) color styles. We only handle the - // ones we generate ourselves. - var values = style.substring(5, style.length - 1).split(","); - var r = parseInt(values[0]); - var g = parseInt(values[1]); - var b = parseInt(values[2]); - var a = parseFloat(values[3]); - return (r & 0xff) << 24 | - (g & 0xff) << 16 | - (b & 0xff) << 8 | - ((a * 255) & 0xff); - } - return 0xff0000ff; // Red - } - - export function hexToRGB(color: string): number { - return parseInt(color.slice(1), 16); - } - - export function rgbToHex(color: number): string { - return '#' + ('000000' + (color >>> 0).toString(16)).slice(-6); - } - - export function isValidHexColor(value: any): boolean { - return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value); - } - - export function clampByte(value: number) { - return Math.max(0, Math.min(255, value)); - } - - /** - * Unpremultiplies the given |pARGB| color value. - */ - export function unpremultiplyARGB(pARGB: number) { - var b = (pARGB >> 0) & 0xff; - var g = (pARGB >> 8) & 0xff; - var r = (pARGB >> 16) & 0xff; - var a = (pARGB >> 24) & 0xff; - r = Math.imul(255, r) / a & 0xff; - g = Math.imul(255, g) / a & 0xff; - b = Math.imul(255, b) / a & 0xff; - return a << 24 | r << 16 | g << 8 | b; - } - - /** - * Premultiplies the given |pARGB| color value. - */ - export function premultiplyARGB(uARGB: number) { - var b = (uARGB >> 0) & 0xff; - var g = (uARGB >> 8) & 0xff; - var r = (uARGB >> 16) & 0xff; - var a = (uARGB >> 24) & 0xff; - r = ((Math.imul(r, a) + 127) / 255) | 0; - g = ((Math.imul(g, a) + 127) / 255) | 0; - b = ((Math.imul(b, a) + 127) / 255) | 0; - return a << 24 | r << 16 | g << 8 | b; - } - - var premultiplyTable: Uint8Array; - - /** - * All possible alpha values and colors 256 * 256 = 65536 entries. Experiments - * indicate that doing unpremultiplication this way is roughly 5x faster. - * - * To lookup a color |c| in the table at a given alpha value |a| use: - * |(a << 8) + c| to compute the index. This layout order was chosen to make - * table lookups cache friendly, it actually makes a difference. - * - * TODO: Figure out if memory / speed tradeoff is worth it. - */ - var unpremultiplyTable: Uint8Array; - - /** - * Make sure to call this before using the |unpremultiplyARGBUsingTableLookup| or - * |premultiplyARGBUsingTableLookup| functions. We want to execute this lazily so - * we don't incur any startup overhead. - */ - export function ensureUnpremultiplyTable() { - if (!unpremultiplyTable) { - unpremultiplyTable = new Uint8Array(256 * 256); - for (var c = 0; c < 256; c++) { - for (var a = 0; a < 256; a++) { - unpremultiplyTable[(a << 8) + c] = Math.imul(255, c) / a; - } - } - } - } - - export function tableLookupUnpremultiplyARGB(pARGB): number { - pARGB = pARGB | 0; - var a = (pARGB >> 24) & 0xff; - if (a === 0) { - return 0; - } else if (a === 0xff) { - return pARGB; - } - var b = (pARGB >> 0) & 0xff; - var g = (pARGB >> 8) & 0xff; - var r = (pARGB >> 16) & 0xff; - var o = a << 8; - var T = unpremultiplyTable; - r = T[o + r]; - g = T[o + g]; - b = T[o + b]; - return a << 24 | r << 16 | g << 8 | b; - } - - /** - * The blending equation for unpremultiplied alpha is: - * - * (src.rgb * src.a) + (dst.rgb * (1 - src.a)) - * - * For premultiplied alpha src.rgb and dst.rgb are already - * premultiplied by alpha, so the equation becomes: - * - * src.rgb + (dst.rgb * (1 - src.a)) - * - * TODO: Not sure what to do about the dst.rgb which is - * premultiplied by its alpah, but this appears to work. - * - * We use the "double blend trick" (http://stereopsis.com/doubleblend.html) to - * compute GA and BR without unpacking them. - */ - export function blendPremultipliedBGRA(tpBGRA: number, spBGRA: number) { - var sA = spBGRA & 0xff; - var sGA = spBGRA & 0x00ff00ff; - var sBR = spBGRA >> 8 & 0x00ff00ff; - var tGA = tpBGRA & 0x00ff00ff; - var tBR = tpBGRA >> 8 & 0x00ff00ff; - var A = 256 - sA; - tGA = Math.imul(tGA, A) >> 8; - tBR = Math.imul(tBR, A) >> 8; - return ((sBR + tBR & 0x00ff00ff) << 8) | (sGA + tGA & 0x00ff00ff); - } - - import swap32 = IntegerUtilities.swap32; - export function convertImage(sourceFormat: ImageType, targetFormat: ImageType, source: Int32Array, target: Int32Array) { - if (source !== target) { - release || Debug.assert(source.buffer !== target.buffer, "Can't handle overlapping views."); - } - var length = source.length; - if (sourceFormat === targetFormat) { - if (source === target) { - return; - } - for (var i = 0; i < length; i++) { - target[i] = source[i]; - } - return; - } - // enterTimeline("convertImage", ImageType[sourceFormat] + " to " + ImageType[targetFormat] + " (" + memorySizeToString(source.length)); - if (sourceFormat === ImageType.PremultipliedAlphaARGB && - targetFormat === ImageType.StraightAlphaRGBA) { - ColorUtilities.ensureUnpremultiplyTable(); - for (var i = 0; i < length; i++) { - var pBGRA = source[i]; - var a = pBGRA & 0xff; - if (a === 0) { - target[i] = 0; - } else if (a === 0xff) { - target[i] = (pBGRA & 0xff) << 24 | ((pBGRA >> 8) & 0x00ffffff); - } else { - var b = (pBGRA >> 24) & 0xff; - var g = (pBGRA >> 16) & 0xff; - var r = (pBGRA >> 8) & 0xff; - var o = a << 8; - var T = unpremultiplyTable; - r = T[o + r]; - g = T[o + g]; - b = T[o + b]; - target[i] = a << 24 | b << 16 | g << 8 | r; - } - } - } else if (sourceFormat === ImageType.StraightAlphaARGB && - targetFormat === ImageType.StraightAlphaRGBA) { - for (var i = 0; i < length; i++) { - target[i] = swap32(source[i]); - } - } else if (sourceFormat === ImageType.StraightAlphaRGBA && - targetFormat === ImageType.PremultipliedAlphaARGB) { - for (var i = 0; i < length; i++) { - var uABGR = source[i]; - var uARGB = (uABGR & 0xFF00FF00) | // A_G_ - (uABGR >> 16) & 0xff | // A_GB - (uABGR & 0xff) << 16; // ARGR - target[i] = swap32(premultiplyARGB(uARGB)); - } - } else { - Debug.somewhatImplemented("Image Format Conversion: " + ImageType[sourceFormat] + " -> " + ImageType[targetFormat]); - // Copy the buffer over for now, we should at least get some image output. - for (var i = 0; i < length; i++) { - target[i] = source[i]; - } - } - // leaveTimeline("convertImage"); - } - } - /** * Simple pool allocator for ArrayBuffers. This reduces memory usage in data structures * that resize buffers. @@ -3276,173 +2242,6 @@ module J2ME { return newArray; } } - - export module Telemetry { - export enum Feature { - EXTERNAL_INTERFACE_FEATURE = 1, - CLIPBOARD_FEATURE = 2, - SHAREDOBJECT_FEATURE = 3, - VIDEO_FEATURE = 4, - SOUND_FEATURE = 5, - NETCONNECTION_FEATURE = 6 - } - - export enum ErrorTypes { - AVM1_ERROR = 1, - AVM2_ERROR = 2 - } - - export var instance: ITelemetryService; - } - - export interface ITelemetryService { - reportTelemetry(data: any); - } - - export interface FileLoadingRequest { - url: string; - data: any; - } - - export interface FileLoadingProgress { - bytesLoaded: number; - bytesTotal: number; - } - - export interface FileLoadingSession { - onopen?: () => void; - onclose?: () => void; - onprogress?: (data: any, progressStatus: FileLoadingProgress) => void; - onhttpstatus?: (location: string, httpStatus: number, httpHeaders: any) => void; - onerror?: (e) => void; - open(request: FileLoadingRequest); - } - - export interface IFileLoadingService { - createSession(): FileLoadingSession; - setBaseUrl(url: string); - resolveUrl(url: string): string; - navigateTo(url: string, target: string); - } - - export module FileLoadingService { - export var instance: IFileLoadingService; - } - - export interface IExternalInterfaceService { - enabled: boolean; - initJS(callback: (functionName: string, args: any[]) => any); - registerCallback(functionName: string); - unregisterCallback(functionName: string); - eval(expression): any; - call(request): any; - getId(): string; - } - - export module ExternalInterfaceService { - export var instance: IExternalInterfaceService = { - enabled: false, - initJS(callback: (functionName: string, args: any[]) => any) { }, - registerCallback(functionName: string) { }, - unregisterCallback(functionName: string) { }, - eval(expression: string): any { }, - call(request: string): any { }, - getId(): string { return null; } - }; - } - - export class ClipboardService { - public static instance: ClipboardService = null; - - public setClipboard(data: string): void { - Debug.abstractMethod("public ClipboardService::setClipboard"); - } - } - - export class Callback { - private _queues: any; - constructor () { - this._queues = {}; - } - - public register(type, callback) { - Debug.assert(type); - Debug.assert(callback); - var queue = this._queues[type]; - if (queue) { - if (queue.indexOf(callback) > -1) { - return; - } - } else { - queue = this._queues[type] = []; - } - queue.push(callback); - } - - public unregister(type: string, callback) { - Debug.assert(type); - Debug.assert(callback); - var queue = this._queues[type]; - if (!queue) { - return; - } - var i = queue.indexOf(callback); - if (i !== -1) { - queue.splice(i, 1); - } - if (queue.length === 0) { - this._queues[type] = null; - } - } - - public notify(type: string, args) { - var queue = this._queues[type]; - if (!queue) { - return; - } - queue = queue.slice(); - var args = Array.prototype.slice.call(arguments, 0); - for (var i = 0; i < queue.length; i++) { - var callback = queue[i]; - callback.apply(null, args); - } - } - - public notify1(type: string, value) { - var queue = this._queues[type]; - if (!queue) { - return; - } - queue = queue.slice(); - for (var i = 0; i < queue.length; i++) { - var callback = queue[i]; - callback(type, value); - } - } - } - - export enum ImageType { - None, - - /** - * Premultiplied ARGB (byte-order). - */ - PremultipliedAlphaARGB, - - /** - * Unpremultiplied ARGB (byte-order). - */ - StraightAlphaARGB, - - /** - * Unpremultiplied RGBA (byte-order), this is what putImageData expects. - */ - StraightAlphaRGBA, - - JPEG, - PNG, - GIF - } } /**