aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-02-19 15:48:17 +0100
committerPierre Ossman <ossman@cendio.se>2017-02-22 16:58:10 +0100
commit6a1a0d0c578e39338e757edf59cf8806a9d86b0f (patch)
treea82ede30f7e9d1f36b3169acb6a7a6a4f936ad78 /common
parente20cf62bbdefd48979603105d60c3a170eb2ece6 (diff)
downloadtigervnc-6a1a0d0c578e39338e757edf59cf8806a9d86b0f.tar.gz
tigervnc-6a1a0d0c578e39338e757edf59cf8806a9d86b0f.zip
Change cursor API to use RGBA data
This will allow us to use better formats that preserve the entire alpha channel.
Diffstat (limited to 'common')
-rw-r--r--common/rfb/CMsgHandler.h2
-rw-r--r--common/rfb/CMsgReader.cxx29
-rw-r--r--common/rfb/ConnParams.cxx15
-rw-r--r--common/rfb/ConnParams.h4
-rw-r--r--common/rfb/Cursor.cxx203
-rw-r--r--common/rfb/Cursor.h35
-rw-r--r--common/rfb/PixelBuffer.cxx104
-rw-r--r--common/rfb/PixelBuffer.h14
-rw-r--r--common/rfb/SMsgWriter.cxx56
-rw-r--r--common/rfb/SMsgWriter.h1
-rw-r--r--common/rfb/VNCSConnectionST.cxx2
-rw-r--r--common/rfb/VNCServer.h12
-rw-r--r--common/rfb/VNCServerST.cxx24
-rw-r--r--common/rfb/VNCServerST.h4
14 files changed, 190 insertions, 315 deletions
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 7d2cdc20..2686712e 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -50,7 +50,7 @@ namespace rfb {
int w, int h,
const ScreenSet& layout);
virtual void setCursor(int width, int height, const Point& hotspot,
- void* data, void* mask) = 0;
+ const rdr::U8* data) = 0;
virtual void setPixelFormat(const PixelFormat& pf);
virtual void setName(const char* name);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index 96ddf443..bbb99096 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -198,10 +198,35 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
rdr::U8Array data(data_len);
rdr::U8Array mask(mask_len);
+ int x, y;
+ rdr::U8 buf[width*height*4];
+ rdr::U8* in;
+ rdr::U8* out;
+
is->readBytes(data.buf, data_len);
is->readBytes(mask.buf, mask_len);
- handler->setCursor(width, height, hotspot, data.buf, mask.buf);
+ int maskBytesPerRow = (width+7)/8;
+ in = data.buf;
+ out = buf;
+ for (y = 0;y < height;y++) {
+ for (x = 0;x < width;x++) {
+ int byte = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+
+ handler->cp.pf().rgbFromBuffer(out, in, 1);
+
+ if (mask.buf[byte] & (1 << bit))
+ out[3] = 255;
+ else
+ out[3] = 0;
+
+ in += handler->cp.pf().bpp/8;
+ out += 4;
+ }
+ }
+
+ handler->setCursor(width, height, hotspot, buf);
}
void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index ab3b884a..dc9ebf58 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -39,11 +39,13 @@ ConnParams::ConnParams()
subsampling(subsampleUndefined), name_(0), verStrPos(0)
{
setName("");
+ cursor_ = new Cursor(0, 0, Point(), NULL);
}
ConnParams::~ConnParams()
{
delete [] name_;
+ delete cursor_;
}
bool ConnParams::readVersion(rdr::InStream* is, bool* done)
@@ -86,17 +88,8 @@ void ConnParams::setName(const char* name)
void ConnParams::setCursor(const Cursor& other)
{
- const rdr::U8* data;
- int stride;
-
- cursor_.hotspot = other.hotspot;
- cursor_.setPF(other.getPF());
- cursor_.setSize(other.width(), other.height());
-
- data = other.getBuffer(other.getRect(), &stride);
- cursor_.imageRect(cursor_.getRect(), data, stride);
-
- memcpy(cursor_.mask.buf, other.mask.buf, cursor_.maskLen());
+ delete cursor_;
+ cursor_ = new Cursor(other);
}
bool ConnParams::supportsEncoding(rdr::S32 encoding) const
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index 9e647baa..517e6490 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -77,7 +77,7 @@ namespace rfb {
const char* name() const { return name_; }
void setName(const char* name);
- const Cursor& cursor() const { return cursor_; }
+ const Cursor& cursor() const { return *cursor_; }
void setCursor(const Cursor& cursor);
bool supportsEncoding(rdr::S32 encoding) const;
@@ -106,7 +106,7 @@ namespace rfb {
PixelFormat pf_;
char* name_;
- Cursor cursor_;
+ Cursor* cursor_;
std::set<rdr::S32> encodings_;
char verStr[13];
int verStrPos;
diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx
index e226118c..a79f0460 100644
--- a/common/rfb/Cursor.cxx
+++ b/common/rfb/Cursor.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,71 +26,63 @@ using namespace rfb;
static LogWriter vlog("Cursor");
-void Cursor::setSize(int w, int h) {
- int oldMaskLen = maskLen();
- ManagedPixelBuffer::setSize(w, h);
- if (maskLen() > oldMaskLen) {
- delete [] mask.buf;
- mask.buf = new rdr::U8[maskLen()];
- }
+Cursor::Cursor(int width, int height, const Point& hotspot,
+ const rdr::U8* data) :
+ width_(width), height_(height), hotspot_(hotspot)
+{
+ this->data = new rdr::U8[width_*height_*4];
+ memcpy(this->data, data, width_*height_*4);
}
-void Cursor::drawOutline(const Pixel& c)
+Cursor::Cursor(const Cursor& other) :
+ width_(other.width_), height_(other.height_),
+ hotspot_(other.hotspot_)
{
- Cursor outlined;
- rdr::U8 cbuf[4];
-
- // Create a mirror of the existing cursor
- outlined.setPF(getPF());
- outlined.setSize(width(), height());
- outlined.hotspot = hotspot;
+ data = new rdr::U8[width_*height_*4];
+ memcpy(data, other.data, width_*height_*4);
+}
- // Clear the mirror's background to the outline colour
- outlined.getPF().bufferFromPixel(cbuf, c);
- outlined.fillRect(getRect(), cbuf);
+Cursor::~Cursor()
+{
+ delete [] data;
+}
- // Blit the existing cursor, using its mask
- outlined.maskRect(getRect(), data, mask.buf);
+rdr::U8* Cursor::getBitmap() const
+{
+ rdr::U8Array source((width()+7)/8*height());
+ memset(source.buf, 0, (width()+7)/8*height());
- // Now just adjust the mask to add the outline. The outline pixels
- // will already be the right colour. :)
int maskBytesPerRow = (width() + 7) / 8;
+ const rdr::U8 *data_ptr = data;
for (int y = 0; y < height(); y++) {
- for (int byte=0; byte<maskBytesPerRow; byte++) {
- rdr::U8 m8 = mask.buf[y*maskBytesPerRow + byte];
-
- // Handle above & below outline
- if (y > 0) m8 |= mask.buf[(y-1)*maskBytesPerRow + byte];
- if (y < height()-1) m8 |= mask.buf[(y+1)*maskBytesPerRow + byte];
-
- // Left outline
- m8 |= mask.buf[y*maskBytesPerRow + byte] << 1;
- if (byte < maskBytesPerRow-1)
- m8 |= (mask.buf[y*maskBytesPerRow + byte + 1] >> 7) & 1;
-
- // Right outline
- m8 |= mask.buf[y*maskBytesPerRow + byte] >> 1;
- if (byte > 0)
- m8 |= (mask.buf[y*maskBytesPerRow + byte - 1] << 7) & 128;
-
- outlined.mask.buf[y*maskBytesPerRow + byte] = m8;
+ for (int x = 0; x < width(); x++) {
+ int byte = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+ if (data_ptr[3] >= 0x80) {
+ // Use Luma with BT.709 coefficients for grayscale
+ unsigned luma;
+
+ luma = 0;
+ luma += (unsigned)data_ptr[0] * 13933; // 0.2126
+ luma += (unsigned)data_ptr[1] * 46871; // 0.7152
+ luma += (unsigned)data_ptr[2] * 4732; // 0.0722
+ luma /= 65536;
+
+ // Gamma compensated half intensity gray
+ if (luma > 187)
+ source.buf[byte] |= (1 << bit);
+ }
+ data_ptr += 4;
}
}
- // Replace the existing cursor & mask with the new one
- delete [] data;
- delete [] mask.buf;
- data = outlined.data; outlined.data = 0;
- mask.buf = outlined.mask.buf; outlined.mask.buf = 0;
+ return source.takeBuf();
}
-rdr::U8* Cursor::getBitmap(Pixel* pix0, Pixel* pix1) const
+rdr::U8* Cursor::getMask() const
{
- bool gotPix0 = false;
- bool gotPix1 = false;
- *pix0 = *pix1 = 0;
- rdr::U8Array source(maskLen());
- memset(source.buf, 0, maskLen());
+ rdr::U8Array mask((width()+7)/8*height());
+ memset(mask.buf, 0, (width()+7)/8*height());
int maskBytesPerRow = (width() + 7) / 8;
const rdr::U8 *data_ptr = data;
@@ -98,24 +90,13 @@ rdr::U8* Cursor::getBitmap(Pixel* pix0, Pixel* pix1) const
for (int x = 0; x < width(); x++) {
int byte = y * maskBytesPerRow + x / 8;
int bit = 7 - x % 8;
- if (mask.buf[byte] & (1 << bit)) {
- Pixel pix = getPF().pixelFromBuffer(data_ptr);
- if (!gotPix0 || pix == *pix0) {
- gotPix0 = true;
- *pix0 = pix;
- } else if (!gotPix1 || pix == *pix1) {
- gotPix1 = true;
- *pix1 = pix;
- source.buf[byte] |= (1 << bit);
- } else {
- // not a bitmap
- return 0;
- }
- }
- data_ptr += getPF().bpp/8;
+ if (data_ptr[3] >= 0x80)
+ mask.buf[byte] |= (1 << bit);
+ data_ptr += 4;
}
}
- return source.takeBuf();
+
+ return mask.takeBuf();
}
// crop() determines the "busy" rectangle for the cursor - the minimum bounding
@@ -126,58 +107,40 @@ rdr::U8* Cursor::getBitmap(Pixel* pix0, Pixel* pix1) const
void Cursor::crop()
{
- Rect busy = getRect().intersect(Rect(hotspot.x, hotspot.y,
- hotspot.x+1, hotspot.y+1));
- int maskBytesPerRow = (width() + 7) / 8;
+ Rect busy = Rect(0, 0, width_, height_);
+ busy = busy.intersect(Rect(hotspot_.x, hotspot_.y,
+ hotspot_.x+1, hotspot_.y+1));
int x, y;
+ rdr::U8 *data_ptr = data;
for (y = 0; y < height(); y++) {
for (x = 0; x < width(); x++) {
- int byte = y * maskBytesPerRow + x / 8;
- int bit = 7 - x % 8;
- if (mask.buf[byte] & (1 << bit)) {
+ if (data_ptr[3] > 0) {
if (x < busy.tl.x) busy.tl.x = x;
if (x+1 > busy.br.x) busy.br.x = x+1;
if (y < busy.tl.y) busy.tl.y = y;
if (y+1 > busy.br.y) busy.br.y = y+1;
}
+ data_ptr += 4;
}
}
if (width() == busy.width() && height() == busy.height()) return;
- vlog.debug("cropping %dx%d to %dx%d", width(), height(),
- busy.width(), busy.height());
-
// Copy the pixel data
- int newDataLen = busy.area() * (getPF().bpp/8);
+ int newDataLen = busy.area() * 4;
rdr::U8* newData = new rdr::U8[newDataLen];
- getImage(newData, busy);
-
- // Copy the mask
- int newMaskBytesPerRow = (busy.width()+7)/8;
- int newMaskLen = newMaskBytesPerRow * busy.height();
- rdr::U8* newMask = new rdr::U8[newMaskLen];
- memset(newMask, 0, newMaskLen);
- for (y = 0; y < busy.height(); y++) {
- int newByte, newBit;
- for (x = 0; x < busy.width(); x++) {
- int oldByte = (y+busy.tl.y) * maskBytesPerRow + (x+busy.tl.x) / 8;
- int oldBit = 7 - (x+busy.tl.x) % 8;
- newByte = y * newMaskBytesPerRow + x / 8;
- newBit = 7 - x % 8;
- if (mask.buf[oldByte] & (1 << oldBit))
- newMask[newByte] |= (1 << newBit);
- }
+ data_ptr = newData;
+ for (y = busy.tl.y; y < busy.br.y; y++) {
+ memcpy(data_ptr, data + y*width()*4 + busy.tl.x*4, busy.width()*4);
+ data_ptr += busy.width()*4;
}
// Set the size and data to the new, cropped cursor.
- setSize(busy.width(), busy.height());
- hotspot = hotspot.subtract(busy.tl);
+ width_ = busy.width();
+ height_ = busy.height();
+ hotspot_ = hotspot_.subtract(busy.tl);
delete [] data;
- delete [] mask.buf;
- datasize = newDataLen;
data = newData;
- mask.buf = newMask;
}
RenderedCursor::RenderedCursor()
@@ -207,26 +170,48 @@ void RenderedCursor::update(PixelBuffer* framebuffer,
assert(framebuffer);
assert(cursor);
- if (!framebuffer->getPF().equal(cursor->getPF()))
- throw Exception("RenderedCursor: Trying to render cursor on incompatible frame buffer");
-
format = framebuffer->getPF();
width_ = framebuffer->width();
height_ = framebuffer->height();
- rawOffset = pos.subtract(cursor->hotspot);
- clippedRect = cursor->getRect(rawOffset).intersect(framebuffer->getRect());
+ rawOffset = pos.subtract(cursor->hotspot());
+ clippedRect = Rect(0, 0, cursor->width(), cursor->height())
+ .translate(rawOffset)
+ .intersect(framebuffer->getRect());
offset = clippedRect.tl;
- buffer.setPF(cursor->getPF());
+ buffer.setPF(format);
buffer.setSize(clippedRect.width(), clippedRect.height());
data = framebuffer->getBuffer(buffer.getRect(offset), &stride);
buffer.imageRect(buffer.getRect(), data, stride);
diff = offset.subtract(rawOffset);
- data = cursor->getBuffer(buffer.getRect(diff), &stride);
+ for (int y = 0;y < buffer.height();y++) {
+ for (int x = 0;x < buffer.width();x++) {
+ size_t idx;
+ rdr::U8 bg[4], fg[4];
+ rdr::U8 rgb[3];
+
+ idx = (y+diff.y)*cursor->width() + (x+diff.x);
+ memcpy(fg, cursor->getBuffer() + idx*4, 4);
+
+ if (fg[3] == 0x00)
+ continue;
+ else if (fg[3] == 0xff) {
+ memcpy(rgb, fg, 3);
+ } else {
+ buffer.getImage(bg, Rect(x, y, x+1, y+1));
+ format.rgbFromBuffer(rgb, bg, 1);
+ // FIXME: Gamma aware blending
+ for (int i = 0;i < 3;i++) {
+ rgb[i] = (unsigned)rgb[i]*(255-fg[3])/255 +
+ (unsigned)fg[i]*fg[3]/255;
+ }
+ }
- buffer.maskRect(buffer.getRect(), data, cursor->mask.buf, diff,
- stride, (cursor->width() + 7) / 8);
+ format.bufferFromRGB(bg, rgb, 1);
+ buffer.imageRect(Rect(x, y, x+1, y+1), bg);
+ }
+ }
}
diff --git a/common/rfb/Cursor.h b/common/rfb/Cursor.h
index 560e4d81..6c6db7ee 100644
--- a/common/rfb/Cursor.h
+++ b/common/rfb/Cursor.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2014 Pierre Ossman for Cendio AB
+ * Copyright 2014-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,29 +28,30 @@
namespace rfb {
- class Cursor : public ManagedPixelBuffer {
+ class Cursor {
public:
- Cursor() {}
- rdr::U8Array mask;
- Point hotspot;
+ Cursor(int width, int height, const Point& hotspot, const rdr::U8* data);
+ Cursor(const Cursor& other);
+ ~Cursor();
- int maskLen() const { return (width() + 7) / 8 * height(); }
+ int width() const { return width_; };
+ int height() const { return height_; };
+ const Point& hotspot() const { return hotspot_; };
+ const rdr::U8* getBuffer() const { return data; };
- // setSize() resizes the cursor. The contents of the data and mask are
- // undefined after this call.
- virtual void setSize(int w, int h);
-
- // drawOutline() adds an outline to the cursor in the given colour.
- void drawOutline(const Pixel& c);
-
- // getBitmap() tests whether the cursor is monochrome, and if so returns a
- // bitmap together with background and foreground colours. The size and
- // layout of the bitmap are the same as the mask.
- rdr::U8* getBitmap(Pixel* pix0, Pixel* pix1) const;
+ // getBitmap() returns a monochrome version of the cursor
+ rdr::U8* getBitmap() const;
+ // getMask() returns a simple mask version of the alpha channel
+ rdr::U8* getMask() const;
// crop() crops the cursor down to the smallest possible size, based on the
// mask.
void crop();
+
+ protected:
+ int width_, height_;
+ Point hotspot_;
+ rdr::U8* data;
};
class RenderedCursor : public PixelBuffer {
diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx
index e788fcad..1edd9c3d 100644
--- a/common/rfb/PixelBuffer.cxx
+++ b/common/rfb/PixelBuffer.cxx
@@ -200,110 +200,6 @@ void ModifiablePixelBuffer::imageRect(const Rect& r,
commitBufferRW(r);
}
-void ModifiablePixelBuffer::maskRect(const Rect& r,
- const void* pixels,
- const void* mask_,
- const Point& maskPos,
- int pStride, int mStride)
-{
- int stride;
- U8* data;
- U8* mask;
- int w, h, bpp;
-
- if (!r.enclosed_by(getRect()))
- throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y, width_, height_);
-
- data = getBufferRW(r, &stride);
- mask = (U8*) mask_;
-
- w = r.width();
- h = r.height();
- bpp = getPF().bpp;
- if (pStride == 0)
- pStride = r.width();
- if (mStride == 0)
- mStride = (r.width() + 7) / 8;
-
- mask += maskPos.y * mStride;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int cx = maskPos.x + x;
- U8* byte = mask + (cx / 8);
- int bit = 7 - cx % 8;
- if ((*byte) & (1 << bit)) {
- switch (bpp) {
- case 8:
- ((U8*)data)[y * stride + x] = ((U8*)pixels)[y * pStride + x];
- break;
- case 16:
- ((U16*)data)[y * stride + x] = ((U16*)pixels)[y * pStride + x];
- break;
- case 32:
- ((U32*)data)[y * stride + x] = ((U32*)pixels)[y * pStride + x];
- break;
- }
- }
- }
- mask += mStride;
- }
-
- commitBufferRW(r);
-}
-
-void ModifiablePixelBuffer::maskRect(const Rect& r,
- Pixel pixel,
- const void* mask_,
- const Point& maskPos,
- int mStride)
-{
- int stride;
- U8* data;
- U8* mask;
- int w, h, bpp;
-
- if (!r.enclosed_by(getRect()))
- throw rfb::Exception("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y, width_, height_);
-
- data = getBufferRW(r, &stride);
- mask = (U8*) mask_;
-
- w = r.width();
- h = r.height();
- bpp = getPF().bpp;
- if (mStride == 0)
- mStride = (r.width() + 7) / 8;
-
- mask += maskPos.y * mStride;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int cx = maskPos.x + x;
- U8* byte = mask + (cx / 8);
- int bit = 7 - cx % 8;
- if ((*byte) & (1 << bit)) {
- switch (bpp) {
- case 8:
- ((U8*)data)[y * stride + x] = pixel;
- break;
- case 16:
- ((U16*)data)[y * stride + x] = pixel;
- break;
- case 32:
- ((U32*)data)[y * stride + x] = pixel;
- break;
- }
- }
- }
- mask += mStride;
- }
-
- commitBufferRW(r);
-}
-
void ModifiablePixelBuffer::copyRect(const Rect &rect,
const Point &move_by_delta)
{
diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h
index b38999ae..75caa63f 100644
--- a/common/rfb/PixelBuffer.h
+++ b/common/rfb/PixelBuffer.h
@@ -127,20 +127,6 @@ namespace rfb {
// Copy pixel data from one PixelBuffer location to another
void copyRect(const Rect &dest, const Point& move_by_delta);
- // Copy pixel data to the buffer through a mask
- // pixels is a pointer to the pixel to be copied to r.tl.
- // maskPos specifies the pixel offset in the mask to start from.
- // mask_ is a pointer to the mask bits at (0,0).
- // pStride and mStride are the strides of the pixel and mask buffers.
- void maskRect(const Rect& r, const void* pixels, const void* mask_,
- const Point& maskPos=Point(0, 0),
- int pStride=0, int mStride=0);
-
- // pixel is the Pixel value to be used where mask_ is set
- void maskRect(const Rect& r, Pixel pixel, const void* mask_,
- const Point& maskPos=Point(0, 0),
- int mStride=0);
-
// Render in a specific format
// Does the exact same thing as the above methods, but the given
// pixel values are defined by the given PixelFormat.
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 5040b658..51e1105a 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -1,6 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -301,38 +301,36 @@ void SMsgWriter::endMsg()
void SMsgWriter::writePseudoRects()
{
if (needSetCursor) {
- rdr::U8* data;
-
const Cursor& cursor = cp->cursor();
- data = new rdr::U8[cursor.area() * cp->pf().bpp/8];
- cursor.getImage(cp->pf(), data, cursor.getRect());
+ rdr::U8Array data(cursor.width()*cursor.height() * cp->pf().bpp/8);
+ rdr::U8Array mask(cursor.getMask());
+
+ const rdr::U8* in;
+ rdr::U8* out;
+
+ in = cursor.getBuffer();
+ out = data.buf;
+ for (int i = 0;i < cursor.width()*cursor.height();i++) {
+ cp->pf().bufferFromRGB(out, in, 1);
+ in += 4;
+ out += cp->pf().bpp/8;
+ }
writeSetCursorRect(cursor.width(), cursor.height(),
- cursor.hotspot.x, cursor.hotspot.y,
- data, cursor.mask.buf);
+ cursor.hotspot().x, cursor.hotspot().y,
+ data.buf, mask.buf);
needSetCursor = false;
-
- delete [] data;
}
if (needSetXCursor) {
const Cursor& cursor = cp->cursor();
- Pixel pix0, pix1;
- rdr::U8 rgb0[3], rgb1[3];
- rdr::U8Array bitmap(cursor.getBitmap(&pix0, &pix1));
-
- if (!bitmap.buf) {
- // FIXME: We could reduce to two colors.
- throw Exception("SMsgWriter::writePseudoRects: Unable to send multicolor cursor: RichCursor not supported by client");
- }
-
- cp->pf().rgbFromPixel(pix0, &rgb0[0], &rgb0[1], &rgb0[2]);
- cp->pf().rgbFromPixel(pix1, &rgb1[0], &rgb1[1], &rgb1[2]);
+ rdr::U8Array bitmap(cursor.getBitmap());
+ rdr::U8Array mask(cursor.getMask());
writeSetXCursorRect(cursor.width(), cursor.height(),
- cursor.hotspot.x, cursor.hotspot.y,
- rgb0, rgb1, bitmap.buf, cursor.mask.buf);
+ cursor.hotspot().x, cursor.hotspot().y,
+ bitmap.buf, mask.buf);
needSetXCursor = false;
}
@@ -452,8 +450,6 @@ void SMsgWriter::writeSetCursorRect(int width, int height,
void SMsgWriter::writeSetXCursorRect(int width, int height,
int hotspotX, int hotspotY,
- const rdr::U8 pix0[],
- const rdr::U8 pix1[],
const void* data, const void* mask)
{
if (!cp->supportsLocalXCursor)
@@ -467,12 +463,12 @@ void SMsgWriter::writeSetXCursorRect(int width, int height,
os->writeU16(height);
os->writeU32(pseudoEncodingXCursor);
if (width * height) {
- os->writeU8(pix0[0]);
- os->writeU8(pix0[1]);
- os->writeU8(pix0[2]);
- os->writeU8(pix1[0]);
- os->writeU8(pix1[1]);
- os->writeU8(pix1[2]);
+ os->writeU8(255);
+ os->writeU8(255);
+ os->writeU8(255);
+ os->writeU8(0);
+ os->writeU8(0);
+ os->writeU8(0);
os->writeBytes(data, (width+7)/8 * height);
os->writeBytes(mask, (width+7)/8 * height);
}
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 917b933c..a516e103 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -126,7 +126,6 @@ namespace rfb {
const void* data, const void* mask);
void writeSetXCursorRect(int width, int height,
int hotspotX, int hotspotY,
- const rdr::U8 pix0[], const rdr::U8 pix1[],
const void* data, const void* mask);
ConnParams* cp;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 74c40d15..e7a5dcf1 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -1119,7 +1119,7 @@ void VNCSConnectionST::setCursor()
if (state() != RFBSTATE_NORMAL)
return;
- cp.setCursor(server->cursor);
+ cp.setCursor(*server->cursor);
if (!writer()->writeSetCursor()) {
if (!writer()->writeSetXCursor()) {
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index c76e5c9c..982a4ff5 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -64,16 +64,10 @@ namespace rfb {
virtual void closeClients(const char* reason) = 0;
// setCursor() tells the server that the cursor has changed. The
- // cursorData argument contains width*height pixel values in the pixel
- // buffer's format. The mask argument is a bitmask with a 1-bit meaning
- // the corresponding pixel in cursorData is valid. The mask consists of
- // left-to-right, top-to-bottom scanlines, where each scanline is padded to
- // a whole number of bytes [(width+7)/8]. Within each byte the most
- // significant bit represents the leftmost pixel, and the bytes are simply
- // in left-to-right order. The server takes its own copy of the data in
- // cursorData and mask.
+ // cursorData argument contains width*height rgba quadruplets with
+ // non-premultiplied alpha.
virtual void setCursor(int width, int height, const Point& hotspot,
- const void* cursorData, const void* mask) = 0;
+ const rdr::U8* cursorData) = 0;
// setCursorPos() tells the server the current position of the cursor.
virtual void setCursorPos(const Point& p) = 0;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index e15cd701..81eed37a 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2017 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,6 +82,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
: blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
blockCounter(0), pb(0),
name(strDup(name_)), pointerClient(0), comparer(0),
+ cursor(new Cursor(0, 0, Point(), NULL)),
renderedCursorInvalid(false),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), disableclients(false),
@@ -113,6 +114,8 @@ VNCServerST::~VNCServerST()
if (comparer)
comparer->logStats();
delete comparer;
+
+ delete cursor;
}
@@ -314,7 +317,6 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
}
comparer = new ComparingUpdateTracker(pb);
- cursor.setPF(pb->getPF());
renderedCursorInvalid = true;
// Make sure that we have at least one screen
@@ -430,14 +432,11 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta)
}
void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
- const void* data, const void* mask)
+ const rdr::U8* data)
{
- cursor.hotspot = newHotspot;
- cursor.setSize(width, height);
- cursor.imageRect(cursor.getRect(), data);
- memcpy(cursor.mask.buf, mask, cursor.maskLen());
-
- cursor.crop();
+ delete cursor;
+ cursor = new Cursor(width, height, newHotspot, data);
+ cursor->crop();
renderedCursorInvalid = true;
@@ -618,8 +617,9 @@ bool VNCServerST::checkUpdate()
Region toCheck = ui.changed.union_(ui.copied);
if (renderCursor) {
- Rect clippedCursorRect
- = cursor.getRect(cursorPos.subtract(cursor.hotspot)).intersect(pb->getRect());
+ Rect clippedCursorRect = Rect(0, 0, cursor->width(), cursor->height())
+ .translate(cursorPos.subtract(cursor->hotspot()))
+ .intersect(pb->getRect());
if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
.is_empty())) {
@@ -640,7 +640,7 @@ bool VNCServerST::checkUpdate()
comparer->getUpdateInfo(&ui, pb->getRect());
if (renderCursor) {
- renderedCursor.update(pb, &cursor, cursorPos);
+ renderedCursor.update(pb, cursor, cursorPos);
renderedCursorInvalid = false;
}
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 0ced12a4..49757164 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -98,7 +98,7 @@ namespace rfb {
virtual void add_changed(const Region &region);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void setCursor(int width, int height, const Point& hotspot,
- const void* cursorData, const void* mask);
+ const rdr::U8* data);
virtual void setCursorPos(const Point& p);
virtual void bell();
@@ -218,7 +218,7 @@ namespace rfb {
ComparingUpdateTracker* comparer;
Point cursorPos;
- Cursor cursor;
+ Cursor* cursor;
RenderedCursor renderedCursor;
bool renderedCursorInvalid;