"use strict"; /* Copyright (C) 2012 by Jeremy P. White This file is part of spice-html5. spice-html5 is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. spice-html5 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with spice-html5. If not, see . */ /*---------------------------------------------------------------------------- ** Spice types ** This file contains classes for common spice types. ** Generally, they are used as helpers in reading and writing messages ** to and from the server. **--------------------------------------------------------------------------*/ function SpiceChannelId() { } SpiceChannelId.prototype = { from_dv: function(dv, at, mb) { this.type = dv.getUint8(at, true); at ++; this.id = dv.getUint8(at, true); at ++; return at; }, } function SpiceRect() { } SpiceRect.prototype = { from_dv: function(dv, at, mb) { this.top = dv.getUint32(at, true); at += 4; this.left = dv.getUint32(at, true); at += 4; this.bottom = dv.getUint32(at, true); at += 4; this.right = dv.getUint32(at, true); at += 4; return at; }, is_same_size : function(r) { if ((this.bottom - this.top) == (r.bottom - r.top) && (this.right - this.left) == (r.right - r.left) ) return true; return false; }, } function SpiceClipRects() { } SpiceClipRects.prototype = { from_dv: function(dv, at, mb) { var i; this.num_rects = dv.getUint32(at, true); at += 4; if (this.num_rects > 0) this.rects = []; for (i = 0; i < this.num_rects; i++) { this.rects[i] = new SpiceRect(); at = this.rects[i].from_dv(dv, at, mb); } return at; }, } function SpiceClip() { } SpiceClip.prototype = { from_dv: function(dv, at, mb) { this.type = dv.getUint8(at, true); at ++; if (this.type == SPICE_CLIP_TYPE_RECTS) { this.rects = new SpiceClipRects(); at = this.rects.from_dv(dv, at, mb); } return at; }, } function SpiceImageDescriptor() { } SpiceImageDescriptor.prototype = { from_dv: function(dv, at, mb) { this.id = dv.getUint64(at, true); at += 8; this.type = dv.getUint8(at, true); at ++; this.flags = dv.getUint8(at, true); at ++; this.width = dv.getUint32(at, true); at += 4; this.height= dv.getUint32(at, true); at += 4; return at; }, } function SpicePalette() { } SpicePalette.prototype = { from_dv: function(dv, at, mb) { var i; this.unique = dv.getUint64(at, true); at += 8; this.num_ents = dv.getUint16(at, true); at += 2; this.ents = []; for (i = 0; i < this.num_ents; i++) { this.ents[i] = dv.getUint32(at, true); at += 4; } return at; }, } function SpiceBitmap() { } SpiceBitmap.prototype = { from_dv: function(dv, at, mb) { this.format = dv.getUint8(at, true); at++; this.flags = dv.getUint8(at, true); at++; this.x = dv.getUint32(at, true); at += 4; this.y = dv.getUint32(at, true); at += 4; this.stride = dv.getUint32(at, true); at += 4; if (this.flags & SPICE_BITMAP_FLAGS_PAL_FROM_CACHE) { this.palette_id = dv.getUint64(at, true); at += 8; } else { var offset = dv.getUint32(at, true); at += 4; if (offset == 0) this.palette = null; else { this.palette = new SpicePalette; this.palette.from_dv(dv, offset, mb); } } // FIXME - should probably constrain this to the offset // of palette, if non zero this.data = mb.slice(at); at += this.data.byteLength; return at; }, } function SpiceImage() { } SpiceImage.prototype = { from_dv: function(dv, at, mb) { this.descriptor = new SpiceImageDescriptor; at = this.descriptor.from_dv(dv, at, mb); if (this.descriptor.type == SPICE_IMAGE_TYPE_LZ_RGB) { this.lz_rgb = new Object(); this.lz_rgb.length = dv.getUint32(at, true); at += 4; var initial_at = at; this.lz_rgb.magic = ""; for (var i = 3; i >= 0; i--) this.lz_rgb.magic += String.fromCharCode(dv.getUint8(at + i)); at += 4; // NOTE: The endian change is *correct* this.lz_rgb.version = dv.getUint32(at); at += 4; this.lz_rgb.type = dv.getUint32(at); at += 4; this.lz_rgb.width = dv.getUint32(at); at += 4; this.lz_rgb.height = dv.getUint32(at); at += 4; this.lz_rgb.stride = dv.getUint32(at); at += 4; this.lz_rgb.top_down = dv.getUint32(at); at += 4; var header_size = at - initial_at; this.lz_rgb.data = mb.slice(at, this.lz_rgb.length + at - header_size); at += this.lz_rgb.data.byteLength; } if (this.descriptor.type == SPICE_IMAGE_TYPE_BITMAP) { this.bitmap = new SpiceBitmap; at = this.bitmap.from_dv(dv, at, mb); } if (this.descriptor.type == SPICE_IMAGE_TYPE_SURFACE) { this.surface_id = dv.getUint32(at, true); at += 4; } if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG) { this.jpeg = new Object; this.jpeg.data_size = dv.getUint32(at, true); at += 4; this.jpeg.data = mb.slice(at); at += this.jpeg.data.byteLength; } if (this.descriptor.type == SPICE_IMAGE_TYPE_JPEG_ALPHA) { this.jpeg_alpha = new Object; this.jpeg_alpha.flags = dv.getUint8(at, true); at += 1; this.jpeg_alpha.jpeg_size = dv.getUint32(at, true); at += 4; this.jpeg_alpha.data_size = dv.getUint32(at, true); at += 4; this.jpeg_alpha.data = mb.slice(at, this.jpeg_alpha.jpeg_size + at); at += this.jpeg_alpha.data.byteLength; // Alpha channel is an LZ image this.jpeg_alpha.alpha = new Object(); this.jpeg_alpha.alpha.length = this.jpeg_alpha.data_size - this.jpeg_alpha.jpeg_size; var initial_at = at; this.jpeg_alpha.alpha.magic = ""; for (var i = 3; i >= 0; i--) this.jpeg_alpha.alpha.magic += String.fromCharCode(dv.getUint8(at + i)); at += 4; // NOTE: The endian change is *correct* this.jpeg_alpha.alpha.version = dv.getUint32(at); at += 4; this.jpeg_alpha.alpha.type = dv.getUint32(at); at += 4; this.jpeg_alpha.alpha.width = dv.getUint32(at); at += 4; this.jpeg_alpha.alpha.height = dv.getUint32(at); at += 4; this.jpeg_alpha.alpha.stride = dv.getUint32(at); at += 4; this.jpeg_alpha.alpha.top_down = dv.getUint32(at); at += 4; var header_size = at - initial_at; this.jpeg_alpha.alpha.data = mb.slice(at, this.jpeg_alpha.alpha.length + at - header_size); at += this.jpeg_alpha.alpha.data.byteLength; } if (this.descriptor.type == SPICE_IMAGE_TYPE_QUIC) { this.quic = new SpiceQuic; at = this.quic.from_dv(dv, at, mb); } return at; }, } function SpiceQMask() { } SpiceQMask.prototype = { from_dv: function(dv, at, mb) { this.flags = dv.getUint8(at, true); at++; this.pos = new SpicePoint; at = this.pos.from_dv(dv, at, mb); var offset = dv.getUint32(at, true); at += 4; if (offset == 0) { this.bitmap = null; return at; } this.bitmap = new SpiceImage; return this.bitmap.from_dv(dv, offset, mb); }, } function SpicePattern() { } SpicePattern.prototype = { from_dv: function(dv, at, mb) { var offset = dv.getUint32(at, true); at += 4; if (offset == 0) { this.pat = null; } else { this.pat = new SpiceImage; this.pat.from_dv(dv, offset, mb); } this.pos = new SpicePoint; return this.pos.from_dv(dv, at, mb); } } function SpiceBrush() { } SpiceBrush.prototype = { from_dv: function(dv, at, mb) { this.type = dv.getUint8(at, true); at ++; if (this.type == SPICE_BRUSH_TYPE_SOLID) { this.color = dv.getUint32(at, true); at += 4; } else if (this.type == SPICE_BRUSH_TYPE_PATTERN) { this.pattern = new SpicePattern; at = this.pattern.from_dv(dv, at, mb); } return at; }, } function SpiceFill() { } SpiceFill.prototype = { from_dv: function(dv, at, mb) { this.brush = new SpiceBrush; at = this.brush.from_dv(dv, at, mb); this.rop_descriptor = dv.getUint16(at, true); at += 2; this.mask = new SpiceQMask; return this.mask.from_dv(dv, at, mb); }, } function SpiceCopy() { } SpiceCopy.prototype = { from_dv: function(dv, at, mb) { var offset = dv.getUint32(at, true); at += 4; if (offset == 0) { this.src_bitmap = null; } else { this.src_bitmap = new SpiceImage; this.src_bitmap.from_dv(dv, offset, mb); } this.src_area = new SpiceRect; at = this.src_area.from_dv(dv, at, mb); this.rop_descriptor = dv.getUint16(at, true); at += 2; this.scale_mode = dv.getUint8(at, true); at ++; this.mask = new SpiceQMask; return this.mask.from_dv(dv, at, mb); }, } function SpicePoint16() { } SpicePoint16.prototype = { from_dv: function(dv, at, mb) { this.x = dv.getUint16(at, true); at += 2; this.y = dv.getUint16(at, true); at += 2; return at; }, } function SpicePoint() { } SpicePoint.prototype = { from_dv: function(dv, at, mb) { this.x = dv.getUint32(at, true); at += 4; this.y = dv.getUint32(at, true); at += 4; return at; }, } function SpiceCursorHeader() { } SpiceCursorHeader.prototype = { from_dv: function(dv, at, mb) { this.unique = dv.getUint64(at, true); at += 8; this.type = dv.getUint8(at, true); at ++; this.width = dv.getUint16(at, true); at += 2; this.height = dv.getUint16(at, true); at += 2; this.hot_spot_x = dv.getUint16(at, true); at += 2; this.hot_spot_y = dv.getUint16(at, true); at += 2; return at; }, } function SpiceCursor() { } SpiceCursor.prototype = { from_dv: function(dv, at, mb) { this.flags = dv.getUint16(at, true); at += 2; if (this.flags & SPICE_CURSOR_FLAGS_NONE) this.header = null; else { this.header = new SpiceCursorHeader; at = this.header.from_dv(dv, at, mb); this.data = mb.slice(at); at += this.data.byteLength; } return at; }, } function SpiceSurface() { } SpiceSurface.prototype = { from_dv: function(dv, at, mb) { this.surface_id = dv.getUint32(at, true); at += 4; this.width = dv.getUint32(at, true); at += 4; this.height = dv.getUint32(at, true); at += 4; this.format = dv.getUint32(at, true); at += 4; this.flags = dv.getUint32(at, true); at += 4; return at; }, } /* FIXME - SpiceImage types lz_plt, jpeg, zlib_glz, and jpeg_alpha are completely unimplemented */