474 lines
12 KiB
JavaScript
474 lines
12 KiB
JavaScript
"use strict";
|
|
/*
|
|
Copyright (C) 2012 by Jeremy P. White <jwhite@codeweavers.com>
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
** 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 */
|