From: Brian P. Hinz Date: Thu, 28 Nov 2019 19:22:33 +0000 (-0500) Subject: Add support for VMwareCursor pseudo encoding to Java client X-Git-Tag: v1.10.90~87 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=cc8bd384ce34d1deecbcf99ddc472243a0866e22;p=tigervnc.git Add support for VMwareCursor pseudo encoding to Java client --- diff --git a/java/com/tigervnc/rfb/CConnection.java b/java/com/tigervnc/rfb/CConnection.java index aaa2f490..3b60de57 100644 --- a/java/com/tigervnc/rfb/CConnection.java +++ b/java/com/tigervnc/rfb/CConnection.java @@ -667,6 +667,7 @@ abstract public class CConnection extends CMsgHandler { // JRE on Windows does not support alpha cursor if (!osName.contains("windows")) encodings.add(Encodings.pseudoEncodingCursorWithAlpha); + encodings.add(Encodings.pseudoEncodingVMwareCursor); encodings.add(Encodings.pseudoEncodingCursor); encodings.add(Encodings.pseudoEncodingXCursor); } diff --git a/java/com/tigervnc/rfb/CMsgReader.java b/java/com/tigervnc/rfb/CMsgReader.java index 56b761e4..c71a1e02 100644 --- a/java/com/tigervnc/rfb/CMsgReader.java +++ b/java/com/tigervnc/rfb/CMsgReader.java @@ -104,6 +104,9 @@ public class CMsgReader { case Encodings.pseudoEncodingCursorWithAlpha: readSetCursorWithAlpha(w, h, new Point(x,y)); break; + case Encodings.pseudoEncodingVMwareCursor: + readSetVMwareCursor(w, h, new Point(x,y)); + break; case Encodings.pseudoEncodingDesktopName: readSetDesktopName(x, y, w, h); break; @@ -349,6 +352,103 @@ public class CMsgReader { handler.setCursor(width, height, hotspot, buf.array()); } + protected void readSetVMwareCursor(int width, int height, Point hotspot) + { + // VMware cursor sends RGBA, java BufferedImage needs ARGB + if (width > maxCursorSize || height > maxCursorSize) + throw new Exception("Too big cursor"); + + byte type; + + type = (byte)is.readU8(); + is.skip(1); + + if (type == 0) { + int len = width * height * (handler.server.pf().bpp/8); + ByteBuffer andMask = ByteBuffer.allocate(len); + ByteBuffer xorMask = ByteBuffer.allocate(len); + + ByteBuffer data = ByteBuffer.allocate(width*height*4); + + ByteBuffer andIn; + ByteBuffer xorIn; + ByteBuffer out; + int Bpp; + + is.readBytes(andMask, len); + is.readBytes(xorMask, len); + + andIn = ByteBuffer.wrap(andMask.array()); + xorIn = ByteBuffer.wrap(xorMask.array()); + out = ByteBuffer.wrap(data.array()); + Bpp = handler.server.pf().bpp/8; + for (int y = 0;y < height;y++) { + for (int x = 0;x < width;x++) { + int andPixel, xorPixel; + + andPixel = handler.server.pf().pixelFromBuffer(andIn.duplicate()); + xorPixel = handler.server.pf().pixelFromBuffer(xorIn.duplicate()); + andIn.position(andIn.position() + Bpp); + xorIn.position(xorIn.position() + Bpp); + + if (andPixel == 0) { + byte r, g, b; + + // Opaque pixel + + r = (byte)handler.server.pf().getColorModel().getRed(xorPixel); + g = (byte)handler.server.pf().getColorModel().getGreen(xorPixel); + b = (byte)handler.server.pf().getColorModel().getBlue(xorPixel); + out.put((byte)0xff); + out.put(r); + out.put(g); + out.put(b); + } else if (xorPixel == 0) { + // Fully transparent pixel + out.put((byte)0); + out.put((byte)0); + out.put((byte)0); + out.put((byte)0); + } else if (andPixel == xorPixel) { + // Inverted pixel + + // We don't really support this, so just turn the pixel black + // FIXME: Do an outline like WinVNC does? + out.put((byte)0xff); + out.put((byte)0); + out.put((byte)0); + out.put((byte)0); + } else { + // Partially transparent/inverted pixel + + // We _really_ can't handle this, just make it black + out.put((byte)0xff); + out.put((byte)0); + out.put((byte)0); + out.put((byte)0); + } + } + } + + handler.setCursor(width, height, hotspot, data.array()); + } else if (type == 1) { + ByteBuffer data = ByteBuffer.allocate(width*height*4); + + // FIXME: Is alpha premultiplied? + ByteBuffer buf = ByteBuffer.allocate(4); + for (int i=0;i < width*height*4;i+=4) { + is.readBytes(buf,4); + data.put(buf.array(),3,1); + data.put(buf.array(),0,3); + buf.clear(); + } + + handler.setCursor(width, height, hotspot, data.array()); + } else { + throw new Exception("Unknown cursor type"); + } + } + protected void readSetDesktopName(int x, int y, int w, int h) { String name = is.readString(); @@ -425,6 +525,7 @@ public class CMsgReader { protected CMsgHandler handler; protected InStream is; protected int nUpdateRectsLeft; + protected final int maxCursorSize = 256; protected int[] imageBuf; protected int imageBufSize; } diff --git a/java/com/tigervnc/rfb/Encodings.java b/java/com/tigervnc/rfb/Encodings.java index 8a499e03..d9b713bc 100644 --- a/java/com/tigervnc/rfb/Encodings.java +++ b/java/com/tigervnc/rfb/Encodings.java @@ -59,6 +59,9 @@ public class Encodings { public static final int pseudoEncodingSubsamp8X = -764; public static final int pseudoEncodingSubsamp16X = -763; + // VMware-specific + public static final int pseudoEncodingVMwareCursor = 0x574d5664; + public static int encodingNum(String name) { if (name.equalsIgnoreCase("raw")) return encodingRaw; if (name.equalsIgnoreCase("copyRect")) return encodingCopyRect;