diff options
author | Pierre Ossman <ossman@cendio.se> | 2017-02-19 15:48:17 +0100 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2017-02-22 16:58:10 +0100 |
commit | 6a1a0d0c578e39338e757edf59cf8806a9d86b0f (patch) | |
tree | a82ede30f7e9d1f36b3169acb6a7a6a4f936ad78 /common | |
parent | e20cf62bbdefd48979603105d60c3a170eb2ece6 (diff) | |
download | tigervnc-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.h | 2 | ||||
-rw-r--r-- | common/rfb/CMsgReader.cxx | 29 | ||||
-rw-r--r-- | common/rfb/ConnParams.cxx | 15 | ||||
-rw-r--r-- | common/rfb/ConnParams.h | 4 | ||||
-rw-r--r-- | common/rfb/Cursor.cxx | 203 | ||||
-rw-r--r-- | common/rfb/Cursor.h | 35 | ||||
-rw-r--r-- | common/rfb/PixelBuffer.cxx | 104 | ||||
-rw-r--r-- | common/rfb/PixelBuffer.h | 14 | ||||
-rw-r--r-- | common/rfb/SMsgWriter.cxx | 56 | ||||
-rw-r--r-- | common/rfb/SMsgWriter.h | 1 | ||||
-rw-r--r-- | common/rfb/VNCSConnectionST.cxx | 2 | ||||
-rw-r--r-- | common/rfb/VNCServer.h | 12 | ||||
-rw-r--r-- | common/rfb/VNCServerST.cxx | 24 | ||||
-rw-r--r-- | common/rfb/VNCServerST.h | 4 |
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 ®ion); 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; |