/* eyeOS Spice Web Client Copyright (c) 2015 eyeOS S.L. Contact Jose Carlos Norte (jose@eyeos.com) for more information about this software. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License version 3 along with this program in the file "LICENSE". If not, see . See www.eyeos.org for more details. All requests should be sent to licensing@eyeos.org The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section 5 of the GNU Affero General Public License version 3. In accordance with Section 7(b) of the GNU Affero General Public License version 3, these Appropriate Legal Notices must retain the display of the "Powered by eyeos" logo and retain the original copyright notice. If the display of the logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices must display the words "Powered by eyeos" and retain the original copyright notice. */ if (typeof CanvasPixelArray != 'undefined' && !CanvasPixelArray.prototype.set) { CanvasPixelArray.prototype.set = function(u8) { var length = u8.length; for (var i=0; i>> 3; var length = bytes.length; var half = length / 2; var canvas = wdi.graphics.getTmpCanvas(width, height); var context = canvas.getContext('2d'); var result = context.createImageData(width, height); var andMask = []; var xorMask = []; for (var i = 0; i < length; i++) { var currentByte = bytes[i]; var bitsLeft = 8; if (i >= half) { while (bitsLeft--) { var bit = (currentByte & this.monoMask[bitsLeft]) && true; andMask.push(bit); } } else if (i < half) { while (bitsLeft--) { var bit = (currentByte & this.monoMask[bitsLeft]) && true; xorMask.push(bit); } } } var pos = 0; half = xorMask.length; for (i = 0; i < half; i++) { pos = i * 4; if (!andMask[i] && !xorMask[i]) { result.data[pos] = 0; result.data[pos + 1] = 0; result.data[pos + 2] = 0; result.data[pos + 3] = 255; } else if (!andMask[i] && xorMask[i]) { result.data[pos] = 255; result.data[pos + 1] = 255; result.data[pos + 2] = 255; result.data[pos + 3] = 0; } else if (andMask[i] && !xorMask[i]) { result.data[pos] = 255; result.data[pos + 1] = 255; result.data[pos + 2] = 255; result.data[pos + 3] = 255; } else if (andMask[i] && xorMask[i]) { result.data[pos] = 0; result.data[pos + 1] = 0; result.data[pos + 2] = 0; result.data[pos + 3] = 255; } } return result; }, drawJpeg: function (imageDescriptor, jpegData, callback, previousScope) { return this.drawBrowserImage(imageDescriptor, jpegData, callback, previousScope, 'jpeg', false); }, drawBrowserImage: function (imageDescriptor, jpegData, callback, previousScope, type, alreadyEncoded) { var tmpstr; var img = wdi.GlobalPool.create('Image'); var url; img.onload = function() { URL.revokeObjectURL(url) try { if (imageDescriptor.flags & wdi.SpiceImageFlags.SPICE_IMAGE_FLAGS_CACHE_ME) { var myImage = wdi.graphics.getTmpCanvas(this.width, this.height); var tmp_context = myImage.getContext('2d'); tmp_context.drawImage(this, 0, 0); wdi.ImageCache.addImage(imageDescriptor, myImage); } callback.call(previousScope, this); } catch (e) { wdi.Debug.error(e.message); } finally { wdi.ExecutionControl.currentProxy.end(); } }; img.onerror = function() { URL.revokeObjectURL(url) wdi.Debug.error('failed to load JPEG image'); wdi.ExecutionControl.currentProxy.end(); }; if(!alreadyEncoded) { url = wdi.SpiceObject.bytesToURI(jpegData); img.src = url; } else { tmpstr = jpegData; img.src = tmpstr; } }, getImageFromSpice: function (imageDescriptor, imageData, clientGui, callback, previousScope, options) { var myImage; var source_img = null; var opaque; var brush; var raw; if (options) { opaque = options['opaque']; brush = options['brush']; raw = options['raw']; } else { opaque = false; raw = false; brush = false; } switch (imageDescriptor.type) { case wdi.SpiceImageType.SPICE_IMAGE_TYPE_LZ_RGB: source_img = this.processLz(imageDescriptor, imageData, brush, opaque, clientGui); break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_LZ_PLT: wdi.Debug.log('lz plt decode'); source_img = wdi.LZSS.convert_spice_lz_to_web(clientGui.getContext(0), imageData, imageDescriptor, opaque); break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_QUIC: source_img = this.processQuic(imageDescriptor, imageData, brush, opaque, clientGui); break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_JPEG: wdi.Debug.log('JPEG decode'); wdi.ExecutionControl.sync = false; this.drawJpeg(imageDescriptor, imageData.subarray(4), callback, previousScope); return; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_JPEG_ALPHA: wdi.Debug.log('JPEG Alpha decode'); wdi.ExecutionControl.sync = false; var jpeg_data = imageData.subarray(9); this.drawJpeg(imageDescriptor, jpeg_data, callback, previousScope); // TODO: extract alpha mask and apply return; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_BITMAP: wdi.Debug.log('BMP'); if (imageData.toJSArray) { imageData = imageData.toJSArray(); } //Spice BMP Headers source_img = new wdi.BMP2(imageData).marshall(clientGui.getContext(0)); break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS: case wdi.SpiceImageType.SPICE_IMAGE_TYPE_FROM_CACHE: wdi.ExecutionControl.sync = false; wdi.ImageCache.getImageFrom(imageDescriptor, function(img) { callback.call(previousScope, img); wdi.ExecutionControl.currentProxy.end(); }); return; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_SURFACE: var origin_surface_id = wdi.SpiceObject.bytesToInt32(imageData.toJSArray()); var context = clientGui.getContext(origin_surface_id); source_img = context.canvas; break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_CANVAS: source_img = imageData; break; case wdi.SpiceImageType.SPICE_IMAGE_TYPE_PNG: wdi.ExecutionControl.sync = false; imageData = wdi.SpiceObject.bytesToString(imageData.toJSArray()); this.drawBrowserImage(imageDescriptor, imageData, callback, previousScope, "png", true); return; default: wdi.Debug.log('Unknown image type: ' + imageDescriptor.type); wdi.ExecutionControl.currentProxy.end(); return; } myImage = null; if (imageDescriptor.flags & wdi.SpiceImageFlags.SPICE_IMAGE_FLAGS_CACHE_ME) { wdi.ImageCache.addImage(imageDescriptor, source_img); } if(source_img.getContext || raw) { myImage = source_img; } else { myImage = this.getImageFromData(source_img); } if (imageDescriptor.flags & wdi.SpiceImageFlags.SPICE_IMAGE_FLAGS_CACHE_ME) { wdi.ImageCache.addImage(imageDescriptor, myImage); } if (wdi.ExecutionControl.sync) callback.call(previousScope, myImage); }, processUncompress: function (imageDescriptor, imageData, brush, opaque, clientGui, callback) { var scope = this; var imageUncompressor = wdi.ImageUncompressor.getSyncInstance(); imageUncompressor.process( imageDescriptor, imageData, brush, opaque, clientGui, callback, scope ); }, processQuic: function(imageDescriptor, imageData, brush, opaque, clientGui) { var source_img; var callback = function(data) { var u8 = new Uint8ClampedArray(data); source_img = new ImageData(u8, imageDescriptor.width, imageDescriptor.height); }; this.processUncompress(imageDescriptor, imageData, brush, opaque, clientGui, callback); return source_img; }, processLz: function(imageDescriptor, imageData, brush, opaque, clientGui) { var source_img; var self = this; function callback(data) { var imageUncompressor = wdi.ImageUncompressor.getSyncInstance(); var extractedData = imageUncompressor.extractLzHeader(imageData, brush); var u8 = new Uint8ClampedArray(data); source_img = new ImageData(u8, imageDescriptor.width, imageDescriptor.height); if (!extractedData.header.top_down && !opaque) { source_img = this.imageFlip(source_img); } }; this.processUncompress(imageDescriptor, imageData, brush, opaque, clientGui, callback); return source_img; }, imageFlip: function (source_img) { return wdi.RasterOperation.flip(this.getImageFromData(source_img)); }, //given an imagedata it returns a canvas getImageFromData: function(data, notUsePool) { if(data.getContext || data instanceof Image) { return data; } var sourceCanvas; if (!notUsePool) { sourceCanvas = this.getNewTmpCanvas(data.width, data.height); } else { sourceCanvas = $('').attr({ 'width': data.width, 'height': data.height })[0]; //this.getNewTmpCanvas(data.width, data.height); } var srcCtx = sourceCanvas.getContext('2d'); srcCtx.putImageData(data, 0, 0); return sourceCanvas; }, //given a canvas it returns a ImageData getDataFromImage: function(canvas) { return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); }, getBoxFromSrcArea: function(src_area) { var box = { width: src_area.right - src_area.left, height: src_area.bottom - src_area.top, x: src_area.left, y: src_area.top }; return box; }, setBrush: function(clientGui, context, brush, box, ropd) { var pattern, imageDescriptor, type, imageData; if (brush.type === wdi.SpiceBrushType.SPICE_BRUSH_TYPE_PATTERN) { imageDescriptor = brush.pattern.image; this.getImageFromSpice(imageDescriptor, brush.pattern.imageData, clientGui, function(sourceImg) { pattern = context.createPattern(sourceImg, "repeat"); if (ropd === wdi.SpiceRopd.SPICE_ROPD_OP_PUT) { //no rop, direct draw context.fillStyle = pattern; context.fillRect(box.x, box.y, box.width, box.height); } else { //Creating brushImg to raster var tmp_canvas = wdi.graphics.getTmpCanvas(box.width, box.height); var tmp_context = tmp_canvas.getContext('2d'); tmp_context.fillStyle = pattern; tmp_context.fillRect(0, 0, box.width, box.height); var dest = wdi.graphics.getRect(box, context.canvas); imageData = wdi.RasterOperation.process(ropd, tmp_canvas, dest); //draw to screen, imageData is a canvas context.drawImage(imageData, box.x, box.y, box.width, box.height); } }, this, { 'opaque': true }); } else if (brush.type === wdi.SpiceBrushType.SPICE_BRUSH_TYPE_SOLID) { if (ropd === wdi.SpiceRopd.SPICE_ROPD_OP_PUT) { //no rop, direct draw if(context.fillStyle != brush.color.simple_html_color) { context.fillStyle = brush.color.simple_html_color; } context.fillRect(box.x, box.y, box.width, box.height); } else { //if we need rop, we need intermediate canvas... //Creating brushImg to raster var tmp_canvas = wdi.graphics.getTmpCanvas(box.width, box.height); var tmp_context = tmp_canvas.getContext('2d'); tmp_context.fillStyle = brush.color.html_color; tmp_context.fillRect(0, 0, box.width, box.height); var dest = wdi.graphics.getRect(box, context.canvas); imageData = wdi.RasterOperation.process(ropd, tmp_canvas, dest); //draw to screen, imageData is a canvas context.drawImage(imageData, box.x, box.y, box.width, box.height); } } }, imageIsEntireColor: function(r,g,b, size, data) { var pos = 0; var equal; do { equal = data[pos] === r && data[pos+1] === g && data[pos+2] === b; pos+= 4; } while(pos != size && equal); return equal; }, drawBackText: function(clientGui, context, text) { var back_brush = text.back_brush; var back_mode = text.back_mode; var box = wdi.graphics.getBoxFromSrcArea(text.base.box); this.setBrush(clientGui, context, back_brush, box, back_mode); }, drawString: function(context, string, bpp, fore_brush, clip_type, display) { var color = fore_brush.color; var length = string.len; var render_pos, glyph_origin; var width; var height; var data; var lines; var imgData; var factor; var x; var y; var i; var buf, buf8, rawData; var bytesLeft; var bytesTotal; var subData; var rasterArray = string.raster_glyph; var currentRaster; var rawLine; var bitsLeft; var byteCounter; var alpha; var index; var box; if (bpp === 1) { factor = 255; } else if (bpp === 4) { factor = 17; } else { factor = 1; } for (i = 0; i < length; i++) { currentRaster = rasterArray[i]; //Loop for each Glyph render_pos = currentRaster.render_pos; glyph_origin = currentRaster.glyph_origin; width = currentRaster.width; height = currentRaster.height; data = currentRaster.data; lines = height; buf = new ArrayBuffer(width * height * 4); buf8 = new Uint8ClampedArray(buf); rawData = new Uint32Array(buf); x = 0; y = 0; while (lines--) { //glyphline, not text line //Loop for each line bytesLeft = Math.ceil(width * bpp / 8); bytesTotal = bytesLeft; subData = []; while (bytesTotal--) { subData.push(data.pop()); } while (bytesLeft--) { rawLine = subData.pop(); bitsLeft = 8; byteCounter = 0; while (bitsLeft) { alpha = wdi.bppMask[bpp][byteCounter] & rawLine; if (bpp === 1 && alpha) { alpha = 1; } else if (bpp === 4 && alpha && alpha > 15) { alpha = alpha >> 4; } if (alpha) { index = (y * width + x); rawData[index] = factor * alpha << 24 | // alpha color.b << 16 | // blue color.g << 8 | // green color.r; // red } bitsLeft -= bpp; x++; byteCounter++; } } y++; x = 0; } box = { 'x': render_pos.x + glyph_origin.x, 'y': render_pos.y + glyph_origin.y - 1, 'width': width, 'height': height }; imgData = new ImageData(buf8, width, height); var tmpCanvas = wdi.graphics.getImageFromData(imgData); display.drawClip(tmpCanvas, box, context); wdi.GlobalPool.discard('Canvas', tmpCanvas); } }, getImgDataPosition: function(x, y, width) { var index = (y * width + x) * 4; return index; }, //returns the shared canvas getTmpCanvas: function(width, height) { var canvas = this.tmpCanvas; canvas.width = width; canvas.height = height; return canvas; }, //return always a new canvas getNewTmpCanvas: function(width, height) { //pool! var sourceCanvas = wdi.GlobalPool.create('Canvas'); sourceCanvas.width = width; sourceCanvas.height = height; return sourceCanvas; } } wdi.Rop3 = { 0x01: function(pat, src, dest) { return~ (pat | src | dest) }, 0x02: function(pat, src, dest) { return~ (pat | src) & dest }, 0x04: function(pat, src, dest) { return~ (pat | dest) & src }, 0x06: function(pat, src, dest) { return~ (~(src ^ dest) | pat) }, 0x07: function(pat, src, dest) { return~ ((src & dest) | pat) }, 0x08: function(pat, src, dest) { return~ pat & dest & src }, 0x09: function(pat, src, dest) { return~ ((src ^ dest) | pat) }, 0x0b: function(pat, src, dest) { return~ ((~dest & src) | pat) }, 0x0d: function(pat, src, dest) { return~ ((~src & dest) | pat) }, 0x0e: function(pat, src, dest) { return~ (~(src | dest) | pat) }, 0x10: function(pat, src, dest) { return~ (src | dest) & pat }, 0x12: function(pat, src, dest) { return~ (~(pat ^ dest) | src) }, 0x13: function(pat, src, dest) { return~ ((pat & dest) | src) }, 0x14: function(pat, src, dest) { return~ (~(pat ^ src) | dest) }, 0x15: function(pat, src, dest) { return~ ((pat & src) | dest) }, 0x16: function(pat, src, dest) { return (~(pat & src) & dest) ^ src ^ pat }, 0x17: function(pat, src, dest) { return~ (((src ^ dest) & (src ^ pat)) ^ src) }, 0x18: function(pat, src, dest) { return (src ^ pat) & (pat ^ dest) }, 0x19: function(pat, src, dest) { return~ ((~(pat & src) & dest) ^ src) }, 0x1a: function(pat, src, dest) { return ((pat & src) | dest) ^ pat }, 0x1b: function(pat, src, dest) { return~ (((pat ^ src) & dest) ^ src) }, 0x1c: function(pat, src, dest) { return ((pat & dest) | src) ^ pat }, 0x1d: function(pat, src, dest) { return~ (((pat ^ dest) & src) ^ dest) }, 0x1e: function(pat, src, dest) { return (dest | src) ^ pat }, 0x1f: function(pat, src, dest) { return~ ((src | dest) & pat) }, 0x20: function(pat, src, dest) { return~ src & pat & dest }, 0x21: function(pat, src, dest) { return~ ((pat ^ dest) | src) }, 0x23: function(pat, src, dest) { return~ ((~dest & pat) | src) }, 0x24: function(pat, src, dest) { return (src ^ pat) & (dest ^ src) }, 0x25: function(pat, src, dest) { return~ ((~(src & pat) & dest) ^ pat) }, 0x26: function(pat, src, dest) { return ((src & pat) | dest) ^ src }, 0x27: function(pat, src, dest) { return (~(src ^ pat) | dest) ^ src }, 0x28: function(pat, src, dest) { return (pat ^ src) & dest }, 0x29: function(pat, src, dest) { return~ (((src & pat) | dest) ^ src ^ pat) }, 0x2a: function(pat, src, dest) { return~ (src & pat) & dest }, 0x2b: function(pat, src, dest) { return~ (((pat ^ dest) & (src ^ pat)) ^ src) }, 0x2c: function(pat, src, dest) { return ((src | dest) & pat) ^ src }, 0x2d: function(pat, src, dest) { return (~dest | src) ^ pat }, 0x2e: function(pat, src, dest) { return ((pat ^ dest) | src) ^ pat }, 0x2f: function(pat, src, dest) { return~ ((~dest | src) & pat) }, 0x31: function(pat, src, dest) { return~ ((~pat & dest) | src) }, 0x32: function(pat, src, dest) { return (src | pat | dest) ^ src }, 0x34: function(pat, src, dest) { return ((src & dest) | pat) ^ src }, 0x35: function(pat, src, dest) { return (~(src ^ dest) | pat) ^ src }, 0x36: function(pat, src, dest) { return (pat | dest) ^ src }, 0x37: function(pat, src, dest) { return~ ((pat | dest) & src) }, 0x38: function(pat, src, dest) { return ((pat | dest) & src) ^ pat }, 0x39: function(pat, src, dest) { return (~dest | pat) ^ src }, 0x3a: function(pat, src, dest) { return ((src ^ dest) | pat) ^ src }, 0x3b: function(pat, src, dest) { return~ ((~dest | pat) & src) }, 0x3d: function(pat, src, dest) { return (~(src | dest) | pat) ^ src }, 0x3e: function(pat, src, dest) { return ((~src & dest) | pat) ^ src }, 0x40: function(pat, src, dest) { return~ dest & src & pat }, 0x41: function(pat, src, dest) { return~ ((src ^ pat) | dest) }, 0x42: function(pat, src, dest) { return (src ^ dest) & (pat ^ dest) }, 0x43: function(pat, src, dest) { return~ ((~(src & dest) & pat) ^ src) }, 0x45: function(pat, src, dest) { return~ ((~src & pat) | dest) }, 0x46: function(pat, src, dest) { return ((dest & pat) | src) ^ dest }, 0x47: function(pat, src, dest) { return~ (((pat ^ dest) & src) ^ pat) }, 0x48: function(pat, src, dest) { return (pat ^ dest) & src }, 0x49: function(pat, src, dest) { return~ (((dest & pat) | src) ^ dest ^ pat) }, 0x4a: function(pat, src, dest) { return ((dest | src) & pat) ^ dest }, 0x4b: function(pat, src, dest) { return (~src | dest) ^ pat }, 0x4c: function(pat, src, dest) { return~ (pat & dest) & src }, 0x4d: function(pat, src, dest) { return~ (((src ^ dest) | (src ^ pat)) ^ src) }, 0x4e: function(pat, src, dest) { return ((pat ^ src) | dest) ^ pat }, 0x4f: function(pat, src, dest) { return~ ((~src | dest) & pat) }, 0x51: function(pat, src, dest) { return~ ((~pat & src) | dest) }, 0x52: function(pat, src, dest) { return ((dest & src) | pat) ^ dest }, 0x53: function(pat, src, dest) { return~ (((src ^ dest) & pat) ^ src) }, 0x54: function(pat, src, dest) { return~ (~(src | pat) | dest) }, 0x56: function(pat, src, dest) { return (src | pat) ^ dest }, 0x57: function(pat, src, dest) { return~ ((src | pat) & dest) }, 0x58: function(pat, src, dest) { return ((pat | src) & dest) ^ pat }, 0x59: function(pat, src, dest) { return (~src | pat) ^ dest }, 0x5b: function(pat, src, dest) { return (~(dest | src) | pat) ^ dest }, 0x5c: function(pat, src, dest) { return ((dest ^ src) | pat) ^ dest }, 0x5d: function(pat, src, dest) { return~ ((~src | pat) & dest) }, 0x5e: function(pat, src, dest) { return ((~dest & src) | pat) ^ dest }, 0x60: function(pat, src, dest) { return (src ^ dest) & pat }, 0x61: function(pat, src, dest) { return~ (((src & dest) | pat) ^ src ^ dest) }, 0x62: function(pat, src, dest) { return ((dest | pat) & src) ^ dest }, 0x63: function(pat, src, dest) { return (~pat | dest) ^ src }, 0x64: function(pat, src, dest) { return ((src | pat) & dest) ^ src }, 0x65: function(pat, src, dest) { return (~pat | src) ^ dest }, 0x67: function(pat, src, dest) { return (~(src | pat) | dest) ^ src }, 0x68: function(pat, src, dest) { return~ ((~(src | dest) | pat) ^ src ^ dest) }, 0x69: function(pat, src, dest) { return~ (src ^ dest ^ pat) }, 0x6a: function(pat, src, dest) { return (src & pat) ^ dest }, 0x6b: function(pat, src, dest) { return~ (((src | pat) & dest) ^ src ^ pat) }, 0x6c: function(pat, src, dest) { return (pat & dest) ^ src }, 0x6d: function(pat, src, dest) { return~ (((dest | pat) & src) ^ dest ^ pat) }, 0x6e: function(pat, src, dest) { return ((~src | pat) & dest) ^ src }, 0x6f: function(pat, src, dest) { return~ (~(src ^ dest) & pat) }, 0x70: function(pat, src, dest) { return~ (src & dest) & pat }, 0x71: function(pat, src, dest) { return~ (((dest ^ pat) & (src ^ dest)) ^ src) }, 0x72: function(pat, src, dest) { return ((src ^ pat) | dest) ^ src }, 0x73: function(pat, src, dest) { return~ ((~pat | dest) & src) }, 0x74: function(pat, src, dest) { return ((dest ^ pat) | src) ^ dest }, 0x75: function(pat, src, dest) { return~ ((~pat | src) & dest) }, 0x76: function(pat, src, dest) { return ((~src & pat) | dest) ^ src }, 0x78: function(pat, src, dest) { return (src & dest) ^ pat }, 0x79: function(pat, src, dest) { return~ (((src | dest) & pat) ^ src ^ dest) }, 0x7a: function(pat, src, dest) { return ((~dest | src) & pat) ^ dest }, 0x7b: function(pat, src, dest) { return~ (~(pat ^ dest) & src) }, 0x7c: function(pat, src, dest) { return ((~src | dest) & pat) ^ src }, 0x7d: function(pat, src, dest) { return~ (~(src ^ pat) & dest) }, 0x7e: function(pat, src, dest) { return (src ^ dest) | (pat ^ src) }, 0x7f: function(pat, src, dest) { return~ (src & pat & dest) }, 0x80: function(pat, src, dest) { return src & pat & dest }, 0x81: function(pat, src, dest) { return~ ((src ^ dest) | (pat ^ src)) }, 0x82: function(pat, src, dest) { return~ (src ^ pat) & dest }, 0x83: function(pat, src, dest) { return~ (((~src | dest) & pat) ^ src) }, 0x84: function(pat, src, dest) { return~ (pat ^ dest) & src }, 0x85: function(pat, src, dest) { return~ (((~pat | src) & dest) ^ pat) }, 0x86: function(pat, src, dest) { return ((src | dest) & pat) ^ src ^ dest }, 0x87: function(pat, src, dest) { return~ ((src & dest) ^ pat) }, 0x89: function(pat, src, dest) { return~ (((~src & pat) | dest) ^ src) }, 0x8a: function(pat, src, dest) { return (~pat | src) & dest }, 0x8b: function(pat, src, dest) { return~ (((dest ^ pat) | src) ^ dest) }, 0x8c: function(pat, src, dest) { return (~pat | dest) & src }, 0x8d: function(pat, src, dest) { return~ (((src ^ pat) | dest) ^ src) }, 0x8e: function(pat, src, dest) { return ((dest ^ pat) & (dest ^ src)) ^ src }, 0x8f: function(pat, src, dest) { return~ (~(src & dest) & pat) }, 0x90: function(pat, src, dest) { return~ (src ^ dest) & pat }, 0x91: function(pat, src, dest) { return~ (((~src | pat) & dest) ^ src) }, 0x92: function(pat, src, dest) { return ((pat | dest) & src) ^ pat ^ dest }, 0x93: function(pat, src, dest) { return~ ((dest & pat) ^ src) }, 0x94: function(pat, src, dest) { return ((src | pat) & dest) ^ src ^ pat }, 0x95: function(pat, src, dest) { return~ ((src & pat) ^ dest) }, 0x96: function(pat, src, dest) { return src ^ pat ^ dest }, 0x97: function(pat, src, dest) { return (~(src | pat) | dest) ^ src ^ pat }, 0x98: function(pat, src, dest) { return~ ((~(src | pat) | dest) ^ src) }, 0x9a: function(pat, src, dest) { return (~src & pat) ^ dest }, 0x9b: function(pat, src, dest) { return~ (((src | pat) & dest) ^ src) }, 0x9c: function(pat, src, dest) { return (~dest & pat) ^ src }, 0x9d: function(pat, src, dest) { return~ (((dest | pat) & src) ^ dest) }, 0x9e: function(pat, src, dest) { return ((src & dest) | pat) ^ src ^ dest }, 0x9f: function(pat, src, dest) { return~ ((src ^ dest) & pat) }, 0xa1: function(pat, src, dest) { return~ (((~pat & src) | dest) ^ pat) }, 0xa2: function(pat, src, dest) { return (~src | pat) & dest }, 0xa3: function(pat, src, dest) { return~ (((dest ^ src) | pat) ^ dest) }, 0xa4: function(pat, src, dest) { return~ ((~(pat | src) | dest) ^ pat) }, 0xa6: function(pat, src, dest) { return (~pat & src) ^ dest }, 0xa7: function(pat, src, dest) { return~ (((pat | src) & dest) ^ pat) }, 0xa8: function(pat, src, dest) { return (src | pat) & dest }, 0xa9: function(pat, src, dest) { return~ ((src | pat) ^ dest) }, 0xab: function(pat, src, dest) { return~ (src | pat) | dest }, 0xac: function(pat, src, dest) { return ((src ^ dest) & pat) ^ src }, 0xad: function(pat, src, dest) { return~ (((dest & src) | pat) ^ dest) }, 0xae: function(pat, src, dest) { return (~pat & src) | dest }, 0xb0: function(pat, src, dest) { return (~src | dest) & pat }, 0xb1: function(pat, src, dest) { return~ (((pat ^ src) | dest) ^ pat) }, 0xb2: function(pat, src, dest) { return ((src ^ dest) | (pat ^ src)) ^ src }, 0xb3: function(pat, src, dest) { return~ (~(pat & dest) & src) }, 0xb4: function(pat, src, dest) { return (~dest & src) ^ pat }, 0xb5: function(pat, src, dest) { return~ (((dest | src) & pat) ^ dest) }, 0xb6: function(pat, src, dest) { return ((pat & dest) | src) ^ pat ^ dest }, 0xb7: function(pat, src, dest) { return~ ((pat ^ dest) & src) }, 0xb8: function(pat, src, dest) { return ((dest ^ pat) & src) ^ pat }, 0xb9: function(pat, src, dest) { return~ (((dest & pat) | src) ^ dest) }, 0xba: function(pat, src, dest) { return (~src & pat) | dest }, 0xbc: function(pat, src, dest) { return (~(src & dest) & pat) ^ src }, 0xbd: function(pat, src, dest) { return~ ((dest ^ pat) & (dest ^ src)) }, 0xbe: function(pat, src, dest) { return (src ^ pat) | dest }, 0xbf: function(pat, src, dest) { return~ (src & pat) | dest }, 0xc1: function(pat, src, dest) { return~ (((~src & dest) | pat) ^ src) }, 0xc2: function(pat, src, dest) { return~ ((~(src | dest) | pat) ^ src) }, 0xc4: function(pat, src, dest) { return (~dest | pat) & src }, 0xc5: function(pat, src, dest) { return~ (((src ^ dest) | pat) ^ src) }, 0xc6: function(pat, src, dest) { return (~pat & dest) ^ src }, 0xc7: function(pat, src, dest) { return~ (((pat | dest) & src) ^ pat) }, 0xc8: function(pat, src, dest) { return (pat | dest) & src }, 0xc9: function(pat, src, dest) { return~ ((dest | pat) ^ src) }, 0xca: function(pat, src, dest) { return ((dest ^ src) & pat) ^ dest }, 0xcb: function(pat, src, dest) { return~ (((src & dest) | pat) ^ src) }, 0xcd: function(pat, src, dest) { return~ (pat | dest) | src }, 0xce: function(pat, src, dest) { return (~pat & dest) | src }, 0xd0: function(pat, src, dest) { return (~dest | src) & pat }, 0xd1: function(pat, src, dest) { return~ (((pat ^ dest) | src) ^ pat) }, 0xd2: function(pat, src, dest) { return (~src & dest) ^ pat }, 0xd3: function(pat, src, dest) { return~ (((src | dest) & pat) ^ src) }, 0xd4: function(pat, src, dest) { return ((dest ^ pat) & (pat ^ src)) ^ src }, 0xd5: function(pat, src, dest) { return~ (~(src & pat) & dest) }, 0xd6: function(pat, src, dest) { return ((src & pat) | dest) ^ src ^ pat }, 0xd7: function(pat, src, dest) { return~ ((src ^ pat) & dest) }, 0xd8: function(pat, src, dest) { return ((pat ^ src) & dest) ^ pat }, 0xd9: function(pat, src, dest) { return~ (((src & pat) | dest) ^ src) }, 0xda: function(pat, src, dest) { return (~(dest & src) & pat) ^ dest }, 0xdb: function(pat, src, dest) { return~ ((src ^ dest) & (pat ^ src)) }, 0xdc: function(pat, src, dest) { return (~dest & pat) | src }, 0xde: function(pat, src, dest) { return (pat ^ dest) | src }, 0xdf: function(pat, src, dest) { return~ (pat & dest) | src }, 0xe0: function(pat, src, dest) { return (src | dest) & pat }, 0xe1: function(pat, src, dest) { return~ ((src | dest) ^ pat) }, 0xe2: function(pat, src, dest) { return ((dest ^ pat) & src) ^ dest }, 0xe3: function(pat, src, dest) { return~ (((pat & dest) | src) ^ pat) }, 0xe4: function(pat, src, dest) { return ((src ^ pat) & dest) ^ src }, 0xe5: function(pat, src, dest) { return~ (((pat & src) | dest) ^ pat) }, 0xe6: function(pat, src, dest) { return (~(src & pat) & dest) ^ src }, 0xe7: function(pat, src, dest) { return~ ((dest ^ pat) & (pat ^ src)) }, 0xe8: function(pat, src, dest) { return ((src ^ dest) & (pat ^ src)) ^ src }, 0xe9: function(pat, src, dest) { return~ ((~(src & dest) & pat) ^ src ^ dest) }, 0xea: function(pat, src, dest) { return (src & pat) | dest }, 0xeb: function(pat, src, dest) { return~ (src ^ pat) | dest }, 0xec: function(pat, src, dest) { return (pat & dest) | src }, 0xed: function(pat, src, dest) { return~ (pat ^ dest) | src }, 0xef: function(pat, src, dest) { return~ pat | dest | src }, 0xf1: function(pat, src, dest) { return~ (src | dest) | pat }, 0xf2: function(pat, src, dest) { return (~src & dest) | pat }, 0xf4: function(pat, src, dest) { return (~dest & src) | pat }, 0xf6: function(pat, src, dest) { return (src ^ dest) | pat }, 0xf7: function(pat, src, dest) { return~ (src & dest) | pat }, 0xf8: function(pat, src, dest) { return (src & dest) | pat }, 0xf9: function(pat, src, dest) { return~ (src ^ dest) | pat }, 0xfb: function(pat, src, dest) { return~ src | pat | dest }, 0xfd: function(pat, src, dest) { return~ dest | src | pat }, 0xfe: function(pat, src, dest) { return src | pat | dest } };