diff options
author | Pierre Ossman <ossman@cendio.se> | 2014-07-14 16:15:16 +0200 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2014-07-14 16:15:16 +0200 |
commit | ff7a923a61154b04d8202039651a66db195affa1 (patch) | |
tree | d9b3db2ac42beb09fe831e14317ac9689a68ae73 | |
parent | 15bb3b07d86f073857bbeeadb9b1cb1a6db066e3 (diff) | |
parent | 2e5a10608394186fd1324c97b17d7f08e0c0aaf6 (diff) | |
download | tigervnc-ff7a923a61154b04d8202039651a66db195affa1.tar.gz tigervnc-ff7a923a61154b04d8202039651a66db195affa1.zip |
Merge branch 'nocolourmap' of https://github.com/CendioOssman/tigervnc
110 files changed, 1990 insertions, 3514 deletions
diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h index 6d22ac6a..760fb3dc 100644 --- a/common/rdr/InStream.h +++ b/common/rdr/InStream.h @@ -71,23 +71,6 @@ namespace rdr { inline S16 readS16() { return (S16)readU16(); } inline S32 readS32() { return (S32)readU32(); } - // readCompactLength() reads 1..3 bytes representing length of the data - // following. This method is used by the Tight decoder. - - inline unsigned int readCompactLength() { - U8 b = readU8(); - int result = (int)b & 0x7F; - if (b & 0x80) { - b = readU8(); - result |= ((int)b & 0x7F) << 7; - if (b & 0x80) { - b = readU8(); - result |= ((int)b & 0xFF) << 14; - } - } - return result; - } - // readString() reads a string - a U32 length followed by the data. // Returns a null-terminated string - the caller should delete[] it // afterwards. @@ -128,12 +111,6 @@ namespace rdr { inline U32 readOpaque32() { check(4); U32 r; ((U8*)&r)[0] = *ptr++; ((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++; ((U8*)&r)[3] = *ptr++; return r; } - inline U32 readOpaque24A() { check(3); U32 r=0; ((U8*)&r)[0] = *ptr++; - ((U8*)&r)[1] = *ptr++; ((U8*)&r)[2] = *ptr++; - return r; } - inline U32 readOpaque24B() { check(3); U32 r=0; ((U8*)&r)[1] = *ptr++; - ((U8*)&r)[2] = *ptr++; ((U8*)&r)[3] = *ptr++; - return r; } // pos() returns the position in the stream. diff --git a/common/rdr/OutStream.h b/common/rdr/OutStream.h index aed2eea1..4afd4bfb 100644 --- a/common/rdr/OutStream.h +++ b/common/rdr/OutStream.h @@ -65,25 +65,6 @@ namespace rdr { inline void writeS16(S16 s) { writeU16((U16)s); } inline void writeS32(S32 s) { writeU32((U32)s); } - // writeCompactLength() writes 1..3 bytes representing length of the data - // following. This method is used by the Tight encoder. - - inline void writeCompactLength(unsigned int len) { - U8 b = len & 0x7F; - if (len <= 0x7F) { - writeU8(b); - } else { - writeU8(b | 0x80); - b = len >> 7 & 0x7F; - if (len <= 0x3FFF) { - writeU8(b); - } else { - writeU8(b | 0x80); - writeU8(len >> 14 & 0xFF); - } - } - } - // writeString() writes a string - a U32 length followed by the data. The // given string should be null-terminated (but the terminating null is not // written to the stream). @@ -128,12 +109,6 @@ namespace rdr { *ptr++ = ((U8*)&u)[1]; *ptr++ = ((U8*)&u)[2]; *ptr++ = ((U8*)&u)[3]; } - inline void writeOpaque24A(U32 u) { check(3); *ptr++ = ((U8*)&u)[0]; - *ptr++ = ((U8*)&u)[1]; - *ptr++ = ((U8*)&u)[2]; } - inline void writeOpaque24B(U32 u) { check(3); *ptr++ = ((U8*)&u)[1]; - *ptr++ = ((U8*)&u)[2]; - *ptr++ = ((U8*)&u)[3]; } // length() returns the length of the stream. diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index e73b02e6..1695c3a6 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -19,8 +19,8 @@ #include <string.h> #include <rfb/Exception.h> #include <rfb/fenceTypes.h> -#include <rfb/CMsgReaderV3.h> -#include <rfb/CMsgWriterV3.h> +#include <rfb/CMsgReader.h> +#include <rfb/CMsgWriter.h> #include <rfb/CSecurity.h> #include <rfb/Security.h> #include <rfb/CConnection.h> @@ -254,8 +254,8 @@ void CConnection::throwConnFailedException() void CConnection::securityCompleted() { state_ = RFBSTATE_INITIALISATION; - reader_ = new CMsgReaderV3(this, is); - writer_ = new CMsgWriterV3(&cp, os); + reader_ = new CMsgReader(this, is); + writer_ = new CMsgWriter(&cp, os); vlog.debug("Authentication success!"); authSuccess(); writer_->writeClientInit(shared); diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index 9f5b59ec..48590f36 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -5,9 +5,7 @@ set(RFB_SOURCES CConnection.cxx CMsgHandler.cxx CMsgReader.cxx - CMsgReaderV3.cxx CMsgWriter.cxx - CMsgWriterV3.cxx CSecurityPlain.cxx CSecurityStack.cxx CSecurityVeNCrypt.cxx @@ -15,6 +13,7 @@ set(RFB_SOURCES ComparingUpdateTracker.cxx Configuration.cxx ConnParams.cxx + CopyRectDecoder.cxx Cursor.cxx Decoder.cxx d3des.c @@ -41,9 +40,7 @@ set(RFB_SOURCES SConnection.cxx SMsgHandler.cxx SMsgReader.cxx - SMsgReaderV3.cxx SMsgWriter.cxx - SMsgWriterV3.cxx ServerCore.cxx Security.cxx SecurityServer.cxx @@ -56,7 +53,6 @@ set(RFB_SOURCES Timer.cxx TightDecoder.cxx TightEncoder.cxx - TightPalette.cxx TransImageGetter.cxx UpdateTracker.cxx VNCSConnectionST.cxx diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index d7ffd65b..8b58e0e5 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -59,8 +59,7 @@ namespace rfb { virtual void framebufferUpdateStart() = 0; virtual void framebufferUpdateEnd() = 0; - virtual void beginRect(const Rect& r, int encoding) = 0; - virtual void endRect(const Rect& r, int encoding) = 0; + virtual void dataRect(const Rect& r, int encoding) = 0; virtual void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs) = 0; diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index 63d31d1a..04846ef4 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -16,31 +17,102 @@ * USA. */ #include <stdio.h> +#include <rfb/msgTypes.h> #include <rdr/InStream.h> #include <rfb/Exception.h> #include <rfb/util.h> #include <rfb/CMsgHandler.h> #include <rfb/CMsgReader.h> +#include <rfb/Decoder.h> using namespace rfb; CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_) : imageBufIdealSize(0), handler(handler_), is(is_), - imageBuf(0), imageBufSize(0) + imageBuf(0), imageBufSize(0), nUpdateRectsLeft(0) { - for (int i = 0; i <= encodingMax; i++) { - decoders[i] = 0; - } } CMsgReader::~CMsgReader() { - for (int i = 0; i <= encodingMax; i++) { - delete decoders[i]; - } delete [] imageBuf; } +void CMsgReader::readServerInit() +{ + int width = is->readU16(); + int height = is->readU16(); + handler->setDesktopSize(width, height); + PixelFormat pf; + pf.read(is); + handler->setPixelFormat(pf); + CharArray name(is->readString()); + handler->setName(name.buf); + handler->serverInit(); +} + +void CMsgReader::readMsg() +{ + if (nUpdateRectsLeft == 0) { + int type = is->readU8(); + + switch (type) { + case msgTypeSetColourMapEntries: + readSetColourMapEntries(); + break; + case msgTypeBell: + readBell(); + break; + case msgTypeServerCutText: + readServerCutText(); + break; + case msgTypeFramebufferUpdate: + readFramebufferUpdate(); + break; + case msgTypeServerFence: + readFence(); + break; + case msgTypeEndOfContinuousUpdates: + readEndOfContinuousUpdates(); + break; + default: + fprintf(stderr, "unknown message type %d\n", type); + throw Exception("unknown message type"); + } + } else { + int x = is->readU16(); + int y = is->readU16(); + int w = is->readU16(); + int h = is->readU16(); + int encoding = is->readS32(); + + switch (encoding) { + case pseudoEncodingLastRect: + nUpdateRectsLeft = 1; // this rectangle is the last one + break; + case pseudoEncodingCursor: + readSetCursor(w, h, Point(x,y)); + break; + case pseudoEncodingDesktopName: + readSetDesktopName(x, y, w, h); + break; + case pseudoEncodingDesktopSize: + handler->setDesktopSize(w, h); + break; + case pseudoEncodingExtendedDesktopSize: + readExtendedDesktopSize(x, y, w, h); + break; + default: + readRect(Rect(x, y, x+w, y+h), encoding); + break; + }; + + nUpdateRectsLeft--; + if (nUpdateRectsLeft == 0) + handler->framebufferUpdateEnd(); + } +} + void CMsgReader::readSetColourMapEntries() { is->skip(1); @@ -72,14 +144,38 @@ void CMsgReader::readServerCutText() handler->serverCutText(ca.buf, len); } -void CMsgReader::readFramebufferUpdateStart() +void CMsgReader::readFence() { - handler->framebufferUpdateStart(); + rdr::U32 flags; + rdr::U8 len; + char data[64]; + + is->skip(3); + + flags = is->readU32(); + + len = is->readU8(); + if (len > sizeof(data)) { + fprintf(stderr, "Ignoring fence with too large payload\n"); + is->skip(len); + return; + } + + is->readBytes(data, len); + + handler->fence(flags, len, data); } -void CMsgReader::readFramebufferUpdateEnd() +void CMsgReader::readEndOfContinuousUpdates() { - handler->framebufferUpdateEnd(); + handler->endOfContinuousUpdates(); +} + +void CMsgReader::readFramebufferUpdate() +{ + is->skip(1); + nUpdateRectsLeft = is->readU16(); + handler->framebufferUpdateStart(); } void CMsgReader::readRect(const Rect& r, int encoding) @@ -94,35 +190,7 @@ void CMsgReader::readRect(const Rect& r, int encoding) if (r.is_empty()) fprintf(stderr, "Warning: zero size rect\n"); - handler->beginRect(r, encoding); - - if (encoding == encodingCopyRect) { - readCopyRect(r); - } else { - - if (!Decoder::supported(encoding)) { - fprintf(stderr, "Unknown rect encoding %d\n", encoding); - throw Exception("Unknown rect encoding"); - } - - if (!decoders[encoding]) { - decoders[encoding] = Decoder::createDecoder(encoding, this); - if (!decoders[encoding]) { - fprintf(stderr, "Unknown rect encoding %d\n", encoding); - throw Exception("Unknown rect encoding"); - } - } - decoders[encoding]->readRect(r, handler); - } - - handler->endRect(r, encoding); -} - -void CMsgReader::readCopyRect(const Rect& r) -{ - int srcX = is->readU16(); - int srcY = is->readU16(); - handler->copyRect(r, srcX, srcY); + handler->dataRect(r, encoding); } void CMsgReader::readSetCursor(int width, int height, const Point& hotspot) @@ -138,6 +206,43 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot) handler->setCursor(width, height, hotspot, data.buf, mask.buf); } +void CMsgReader::readSetDesktopName(int x, int y, int w, int h) +{ + char* name = is->readString(); + + if (x || y || w || h) { + fprintf(stderr, "Ignoring DesktopName rect with non-zero position/size\n"); + } else { + handler->setName(name); + } + + delete [] name; +} + +void CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h) +{ + unsigned int screens, i; + rdr::U32 id, flags; + int sx, sy, sw, sh; + ScreenSet layout; + + screens = is->readU8(); + is->skip(3); + + for (i = 0;i < screens;i++) { + id = is->readU32(); + sx = is->readU16(); + sy = is->readU16(); + sw = is->readU16(); + sh = is->readU16(); + flags = is->readU32(); + + layout.add_screen(Screen(id, sx, sy, sw, sh, flags)); + } + + handler->setExtendedDesktopSize(x, y, w, h, layout); +} + rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels) { int requiredBytes = required * (handler->cp.pf().bpp / 8); @@ -157,8 +262,3 @@ rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels) *nPixels = imageBufSize / (handler->cp.pf().bpp / 8); return imageBuf; } - -int CMsgReader::bpp() -{ - return handler->cp.pf().bpp; -} diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h index 7b361609..3592ef87 100644 --- a/common/rfb/CMsgReader.h +++ b/common/rfb/CMsgReader.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -24,8 +25,9 @@ #define __RFB_CMSGREADER_H__ #include <rdr/types.h> + +#include <rfb/Rect.h> #include <rfb/encodings.h> -#include <rfb/Decoder.h> namespace rdr { class InStream; } @@ -35,39 +37,39 @@ namespace rfb { class CMsgReader { public: + CMsgReader(CMsgHandler* handler, rdr::InStream* is); virtual ~CMsgReader(); - virtual void readServerInit()=0; + void readServerInit(); // readMsg() reads a message, calling the handler as appropriate. - virtual void readMsg()=0; + void readMsg(); rdr::InStream* getInStream() { return is; } rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0); - int bpp(); int imageBufIdealSize; protected: - virtual void readSetColourMapEntries(); - virtual void readBell(); - virtual void readServerCutText(); + void readSetColourMapEntries(); + void readBell(); + void readServerCutText(); + void readFence(); + void readEndOfContinuousUpdates(); - virtual void readFramebufferUpdateStart(); - virtual void readFramebufferUpdateEnd(); - virtual void readRect(const Rect& r, int encoding); + void readFramebufferUpdate(); - virtual void readCopyRect(const Rect& r); + void readRect(const Rect& r, int encoding); - virtual void readSetCursor(int width, int height, const Point& hotspot); - - CMsgReader(CMsgHandler* handler, rdr::InStream* is); + void readSetCursor(int width, int height, const Point& hotspot); + void readSetDesktopName(int x, int y, int w, int h); + void readExtendedDesktopSize(int x, int y, int w, int h); CMsgHandler* handler; rdr::InStream* is; - Decoder* decoders[encodingMax+1]; rdr::U8* imageBuf; int imageBufSize; + int nUpdateRectsLeft; }; } #endif diff --git a/common/rfb/CMsgReaderV3.cxx b/common/rfb/CMsgReaderV3.cxx deleted file mode 100644 index 085cc5ad..00000000 --- a/common/rfb/CMsgReaderV3.cxx +++ /dev/null @@ -1,174 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#include <rfb/PixelFormat.h> -#include <rfb/msgTypes.h> -#include <rfb/Exception.h> -#include <rdr/InStream.h> -#include <rfb/CMsgReaderV3.h> -#include <rfb/CMsgHandler.h> -#include <rfb/util.h> -#include <rfb/ScreenSet.h> -#include <stdio.h> - -using namespace rfb; - -CMsgReaderV3::CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is) - : CMsgReader(handler, is), nUpdateRectsLeft(0) -{ -} - -CMsgReaderV3::~CMsgReaderV3() -{ -} - -void CMsgReaderV3::readServerInit() -{ - int width = is->readU16(); - int height = is->readU16(); - handler->setDesktopSize(width, height); - PixelFormat pf; - pf.read(is); - handler->setPixelFormat(pf); - CharArray name(is->readString()); - handler->setName(name.buf); - handler->serverInit(); -} - -void CMsgReaderV3::readMsg() -{ - if (nUpdateRectsLeft == 0) { - - int type = is->readU8(); - switch (type) { - case msgTypeFramebufferUpdate: readFramebufferUpdate(); break; - case msgTypeSetColourMapEntries: readSetColourMapEntries(); break; - case msgTypeBell: readBell(); break; - case msgTypeServerCutText: readServerCutText(); break; - case msgTypeServerFence: readFence(); break; - case msgTypeEndOfContinuousUpdates: readEndOfContinuousUpdates(); break; - - default: - fprintf(stderr, "unknown message type %d\n", type); - throw Exception("unknown message type"); - } - - } else { - - int x = is->readU16(); - int y = is->readU16(); - int w = is->readU16(); - int h = is->readU16(); - int encoding = is->readS32(); - - switch (encoding) { - case pseudoEncodingDesktopSize: - handler->setDesktopSize(w, h); - break; - case pseudoEncodingExtendedDesktopSize: - readExtendedDesktopSize(x, y, w, h); - break; - case pseudoEncodingDesktopName: - readSetDesktopName(x, y, w, h); - break; - case pseudoEncodingCursor: - readSetCursor(w, h, Point(x,y)); - break; - case pseudoEncodingLastRect: - nUpdateRectsLeft = 1; // this rectangle is the last one - break; - default: - readRect(Rect(x, y, x+w, y+h), encoding); - break; - }; - - nUpdateRectsLeft--; - if (nUpdateRectsLeft == 0) handler->framebufferUpdateEnd(); - } -} - -void CMsgReaderV3::readFramebufferUpdate() -{ - is->skip(1); - nUpdateRectsLeft = is->readU16(); - handler->framebufferUpdateStart(); -} - -void CMsgReaderV3::readSetDesktopName(int x, int y, int w, int h) -{ - char* name = is->readString(); - - if (x || y || w || h) { - fprintf(stderr, "Ignoring DesktopName rect with non-zero position/size\n"); - } else { - handler->setName(name); - } - - delete [] name; -} - -void CMsgReaderV3::readExtendedDesktopSize(int x, int y, int w, int h) -{ - unsigned int screens, i; - rdr::U32 id, flags; - int sx, sy, sw, sh; - ScreenSet layout; - - screens = is->readU8(); - is->skip(3); - - for (i = 0;i < screens;i++) { - id = is->readU32(); - sx = is->readU16(); - sy = is->readU16(); - sw = is->readU16(); - sh = is->readU16(); - flags = is->readU32(); - - layout.add_screen(Screen(id, sx, sy, sw, sh, flags)); - } - - handler->setExtendedDesktopSize(x, y, w, h, layout); -} - -void CMsgReaderV3::readFence() -{ - rdr::U32 flags; - rdr::U8 len; - char data[64]; - - is->skip(3); - - flags = is->readU32(); - - len = is->readU8(); - if (len > sizeof(data)) { - fprintf(stderr, "Ignoring fence with too large payload\n"); - is->skip(len); - return; - } - - is->readBytes(data, len); - - handler->fence(flags, len, data); -} - -void CMsgReaderV3::readEndOfContinuousUpdates() -{ - handler->endOfContinuousUpdates(); -} diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 9ee7a02f..6536eaf2 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -18,7 +19,9 @@ #include <stdio.h> #include <rdr/OutStream.h> #include <rfb/msgTypes.h> +#include <rfb/fenceTypes.h> #include <rfb/encodings.h> +#include <rfb/Exception.h> #include <rfb/PixelFormat.h> #include <rfb/Rect.h> #include <rfb/ConnParams.h> @@ -36,6 +39,12 @@ CMsgWriter::~CMsgWriter() { } +void CMsgWriter::writeClientInit(bool shared) +{ + os->writeU8(shared); + endMsg(); +} + void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf) { startMsg(msgTypeSetPixelFormat); @@ -104,9 +113,11 @@ void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect) // Remaining encodings for (int i = encodingMax; i >= 0; i--) { switch (i) { + case encodingCopyRect: case encodingTight: case encodingZRLE: case encodingHextile: + /* These have already been sent earlier */ break; default: if ((i != preferredEncoding) && Decoder::supported(i)) @@ -121,7 +132,35 @@ void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect) writeSetEncodings(nEncodings, encodings); } - + +void CMsgWriter::writeSetDesktopSize(int width, int height, + const ScreenSet& layout) +{ + if (!cp->supportsSetDesktopSize) + throw Exception("Server does not support SetDesktopSize"); + + startMsg(msgTypeSetDesktopSize); + os->pad(1); + + os->writeU16(width); + os->writeU16(height); + + os->writeU8(layout.num_screens()); + os->pad(1); + + ScreenSet::const_iterator iter; + for (iter = layout.begin();iter != layout.end();++iter) { + os->writeU32(iter->id); + os->writeU16(iter->dimensions.tl.x); + os->writeU16(iter->dimensions.tl.y); + os->writeU16(iter->dimensions.width()); + os->writeU16(iter->dimensions.height()); + os->writeU32(iter->flags); + } + + endMsg(); +} + void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental) { startMsg(msgTypeFramebufferUpdateRequest); @@ -133,6 +172,43 @@ void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental) endMsg(); } +void CMsgWriter::writeEnableContinuousUpdates(bool enable, + int x, int y, int w, int h) +{ + if (!cp->supportsContinuousUpdates) + throw Exception("Server does not support continuous updates"); + + startMsg(msgTypeEnableContinuousUpdates); + + os->writeU8(!!enable); + + os->writeU16(x); + os->writeU16(y); + os->writeU16(w); + os->writeU16(h); + + endMsg(); +} + +void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) +{ + if (!cp->supportsFence) + throw Exception("Server does not support fences"); + if (len > 64) + throw Exception("Too large fence payload"); + if ((flags & ~fenceFlagsSupported) != 0) + throw Exception("Unknown fence flags"); + + startMsg(msgTypeClientFence); + os->pad(3); + + os->writeU32(flags); + + os->writeU8(len); + os->writeBytes(data, len); + + endMsg(); +} void CMsgWriter::keyEvent(rdr::U32 key, bool down) { @@ -168,3 +244,13 @@ void CMsgWriter::clientCutText(const char* str, rdr::U32 len) os->writeBytes(str, len); endMsg(); } + +void CMsgWriter::startMsg(int type) +{ + os->writeU8(type); +} + +void CMsgWriter::endMsg() +{ + os->flush(); +} diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 66174598..06ecbe7d 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB + * Copyright 2009-2014 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 @@ -23,8 +23,9 @@ #ifndef __RFB_CMSGWRITER_H__ #define __RFB_CMSGWRITER_H__ +#include <rdr/types.h> + #include <rfb/InputHandler.h> -#include <rfb/ScreenSet.h> namespace rdr { class OutStream; } @@ -32,39 +33,35 @@ namespace rfb { class PixelFormat; class ConnParams; + class ScreenSet; struct Rect; class CMsgWriter : public InputHandler { public: + CMsgWriter(ConnParams* cp, rdr::OutStream* os); virtual ~CMsgWriter(); - // CMsgWriter abstract interface methods - virtual void writeClientInit(bool shared)=0; - virtual void startMsg(int type)=0; - virtual void endMsg()=0; + void writeClientInit(bool shared); + + void writeSetPixelFormat(const PixelFormat& pf); + void writeSetEncodings(int nEncodings, rdr::U32* encodings); + void writeSetEncodings(int preferredEncoding, bool useCopyRect); + void writeSetDesktopSize(int width, int height, const ScreenSet& layout); - virtual void writeSetDesktopSize(int width, int height, - const ScreenSet& layout)=0; - virtual void writeFence(rdr::U32 flags, unsigned len, const char data[])=0; - virtual void writeEnableContinuousUpdates(bool enable, - int x, int y, int w, int h)=0; + void writeFramebufferUpdateRequest(const Rect& r,bool incremental); + void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h); - // CMsgWriter implemented methods - virtual void writeSetPixelFormat(const PixelFormat& pf); - virtual void writeSetEncodings(int nEncodings, rdr::U32* encodings); - virtual void writeSetEncodings(int preferredEncoding, bool useCopyRect); - virtual void writeFramebufferUpdateRequest(const Rect& r,bool incremental); + void writeFence(rdr::U32 flags, unsigned len, const char data[]); // InputHandler implementation + virtual void keyEvent(rdr::U32 key, bool down); virtual void pointerEvent(const Point& pos, int buttonMask); virtual void clientCutText(const char* str, rdr::U32 len); - ConnParams* getConnParams() { return cp; } - rdr::OutStream* getOutStream() { return os; } - protected: - CMsgWriter(ConnParams* cp, rdr::OutStream* os); + void startMsg(int type); + void endMsg(); ConnParams* cp; rdr::OutStream* os; diff --git a/common/rfb/CMsgWriterV3.cxx b/common/rfb/CMsgWriterV3.cxx deleted file mode 100644 index b96e2b37..00000000 --- a/common/rfb/CMsgWriterV3.cxx +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#include <rdr/OutStream.h> -#include <rfb/msgTypes.h> -#include <rfb/fenceTypes.h> -#include <rfb/Exception.h> -#include <rfb/ConnParams.h> -#include <rfb/CMsgWriterV3.h> - -using namespace rfb; - -CMsgWriterV3::CMsgWriterV3(ConnParams* cp, rdr::OutStream* os) - : CMsgWriter(cp, os) -{ -} - -CMsgWriterV3::~CMsgWriterV3() -{ -} - -void CMsgWriterV3::writeClientInit(bool shared) -{ - os->writeU8(shared); - endMsg(); -} - -void CMsgWriterV3::startMsg(int type) -{ - os->writeU8(type); -} - -void CMsgWriterV3::endMsg() -{ - os->flush(); -} - -void CMsgWriterV3::writeSetDesktopSize(int width, int height, - const ScreenSet& layout) -{ - if (!cp->supportsSetDesktopSize) - throw Exception("Server does not support SetDesktopSize"); - - startMsg(msgTypeSetDesktopSize); - os->pad(1); - - os->writeU16(width); - os->writeU16(height); - - os->writeU8(layout.num_screens()); - os->pad(1); - - ScreenSet::const_iterator iter; - for (iter = layout.begin();iter != layout.end();++iter) { - os->writeU32(iter->id); - os->writeU16(iter->dimensions.tl.x); - os->writeU16(iter->dimensions.tl.y); - os->writeU16(iter->dimensions.width()); - os->writeU16(iter->dimensions.height()); - os->writeU32(iter->flags); - } - - endMsg(); -} - -void CMsgWriterV3::writeFence(rdr::U32 flags, unsigned len, const char data[]) -{ - if (!cp->supportsFence) - throw Exception("Server does not support fences"); - if (len > 64) - throw Exception("Too large fence payload"); - if ((flags & ~fenceFlagsSupported) != 0) - throw Exception("Unknown fence flags"); - - startMsg(msgTypeClientFence); - os->pad(3); - - os->writeU32(flags); - - os->writeU8(len); - os->writeBytes(data, len); - - endMsg(); -} - -void CMsgWriterV3::writeEnableContinuousUpdates(bool enable, - int x, int y, int w, int h) -{ - if (!cp->supportsContinuousUpdates) - throw Exception("Server does not support continuous updates"); - - startMsg(msgTypeEnableContinuousUpdates); - - os->writeU8(!!enable); - - os->writeU16(x); - os->writeU16(y); - os->writeU16(w); - os->writeU16(h); - - endMsg(); -} diff --git a/common/rfb/CMsgWriterV3.h b/common/rfb/CMsgWriterV3.h deleted file mode 100644 index fb1c42c0..00000000 --- a/common/rfb/CMsgWriterV3.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_CMSGWRITERV3_H__ -#define __RFB_CMSGWRITERV3_H__ - -#include <rfb/CMsgWriter.h> - -namespace rfb { - class CMsgWriterV3 : public CMsgWriter { - public: - CMsgWriterV3(ConnParams* cp, rdr::OutStream* os); - virtual ~CMsgWriterV3(); - - virtual void writeClientInit(bool shared); - virtual void startMsg(int type); - virtual void endMsg(); - - virtual void writeSetDesktopSize(int width, int height, - const ScreenSet& layout); - virtual void writeFence(rdr::U32 flags, unsigned len, const char data[]); - virtual void writeEnableContinuousUpdates(bool enable, - int x, int y, int w, int h); - }; -} -#endif diff --git a/common/rfb/ColourCube.h b/common/rfb/ColourCube.h deleted file mode 100644 index b83cbba8..00000000 --- a/common/rfb/ColourCube.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -// -// ColourCube - structure to represent a colour cube. The colour cube consists -// of its dimensions (nRed x nGreen x nBlue) and a table mapping an (r,g,b) -// triple to a pixel value. -// -// A colour cube is used in two cases. The first is internally in a viewer -// when it cannot use a trueColour format, nor can it have exclusive access to -// a writable colour map. This is most notably the case for an X viewer -// wishing to use a PseudoColor X server's default colormap. -// -// The second use is on the server side when a client has asked for a colour -// map and the server is trueColour. Instead of setting an uneven trueColour -// format like bgr233, it can set the client's colour map up with a 6x6x6 -// colour cube. For this use the colour cube table has a null mapping, which -// makes it easy to perform the reverse lookup operation from pixel value to -// r,g,b values. - -#ifndef __RFB_COLOURCUBE_H__ -#define __RFB_COLOURCUBE_H__ - -#include <rfb/Pixel.h> -#include <rfb/ColourMap.h> - -namespace rfb { - - class ColourCube : public ColourMap { - public: - ColourCube(int nr, int ng, int nb, Pixel* table_=0) - : nRed(nr), nGreen(ng), nBlue(nb), table(table_), deleteTable(false) - { - if (!table) { - table = new Pixel[size()]; - deleteTable = true; - // set a null mapping by default - for (int i = 0; i < size(); i++) - table[i] = i; - } - } - - ColourCube() : deleteTable(false) {} - - virtual ~ColourCube() { - if (deleteTable) delete [] table; - } - - void set(int r, int g, int b, Pixel p) { - table[(r * nGreen + g) * nBlue + b] = p; - } - - Pixel lookup(int r, int g, int b) const { - return table[(r * nGreen + g) * nBlue + b]; - } - - int size() const { return nRed*nGreen*nBlue; } - int redMult() const { return nGreen*nBlue; } - int greenMult() const { return nBlue; } - int blueMult() const { return 1; } - - // ColourMap lookup() method. Note that this only works when the table has - // the default null mapping. - virtual void lookup(int i, int* r, int* g, int* b) { - if (i >= size()) return; - *b = i % nBlue; - i /= nBlue; - *g = i % nGreen; - *r = i / nGreen; - *r = (*r * 65535 + (nRed-1) / 2) / (nRed-1); - *g = (*g * 65535 + (nGreen-1) / 2) / (nGreen-1); - *b = (*b * 65535 + (nBlue-1) / 2) / (nBlue-1); - } - - int nRed; - int nGreen; - int nBlue; - Pixel* table; - bool deleteTable; - }; -} -#endif diff --git a/common/rfb/ColourMap.h b/common/rfb/ColourMap.h deleted file mode 100644 index c024adce..00000000 --- a/common/rfb/ColourMap.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011 Pierre Ossman <ossman@cendio.se> 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_COLOURMAP_H__ -#define __RFB_COLOURMAP_H__ -namespace rfb { - struct Colour { - Colour() : r(0), g(0), b(0) {} - Colour(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {} - int r, g, b; - bool operator==(const Colour& c) const {return c.r == r && c.g == g && c.b == b;} - bool operator!=(const Colour& c) const {return !(c == *this);} - }; - - class ColourMap { - public: - virtual void lookup(int index, int* r, int* g, int* b)=0; - virtual ~ColourMap() {} - }; - - class SimpleColourMap : public ColourMap { - public: - SimpleColourMap(int size = 256) { table = new Colour[size]; }; - virtual ~SimpleColourMap() { delete [] table; }; - - void lookup(int index, int* r, int* g, int* b) - { *r = table[index].r; *g = table[index].g; *b = table[index].b; }; - - void set(int index, int r, int g, int b) - { table[index].r = r; table[index].g = g; table[index].b = b; }; - - protected: - Colour *table; - }; -} -#endif diff --git a/common/rfb/SMsgReaderV3.h b/common/rfb/CopyRectDecoder.cxx index 805fd876..bb3084fd 100644 --- a/common/rfb/SMsgReaderV3.h +++ b/common/rfb/CopyRectDecoder.cxx @@ -1,5 +1,4 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB +/* Copyright 2014 Pierre Ossman <ossman@cendio.se> 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 @@ -16,22 +15,25 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#ifndef __RFB_SMSGREADERV3_H__ -#define __RFB_SMSGREADERV3_H__ +#include <rdr/InStream.h> +#include <rfb/CConnection.h> +#include <rfb/CMsgHandler.h> +#include <rfb/PixelBuffer.h> +#include <rfb/CopyRectDecoder.h> -#include <rfb/SMsgReader.h> +using namespace rfb; -namespace rfb { - class SMsgReaderV3 : public SMsgReader { - public: - SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is); - virtual ~SMsgReaderV3(); - virtual void readClientInit(); - virtual void readMsg(); - protected: - virtual void readSetDesktopSize(); - virtual void readFence(); - virtual void readEnableContinuousUpdates(); - }; +CopyRectDecoder::CopyRectDecoder(CConnection* conn) : Decoder(conn) +{ +} + +CopyRectDecoder::~CopyRectDecoder() +{ +} + +void CopyRectDecoder::readRect(const Rect& r, CMsgHandler* handler) +{ + int srcX = conn->getInStream()->readU16(); + int srcY = conn->getInStream()->readU16(); + handler->copyRect(r, srcX, srcY); } -#endif diff --git a/common/rfb/ImageGetter.h b/common/rfb/CopyRectDecoder.h index 2e7bf376..5932066b 100644 --- a/common/rfb/ImageGetter.h +++ b/common/rfb/CopyRectDecoder.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. +/* Copyright 2014 Pierre Ossman <ossman@cendio.se> 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 @@ -15,17 +15,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#ifndef __RFB_IMAGEGETTER_H__ -#define __RFB_IMAGEGETTER_H__ +#ifndef __RFB_COPYRECTDECODER_H__ +#define __RFB_COPYRECTDECODER_H__ -#include <rfb/Rect.h> +#include <rfb/Decoder.h> namespace rfb { - class ImageGetter { + + class CopyRectDecoder : public Decoder { public: - virtual void getImage(void* imageBuf, - const Rect& r, int stride=0) = 0; - virtual ~ImageGetter() {} + CopyRectDecoder(CConnection* conn); + virtual ~CopyRectDecoder(); + virtual void readRect(const Rect& r, CMsgHandler* handler); }; } #endif diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx index e201821f..3faa9753 100644 --- a/common/rfb/Decoder.cxx +++ b/common/rfb/Decoder.cxx @@ -20,6 +20,7 @@ #include <rfb/encodings.h> #include <rfb/Decoder.h> #include <rfb/RawDecoder.h> +#include <rfb/CopyRectDecoder.h> #include <rfb/RREDecoder.h> #include <rfb/HextileDecoder.h> #include <rfb/ZRLEDecoder.h> @@ -27,6 +28,10 @@ using namespace rfb; +Decoder::Decoder(CConnection* conn_) : conn(conn_) +{ +} + Decoder::~Decoder() { } @@ -35,6 +40,7 @@ bool Decoder::supported(int encoding) { switch (encoding) { case encodingRaw: + case encodingCopyRect: case encodingRRE: case encodingHextile: case encodingZRLE: @@ -45,19 +51,21 @@ bool Decoder::supported(int encoding) } } -Decoder* Decoder::createDecoder(int encoding, CMsgReader* reader) +Decoder* Decoder::createDecoder(int encoding, CConnection* conn) { switch (encoding) { case encodingRaw: - return new RawDecoder(reader); + return new RawDecoder(conn); + case encodingCopyRect: + return new CopyRectDecoder(conn); case encodingRRE: - return new RREDecoder(reader); + return new RREDecoder(conn); case encodingHextile: - return new HextileDecoder(reader); + return new HextileDecoder(conn); case encodingZRLE: - return new ZRLEDecoder(reader); + return new ZRLEDecoder(conn); case encodingTight: - return new TightDecoder(reader); + return new TightDecoder(conn); default: return NULL; } diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h index 025d63f5..870fa80e 100644 --- a/common/rfb/Decoder.h +++ b/common/rfb/Decoder.h @@ -22,16 +22,19 @@ #include <rfb/Rect.h> namespace rfb { - class CMsgReader; + class CConnection; class CMsgHandler; class Decoder { public: + Decoder(CConnection* conn); virtual ~Decoder(); virtual void readRect(const Rect& r, CMsgHandler* handler)=0; static bool supported(int encoding); - static Decoder* createDecoder(int encoding, CMsgReader* reader); + static Decoder* createDecoder(int encoding, CConnection* conn); + protected: + CConnection* conn; }; } diff --git a/common/rfb/Encoder.cxx b/common/rfb/Encoder.cxx index 1733c8ec..89a5f149 100644 --- a/common/rfb/Encoder.cxx +++ b/common/rfb/Encoder.cxx @@ -25,9 +25,14 @@ #include <rfb/HextileEncoder.h> #include <rfb/ZRLEEncoder.h> #include <rfb/TightEncoder.h> +#include <rfb/SConnection.h> using namespace rfb; +Encoder::Encoder(SConnection *conn_) : conn(conn_) +{ +} + Encoder::~Encoder() { } @@ -46,19 +51,19 @@ bool Encoder::supported(int encoding) } } -Encoder* Encoder::createEncoder(int encoding, SMsgWriter* writer) +Encoder* Encoder::createEncoder(int encoding, SConnection* conn) { switch (encoding) { case encodingRaw: - return new RawEncoder(writer); + return new RawEncoder(conn); case encodingRRE: - return new RREEncoder(writer); + return new RREEncoder(conn); case encodingHextile: - return new HextileEncoder(writer); + return new HextileEncoder(conn); case encodingZRLE: - return new ZRLEEncoder(writer); + return new ZRLEEncoder(conn); case encodingTight: - return new TightEncoder(writer); + return new TightEncoder(conn); default: return NULL; } diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index 26d57963..2897f9f8 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -24,11 +24,12 @@ #include <rfb/TransImageGetter.h> namespace rfb { - class SMsgWriter; + class SConnection; class TransImageGetter; class Encoder { public: + Encoder(SConnection* conn); virtual ~Encoder(); virtual void setCompressLevel(int level) {}; @@ -36,14 +37,16 @@ namespace rfb { virtual void setFineQualityLevel(int quality, int subsampling) {}; virtual int getNumRects(const Rect &r) { return 1; } - // writeRect() tries to write the given rectangle. If it is unable to - // write the whole rectangle it returns false and sets actual to the actual - // rectangle which was updated. - virtual bool writeRect(const Rect& r, TransImageGetter* ig, - Rect* actual)=0; + // writeRect() is the main interface that encodes the given rectangle + // with data from the ImageGetter onto the SMsgWriter given at + // encoder creation. + virtual void writeRect(const Rect& r, TransImageGetter* ig)=0; static bool supported(int encoding); - static Encoder* createEncoder(int encoding, SMsgWriter* writer); + static Encoder* createEncoder(int encoding, SConnection* conn); + + protected: + SConnection* conn; }; } diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index ae612676..9b335fe9 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -16,14 +16,12 @@ * USA. */ #include <rfb/CMsgReader.h> +#include <rfb/CConnection.h> #include <rfb/CMsgHandler.h> #include <rfb/HextileDecoder.h> using namespace rfb; -#define EXTRA_ARGS CMsgHandler* handler -#define FILL_RECT(r, p) handler->fillRect(r, p) -#define IMAGE_RECT(r, p) handler->imageRect(r, p) #define BPP 8 #include <rfb/hextileDecode.h> #undef BPP @@ -34,7 +32,7 @@ using namespace rfb; #include <rfb/hextileDecode.h> #undef BPP -HextileDecoder::HextileDecoder(CMsgReader* reader_) : reader(reader_) +HextileDecoder::HextileDecoder(CConnection* conn) : Decoder(conn) { } @@ -44,9 +42,9 @@ HextileDecoder::~HextileDecoder() void HextileDecoder::readRect(const Rect& r, CMsgHandler* handler) { - rdr::InStream* is = reader->getInStream(); - rdr::U8* buf = reader->getImageBuf(16 * 16 * 4); - switch (reader->bpp()) { + rdr::InStream* is = conn->getInStream(); + rdr::U8* buf = conn->reader()->getImageBuf(16 * 16 * 4); + switch (conn->cp.pf().bpp) { case 8: hextileDecode8 (r, is, (rdr::U8*) buf, handler); break; case 16: hextileDecode16(r, is, (rdr::U16*)buf, handler); break; case 32: hextileDecode32(r, is, (rdr::U32*)buf, handler); break; diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h index 95a7f8a4..67dc791a 100644 --- a/common/rfb/HextileDecoder.h +++ b/common/rfb/HextileDecoder.h @@ -24,11 +24,9 @@ namespace rfb { class HextileDecoder : public Decoder { public: - HextileDecoder(CMsgReader* reader); + HextileDecoder(CConnection* conn); virtual ~HextileDecoder(); virtual void readRect(const Rect& r, CMsgHandler* handler); - private: - CMsgReader* reader; }; } #endif diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index 0907bab8..aa1b218a 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -19,6 +19,7 @@ #include <rfb/TransImageGetter.h> #include <rfb/encodings.h> #include <rfb/SMsgWriter.h> +#include <rfb/SConnection.h> #include <rfb/HextileEncoder.h> #include <rfb/Configuration.h> @@ -30,8 +31,6 @@ BoolParameter improvedHextile("ImprovedHextile", "ratios by the cost of using more CPU time", true); -#define EXTRA_ARGS ImageGetter* ig -#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r); #define BPP 8 #include <rfb/hextileEncode.h> #include <rfb/hextileEncodeBetter.h> @@ -45,7 +44,7 @@ BoolParameter improvedHextile("ImprovedHextile", #include <rfb/hextileEncodeBetter.h> #undef BPP -HextileEncoder::HextileEncoder(SMsgWriter* writer_) : writer(writer_) +HextileEncoder::HextileEncoder(SConnection* conn) : Encoder(conn) { } @@ -53,12 +52,11 @@ HextileEncoder::~HextileEncoder() { } -bool HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig, - Rect* actual) +void HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig) { - writer->startRect(r, encodingHextile); - rdr::OutStream* os = writer->getOutStream(); - switch (writer->bpp()) { + conn->writer()->startRect(r, encodingHextile); + rdr::OutStream* os = conn->getOutStream(); + switch (conn->cp.pf().bpp) { case 8: if (improvedHextile) { hextileEncodeBetter8(r, os, ig); @@ -81,6 +79,5 @@ bool HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig, } break; } - writer->endRect(); - return true; + conn->writer()->endRect(); } diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h index 0c475a8e..723f5391 100644 --- a/common/rfb/HextileEncoder.h +++ b/common/rfb/HextileEncoder.h @@ -24,11 +24,9 @@ namespace rfb { class HextileEncoder : public Encoder { public: - HextileEncoder(SMsgWriter* writer); + HextileEncoder(SConnection* conn); virtual ~HextileEncoder(); - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); - private: - SMsgWriter* writer; + virtual void writeRect(const Rect& r, TransImageGetter* ig); }; } #endif diff --git a/common/rfb/Palette.h b/common/rfb/Palette.h new file mode 100644 index 00000000..a9003354 --- /dev/null +++ b/common/rfb/Palette.h @@ -0,0 +1,190 @@ +/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2014 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_PALETTE_H__ +#define __RFB_PALETTE_H__ + +#include <assert.h> +#include <string.h> + +#include <rdr/types.h> + +namespace rfb { + class Palette { + public: + Palette() { clear(); } + ~Palette() {} + + int size() const { return numColours; } + + void clear() { numColours = 0; memset(hash, 0, sizeof(hash)); } + + inline bool insert(rdr::U32 colour, int numPixels); + inline unsigned char lookup(rdr::U32 colour) const; + inline rdr::U32 getColour(unsigned char index) const; + inline int getCount(unsigned char index) const; + + protected: + inline unsigned char genHash(rdr::U32 colour) const; + + protected: + int numColours; + + struct PaletteListNode { + PaletteListNode *next; + unsigned char idx; + rdr::U32 colour; + }; + + struct PaletteEntry { + PaletteListNode *listNode; + int numPixels; + }; + + // This is the raw list of colours, allocated from 0 and up + PaletteListNode list[256]; + // Hash table for quick lookup into the list above + PaletteListNode *hash[256]; + // Occurances of each colour, where the 0:th entry is the most common. + // Indices also refer to this array. + PaletteEntry entry[256]; + }; +} + +inline bool rfb::Palette::insert(rdr::U32 colour, int numPixels) +{ + PaletteListNode* pnode; + PaletteListNode* prev_pnode; + unsigned char hash_key, idx; + + hash_key = genHash(colour); + + pnode = hash[hash_key]; + prev_pnode = NULL; + + // Do we already have an entry for this colour? + while (pnode != NULL) { + if (pnode->colour == colour) { + // Yup + + idx = pnode->idx; + numPixels = entry[idx].numPixels + numPixels; + + // The extra pixels might mean we have to adjust the sort list + while (idx > 0) { + if (entry[idx-1].numPixels >= numPixels) + break; + entry[idx] = entry[idx-1]; + entry[idx].listNode->idx = idx; + idx--; + } + + if (idx != pnode->idx) { + entry[idx].listNode = pnode; + pnode->idx = idx; + } + + entry[idx].numPixels = numPixels; + + return true; + } + + prev_pnode = pnode; + pnode = pnode->next; + } + + // Check if palette is full. + if (numColours == 256) + return false; + + // Create a new colour entry + pnode = &list[numColours]; + pnode->next = NULL; + pnode->idx = 0; + pnode->colour = colour; + + // Add it to the hash table + if (prev_pnode != NULL) + prev_pnode->next = pnode; + else + hash[hash_key] = pnode; + + // Move palette entries with lesser pixel counts. + idx = numColours; + while (idx > 0) { + if (entry[idx-1].numPixels >= numPixels) + break; + entry[idx] = entry[idx-1]; + entry[idx].listNode->idx = idx; + idx--; + } + + // And add it into the freed slot. + pnode->idx = idx; + entry[idx].listNode = pnode; + entry[idx].numPixels = numPixels; + + numColours++; + + return true; +} + +inline unsigned char rfb::Palette::lookup(rdr::U32 colour) const +{ + unsigned char hash_key; + PaletteListNode* pnode; + + hash_key = genHash(colour); + pnode = hash[hash_key]; + + while (pnode != NULL) { + if (pnode->colour == colour) + return pnode->idx; + pnode = pnode->next; + } + + // We are being fed a bad colour + assert(false); + + return 0; +} + +inline rdr::U32 rfb::Palette::getColour(unsigned char index) const +{ + return entry[index].listNode->colour; +} + +inline int rfb::Palette::getCount(unsigned char index) const +{ + return entry[index].numPixels; +} + +inline unsigned char rfb::Palette::genHash(rdr::U32 colour) const +{ + unsigned char hash_key; + + // djb2 hash function + hash_key = 5; // 5381 & 0xff + for (int i = 0; i < 32; i += 8) + hash_key = ((hash_key << 5) + hash_key) ^ (colour >> i); + + return hash_key; +} + +#endif diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx index 9d151b97..ea19d183 100644 --- a/common/rfb/PixelBuffer.cxx +++ b/common/rfb/PixelBuffer.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014 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 @@ -33,18 +34,13 @@ static LogWriter vlog("PixelBuffer"); // -=- Generic pixel buffer class -PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h, ColourMap* cm) - : format(pf), width_(w), height_(h), colourmap(cm) {} -PixelBuffer::PixelBuffer() : width_(0), height_(0), colourmap(0) {} +PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h) + : format(pf), width_(w), height_(h) {} +PixelBuffer::PixelBuffer() : width_(0), height_(0) {} PixelBuffer::~PixelBuffer() {} -void PixelBuffer::setPF(const PixelFormat &pf) {format = pf;} -const PixelFormat& PixelBuffer::getPF() const {return format;} -ColourMap* PixelBuffer::getColourMap() const {return colourmap;} - - void PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) { int inStride; @@ -65,63 +61,10 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) { } -static void fillRect8(U8 *buf, int stride, const Rect& r, Pixel pix) -{ - U8* ptr = buf; - int w = r.width(), h = r.height(); - - while (h > 0) { - memset(ptr, pix, w); - ptr += stride; - h--; - } -} - -static void fillRect16(U8 *buf, int stride, const Rect& r, Pixel pix) -{ - U16* ptr = (U16 *)buf; - int w = r.width(), h = r.height(), wBytes = w * 2; - - while (w > 0) { - *ptr++ = pix; w--; - } - h--; - - ptr = (U16 *)buf; - - while (h > 0) { - U16 *oldptr = ptr; - memcpy(ptr += stride, oldptr, wBytes); - h--; - } -} - -static void fillRect32(U8 *buf, int stride, const Rect& r, Pixel pix) -{ - U32* ptr = (U32 *)buf; - int w = r.width(), h = r.height(), wBytes = w * 4; - - while (w > 0) { - *ptr++ = pix; w--; - } - h--; - - ptr = (U32 *)buf; - - while (h > 0) { - U32 *oldptr = ptr; - memcpy(ptr += stride, oldptr, wBytes); - h--; - } -} - - FullFramePixelBuffer::FullFramePixelBuffer(const PixelFormat& pf, int w, int h, - rdr::U8* data_, ColourMap* cm) - : PixelBuffer(pf, w, h, cm), data(data_) + rdr::U8* data_, int stride_) + : PixelBuffer(pf, w, h), data(data_), stride(stride_) { - // Called again to configure the fill function - setPF(pf); } FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {} @@ -129,42 +72,33 @@ FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {} FullFramePixelBuffer::~FullFramePixelBuffer() {} -void FullFramePixelBuffer::setPF(const PixelFormat &pf) { - // We have this as a separate method for ManagedPixelBuffer's - // sake. Direct users of FullFramePixelBuffer aren't allowed - // to call it. - - PixelBuffer::setPF(pf); - - switch(pf.bpp) { - case 8: - fillRectFn = fillRect8; - break; - case 16: - fillRectFn = fillRect16; - break; - case 32: - fillRectFn = fillRect32; - break; - default: - throw Exception("rfb::FullFramePixelBuffer - Unsupported pixel format"); - } -} - - -int FullFramePixelBuffer::getStride() const { return width(); } - -rdr::U8* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride) +rdr::U8* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride_) { - *stride = getStride(); - return &data[(r.tl.x + (r.tl.y * *stride)) * format.bpp/8]; + *stride_ = stride; + return &data[(r.tl.x + (r.tl.y * stride)) * format.bpp/8]; } void FullFramePixelBuffer::fillRect(const Rect& r, Pixel pix) { int stride; - U8 *buf = getBufferRW(r, &stride); - fillRectFn(buf, stride, r, pix); + U8 *buf, pixbuf[4]; + int w, h, b; + + buf = getBufferRW(r, &stride); + w = r.width(); + h = r.height(); + b = format.bpp/8; + + format.bufferFromPixel(pixbuf, pix); + + while (h--) { + int w_ = w; + while (w_--) { + memcpy(buf, pixbuf, b); + buf += b; + } + buf += (stride - w) * b; + } } void FullFramePixelBuffer::imageRect(const Rect& r, const void* pixels, int srcStride) { @@ -314,40 +248,32 @@ void FullFramePixelBuffer::copyRect(const Rect &rect, const Point &move_by_delta // Automatically allocates enough space for the specified format & area ManagedPixelBuffer::ManagedPixelBuffer() - : datasize(0), own_colourmap(false) + : datasize(0) { checkDataSize(); }; ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h) - : FullFramePixelBuffer(pf, w, h, 0, 0), datasize(0), own_colourmap(false) + : FullFramePixelBuffer(pf, w, h, NULL, w), datasize(0) { checkDataSize(); }; ManagedPixelBuffer::~ManagedPixelBuffer() { if (data) delete [] data; - if (colourmap && own_colourmap) delete colourmap; }; void ManagedPixelBuffer::setPF(const PixelFormat &pf) { - FullFramePixelBuffer::setPF(pf); checkDataSize(); + format = pf; checkDataSize(); }; void ManagedPixelBuffer::setSize(int w, int h) { - width_ = w; height_ = h; checkDataSize(); + width_ = w; height_ = h; stride = w; checkDataSize(); }; -void -ManagedPixelBuffer::setColourMap(ColourMap* cm, bool own_cm) { - if (colourmap && own_colourmap) delete colourmap; - colourmap = cm; - own_colourmap = own_cm; -} - inline void ManagedPixelBuffer::checkDataSize() { unsigned long new_datasize = width_ * height_ * (format.bpp/8); diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h index 5c4f9666..59d71c79 100644 --- a/common/rfb/PixelBuffer.h +++ b/common/rfb/PixelBuffer.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014 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 @@ -24,9 +25,7 @@ #ifndef __RFB_PIXEL_BUFFER_H__ #define __RFB_PIXEL_BUFFER_H__ -#include <rfb/ImageGetter.h> #include <rfb/PixelFormat.h> -#include <rfb/ColourMap.h> #include <rfb/Rect.h> #include <rfb/Pixel.h> @@ -34,22 +33,18 @@ namespace rfb { class Region; - class PixelBuffer : public ImageGetter { + class PixelBuffer { public: - PixelBuffer(const PixelFormat& pf, int width, int height, ColourMap* cm); + PixelBuffer(const PixelFormat& pf, int width, int height); virtual ~PixelBuffer(); /////////////////////////////////////////////// // Format / Layout // - // Set/get pixel format & colourmap - protected: - // Only for subclasses that support changing parameters - virtual void setPF(const PixelFormat &pf); public: - virtual const PixelFormat &getPF() const; - virtual ColourMap* getColourMap() const; + // Get pixel format + const PixelFormat &getPF() const { return format; } // Get width, height and number of pixels int width() const { return width_; } @@ -75,8 +70,9 @@ namespace rfb { // Get pixel data for a given part of the buffer // Data is copied into the supplied buffer, with the specified - // stride. - virtual void getImage(void* imageBuf, const Rect& r, int stride=0); + // stride. Try to avoid using this though as getBuffer() will in + // most cases avoid the extra memory copy. + void getImage(void* imageBuf, const Rect& r, int stride=0); /////////////////////////////////////////////// // Framebuffer update methods @@ -91,7 +87,6 @@ namespace rfb { PixelBuffer(); PixelFormat format; int width_, height_; - ColourMap* colourmap; }; // FullFramePixelBuffer @@ -99,17 +94,10 @@ namespace rfb { class FullFramePixelBuffer : public PixelBuffer { public: FullFramePixelBuffer(const PixelFormat& pf, int width, int height, - rdr::U8* data_, ColourMap* cm); + rdr::U8* data, int stride); virtual ~FullFramePixelBuffer(); - protected: - virtual void setPF(const PixelFormat &pf); - public: - // - Get the number of pixels per row in the actual pixel buffer data area - // This may in some cases NOT be the same as width(). - virtual int getStride() const; - // Get a pointer to specified pixel data virtual const rdr::U8* getBuffer(const Rect& r, int* stride) { return getBufferRW(r, stride); @@ -121,30 +109,29 @@ namespace rfb { // These operations DO NOT clip to the pixelbuffer area, or trap overruns. // Fill a rectangle - virtual void fillRect(const Rect &dest, Pixel pix); + void fillRect(const Rect &dest, Pixel pix); // Copy pixel data to the buffer - virtual void imageRect(const Rect &dest, const void* pixels, int stride=0); + void imageRect(const Rect &dest, const void* pixels, int stride=0); // Copy pixel data from one PixelBuffer location to another - virtual void copyRect(const Rect &dest, const Point &move_by_delta); + 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. - virtual void maskRect(const Rect& r, const void* pixels, const void* mask_); + void maskRect(const Rect& r, const void* pixels, const void* mask_); // pixel is the Pixel value to be used where mask_ is set - virtual void maskRect(const Rect& r, Pixel pixel, const void* mask_); - - // *** Should this be visible? - rdr::U8* data; + void maskRect(const Rect& r, Pixel pixel, const void* mask_); protected: FullFramePixelBuffer(); - void (*fillRectFn)(rdr::U8 *, int, const Rect&, Pixel); + + rdr::U8* data; + int stride; }; // -=- Managed pixel buffer class @@ -160,15 +147,11 @@ namespace rfb { virtual void setPF(const PixelFormat &pf); virtual void setSize(int w, int h); - // Assign a colour map to the buffer - virtual void setColourMap(ColourMap* cm, bool own_cm); - // Return the total number of bytes of pixel data in the buffer int dataLen() const { return width_ * height_ * (format.bpp/8); } protected: unsigned long datasize; - bool own_colourmap; void checkDataSize(); }; diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index b11f8836..9e762d9d 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -53,16 +53,51 @@ PixelFormat::PixelFormat() bool PixelFormat::equal(const PixelFormat& other) const { - return (bpp == other.bpp && - depth == other.depth && - (bigEndian == other.bigEndian || bpp == 8) && - trueColour == other.trueColour && - (!trueColour || (redMax == other.redMax && - greenMax == other.greenMax && - blueMax == other.blueMax && - redShift == other.redShift && - greenShift == other.greenShift && - blueShift == other.blueShift))); + if (bpp != other.bpp || depth != other.depth) + return false; + + if (redMax != other.redMax) + return false; + if (greenMax != other.greenMax) + return false; + if (blueMax != other.blueMax) + return false; + + // Endianness requires more care to determine compatibility + if (bigEndian == other.bigEndian || bpp == 8) { + if (redShift != other.redShift) + return false; + if (greenShift != other.greenShift) + return false; + if (blueShift != other.blueShift) + return false; + } else { + // Has to be the same byte for each channel + if (redShift/8 != (3 - other.redShift/8)) + return false; + if (greenShift/8 != (3 - other.greenShift/8)) + return false; + if (blueShift/8 != (3 - other.blueShift/8)) + return false; + + // And the same bit offset within the byte + if (redShift%8 != other.redShift%8) + return false; + if (greenShift%8 != other.greenShift%8) + return false; + if (blueShift%8 != other.blueShift%8) + return false; + + // And not cross a byte boundary + if (redShift/8 != (redShift + redBits - 1)/8) + return false; + if (greenShift/8 != (greenShift + greenBits - 1)/8) + return false; + if (blueShift/8 != (blueShift + blueBits - 1)/8) + return false; + } + + return true; } void PixelFormat::read(rdr::InStream* is) @@ -79,6 +114,18 @@ void PixelFormat::read(rdr::InStream* is) blueShift = is->readU8(); is->skip(3); + // We have no real support for colour maps. If the client + // wants one, then we force a 8-bit true colour format and + // pretend it's a colour map. + if (!trueColour) { + redMax = 7; + greenMax = 7; + blueMax = 3; + redShift = 0; + greenShift = 3; + blueShift = 6; + } + if (!isSane()) throw Exception("invalid pixel format"); @@ -132,14 +179,13 @@ bool PixelFormat::isLittleEndian(void) const } -void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, - int pixels, ColourMap* cm) const +void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels) const { - bufferFromRGB(dst, src, pixels, pixels, 1, cm); + bufferFromRGB(dst, src, pixels, pixels, 1); } void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, - int w, int stride, int h, ColourMap* cm) const + int w, int stride, int h) const { if (is888()) { // Optimised common case @@ -188,7 +234,7 @@ void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, g = *(src++); b = *(src++); - p = pixelFromRGB(r, g, b, cm); + p = pixelFromRGB(r, g, b); bufferFromPixel(dst, p); dst += bpp/8; @@ -199,26 +245,14 @@ void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, } -void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, Colour* rgb) const -{ - rdr::U16 r, g, b; - - rgbFromPixel(p, cm, &r, &g, &b); - - rgb->r = r; - rgb->g = g; - rgb->b = b; -} - - -void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, ColourMap* cm) const +void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels) const { - rgbFromBuffer(dst, src, pixels, pixels, 1, cm); + rgbFromBuffer(dst, src, pixels, pixels, 1); } void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, - int w, int stride, int h, ColourMap* cm) const + int w, int stride, int h) const { if (is888()) { // Optimised common case @@ -260,7 +294,7 @@ void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, p = pixelFromBuffer(src); - rgbFromPixel(p, cm, &r, &g, &b); + rgbFromPixel(p, &r, &g, &b); *(dst++) = r; *(dst++) = g; @@ -449,36 +483,34 @@ bool PixelFormat::isSane(void) if (!trueColour && (depth != 8)) return false; - if (trueColour) { - if ((redMax & (redMax + 1)) != 0) - return false; - if ((greenMax & (greenMax + 1)) != 0) - return false; - if ((blueMax & (blueMax + 1)) != 0) - return false; + if ((redMax & (redMax + 1)) != 0) + return false; + if ((greenMax & (greenMax + 1)) != 0) + return false; + if ((blueMax & (blueMax + 1)) != 0) + return false; - /* - * We don't allow individual channels > 8 bits in order to keep our - * conversions simple. - */ - if (redMax >= (1 << 8)) - return false; - if (greenMax >= (1 << 8)) - return false; - if (blueMax >= (1 << 8)) - return false; + /* + * We don't allow individual channels > 8 bits in order to keep our + * conversions simple. + */ + if (redMax >= (1 << 8)) + return false; + if (greenMax >= (1 << 8)) + return false; + if (blueMax >= (1 << 8)) + return false; - totalBits = bits(redMax) + bits(greenMax) + bits(blueMax); - if (totalBits > bpp) - return false; + totalBits = bits(redMax) + bits(greenMax) + bits(blueMax); + if (totalBits > bpp) + return false; - if (((redMax << redShift) & (greenMax << greenShift)) != 0) - return false; - if (((redMax << redShift) & (blueMax << blueShift)) != 0) - return false; - if (((greenMax << greenShift) & (blueMax << blueShift)) != 0) - return false; - } + if (((redMax << redShift) & (greenMax << greenShift)) != 0) + return false; + if (((redMax << redShift) & (blueMax << blueShift)) != 0) + return false; + if (((greenMax << greenShift) & (blueMax << blueShift)) != 0) + return false; return true; } diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index a8408ddd..c3db8783 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -35,7 +35,6 @@ #define __RFB_PIXELFORMAT_H__ #include <rfb/Pixel.h> -#include <rfb/ColourMap.h> namespace rdr { class InStream; class OutStream; } @@ -44,9 +43,12 @@ namespace rfb { class PixelFormat { public: PixelFormat(int b, int d, bool e, bool t, - int rm=0, int gm=0, int bm=0, int rs=0, int gs=0, int bs=0); + int rm, int gm, int bm, int rs, int gs, int bs); PixelFormat(); + // Checks if the formats have identical buffer representation. + // They might still have different pixel representation, endianness + // or true colour state. bool equal(const PixelFormat& other) const; void read(rdr::InStream* is); @@ -59,20 +61,19 @@ namespace rfb { inline Pixel pixelFromBuffer(const rdr::U8* buffer) const; inline void bufferFromPixel(rdr::U8* buffer, Pixel pixel) const; - inline Pixel pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue, ColourMap* cm=0) const; - inline Pixel pixelFromRGB(rdr::U8 red, rdr::U8 green, rdr::U8 blue, ColourMap* cm=0) const; + inline Pixel pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue) const; + inline Pixel pixelFromRGB(rdr::U8 red, rdr::U8 green, rdr::U8 blue) const; - void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const; - void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int w, int stride, - int h, ColourMap* cm=0) const; + void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels) const; + void bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, + int w, int stride, int h) const; - void rgbFromPixel(Pixel pix, ColourMap* cm, Colour* rgb) const; - inline void rgbFromPixel(Pixel pix, ColourMap* cm, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const; - inline void rgbFromPixel(Pixel pix, ColourMap* cm, rdr::U8 *r, rdr::U8 *g, rdr::U8 *b) const; + inline void rgbFromPixel(Pixel pix, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const; + inline void rgbFromPixel(Pixel pix, rdr::U8 *r, rdr::U8 *g, rdr::U8 *b) const; - void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const; - void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int w, int stride, - int h, ColourMap* cm=0) const; + void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels) const; + void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, + int w, int stride, int h) const; void print(char* str, int len) const; bool parse(const char* str); @@ -84,6 +85,9 @@ namespace rfb { public: int bpp; int depth; + + // This only tracks if the client thinks it is in colour map mode. + // In practice we are always in true colour mode. bool trueColour; // FIXME: These should be protected, but we need to fix TransImageGetter first. diff --git a/common/rfb/PixelFormat.inl b/common/rfb/PixelFormat.inl index 547fae5d..4bc4a709 100644 --- a/common/rfb/PixelFormat.inl +++ b/common/rfb/PixelFormat.inl @@ -75,131 +75,81 @@ inline void PixelFormat::bufferFromPixel(rdr::U8* buffer, Pixel p) const } -inline Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue, ColourMap* cm) const +inline Pixel PixelFormat::pixelFromRGB(rdr::U16 red, rdr::U16 green, rdr::U16 blue) const { - if (trueColour) { - Pixel p; - - /* We don't need to mask since we shift out unwanted bits */ - p = ((Pixel)red >> (16 - redBits)) << redShift; - p |= ((Pixel)green >> (16 - greenBits)) << greenShift; - p |= ((Pixel)blue >> (16 - blueBits)) << blueShift; - } else if (cm) { - // Try to find the closest pixel by Cartesian distance - int colours = 1 << depth; - int diff = 256 * 256 * 4; - int col = 0; - for (int i=0; i<colours; i++) { - int r, g, b; - cm->lookup(i, &r, &g, &b); - int rd = (r-red) >> 8; - int gd = (g-green) >> 8; - int bd = (b-blue) >> 8; - int d = rd*rd + gd*gd + bd*bd; - if (d < diff) { - col = i; - diff = d; - } - } - return col; - } else { - // XXX just return 0 for colour map? - return 0; - } + Pixel p; + + /* We don't need to mask since we shift out unwanted bits */ + p = ((Pixel)red >> (16 - redBits)) << redShift; + p |= ((Pixel)green >> (16 - greenBits)) << greenShift; + p |= ((Pixel)blue >> (16 - blueBits)) << blueShift; + + return p; } -inline Pixel PixelFormat::pixelFromRGB(rdr::U8 red, rdr::U8 green, rdr::U8 blue, ColourMap* cm) const +inline Pixel PixelFormat::pixelFromRGB(rdr::U8 red, rdr::U8 green, rdr::U8 blue) const { - if (trueColour) { - Pixel p; + Pixel p; - p = ((Pixel)red >> (8 - redBits)) << redShift; - p |= ((Pixel)green >> (8 - greenBits)) << greenShift; - p |= ((Pixel)blue >> (8 - blueBits)) << blueShift; + p = ((Pixel)red >> (8 - redBits)) << redShift; + p |= ((Pixel)green >> (8 - greenBits)) << greenShift; + p |= ((Pixel)blue >> (8 - blueBits)) << blueShift; - return p; - } else { - return pixelFromRGB((rdr::U16)(red << 8 | red), - (rdr::U16)(green << 8 | green), - (rdr::U16)(blue << 8 | blue), cm); - } + return p; } -inline void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const +inline void PixelFormat::rgbFromPixel(Pixel p, rdr::U16 *r, rdr::U16 *g, rdr::U16 *b) const { - if (trueColour) { - int mb, rb, gb, bb; - - /* Bit replication is much cheaper than multiplication and division */ - - mb = minBits; - rb = redBits; - gb = greenBits; - bb = blueBits; - - *r = (p >> redShift) << (16 - rb); - *g = (p >> greenShift) << (16 - gb); - *b = (p >> blueShift) << (16 - bb); - - while (mb < 16) { - *r = *r | (*r >> rb); - *g = *g | (*g >> gb); - *b = *b | (*b >> bb); - mb <<= 1; - rb <<= 1; - gb <<= 1; - bb <<= 1; - } - } else if (cm) { - int ir, ig, ib; - cm->lookup(p, &ir, &ig, &ib); - *r = ir; - *g = ig; - *b = ib; - } else { - // XXX just return 0 for colour map? - *r = 0; - *g = 0; - *b = 0; + int mb, rb, gb, bb; + + /* Bit replication is much cheaper than multiplication and division */ + + mb = minBits; + rb = redBits; + gb = greenBits; + bb = blueBits; + + *r = (p >> redShift) << (16 - rb); + *g = (p >> greenShift) << (16 - gb); + *b = (p >> blueShift) << (16 - bb); + + while (mb < 16) { + *r = *r | (*r >> rb); + *g = *g | (*g >> gb); + *b = *b | (*b >> bb); + mb <<= 1; + rb <<= 1; + gb <<= 1; + bb <<= 1; } } -inline void PixelFormat::rgbFromPixel(Pixel p, ColourMap* cm, rdr::U8 *r, rdr::U8 *g, rdr::U8 *b) const +inline void PixelFormat::rgbFromPixel(Pixel p, rdr::U8 *r, rdr::U8 *g, rdr::U8 *b) const { - if (trueColour) { - int mb, rb, gb, bb; - - /* Bit replication is much cheaper than multiplication and division */ - - mb = minBits; - rb = redBits; - gb = greenBits; - bb = blueBits; - - *r = (p >> redShift) << (8 - rb); - *g = (p >> greenShift) << (8 - gb); - *b = (p >> blueShift) << (8 - bb); - - while (mb < 8) { - *r = *r | (*r >> rb); - *g = *g | (*g >> gb); - *b = *b | (*b >> bb); - mb <<= 1; - rb <<= 1; - gb <<= 1; - bb <<= 1; - } - } else { - rdr::U16 r2, g2, b2; - - rgbFromPixel(p, cm, &r2, &g2, &b2); - - *r = r2 >> 8; - *g = g2 >> 8; - *b = b2 >> 8; + int mb, rb, gb, bb; + + /* Bit replication is much cheaper than multiplication and division */ + + mb = minBits; + rb = redBits; + gb = greenBits; + bb = blueBits; + + *r = (p >> redShift) << (8 - rb); + *g = (p >> greenShift) << (8 - gb); + *b = (p >> blueShift) << (8 - bb); + + while (mb < 8) { + *r = *r | (*r >> rb); + *g = *g | (*g >> gb); + *b = *b | (*b >> bb); + mb <<= 1; + rb <<= 1; + gb <<= 1; + bb <<= 1; } } diff --git a/common/rfb/PixelTransformer.cxx b/common/rfb/PixelTransformer.cxx index cedf9000..73ec349b 100644 --- a/common/rfb/PixelTransformer.cxx +++ b/common/rfb/PixelTransformer.cxx @@ -22,10 +22,7 @@ #include <string.h> #include <rfb/PixelFormat.h> #include <rfb/Exception.h> -#include <rfb/ColourMap.h> -#include <rfb/TrueColourMap.h> #include <rfb/PixelBuffer.h> -#include <rfb/ColourCube.h> #include <rfb/PixelTransformer.h> using namespace rfb; @@ -100,50 +97,23 @@ static transFnType transRGBFns[][3] = { { transRGB16to8, transRGB16to16, transRGB16to32 }, { transRGB32to8, transRGB32to16, transRGB32to32 } }; -static transFnType transRGBCubeFns[][3] = { - { transRGBCube16to8, transRGBCube16to16, transRGBCube16to32 }, - { transRGBCube32to8, transRGBCube32to16, transRGBCube32to32 } -}; // Table initialisation functions. -typedef void (*initCMtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF, - ColourMap* cm, const PixelFormat& outPF); -typedef void (*initTCtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF, - const PixelFormat& outPF); -typedef void (*initCMtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF, - ColourMap* cm, ColourCube* cube); -typedef void (*initTCtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF, - ColourCube* cube); - +typedef void (*initFnType)(rdr::U8** tablep, const PixelFormat& inPF, + const PixelFormat& outPF); -static initCMtoTCFnType initSimpleCMtoTCFns[] = { - initSimpleCMtoTC8, initSimpleCMtoTC16, initSimpleCMtoTC32 +static initFnType initSimpleFns[] = { + initSimple8, initSimple16, initSimple32 }; -static initTCtoTCFnType initSimpleTCtoTCFns[] = { - initSimpleTCtoTC8, initSimpleTCtoTC16, initSimpleTCtoTC32 -}; - -static initCMtoCubeFnType initSimpleCMtoCubeFns[] = { - initSimpleCMtoCube8, initSimpleCMtoCube16, initSimpleCMtoCube32 -}; - -static initTCtoCubeFnType initSimpleTCtoCubeFns[] = { - initSimpleTCtoCube8, initSimpleTCtoCube16, initSimpleTCtoCube32 -}; - -static initTCtoTCFnType initRGBTCtoTCFns[] = { - initRGBTCtoTC8, initRGBTCtoTC16, initRGBTCtoTC32 -}; - -static initTCtoCubeFnType initRGBTCtoCubeFns[] = { - initRGBTCtoCube8, initRGBTCtoCube16, initRGBTCtoCube32 +static initFnType initRGBFns[] = { + initRGB8, initRGB16, initRGB32 }; PixelTransformer::PixelTransformer(bool econ) - : economic(econ), cmCallback(0), cube(0), table(0), transFn(0) + : economic(econ), table(0), transFn(0) { } @@ -152,17 +122,11 @@ PixelTransformer::~PixelTransformer() delete [] table; } -void PixelTransformer::init(const PixelFormat& inPF_, ColourMap* inCM_, - const PixelFormat& outPF_, ColourCube* cube_, - setCMFnType cmCallback_, void *cbData_) +void PixelTransformer::init(const PixelFormat& inPF_, + const PixelFormat& outPF_) { inPF = inPF_; - inCM = inCM_; - outPF = outPF_; - cube = cube_; - cmCallback = cmCallback_; - cbData = cbData_; if (table) delete [] table; @@ -175,79 +139,17 @@ void PixelTransformer::init(const PixelFormat& inPF_, ColourMap* inCM_, if ((outPF.bpp != 8) && (outPF.bpp != 16) && (outPF.bpp != 32)) throw Exception("PixelTransformer: bpp out not 8, 16 or 32"); - if (!outPF.trueColour) { - if (outPF.bpp != 8) - throw Exception("PixelTransformer: outPF has color map but not 8bpp"); - - if (!inPF.trueColour) { - if (inPF.bpp != 8) - throw Exception("PixelTransformer: inPF has colorMap but not 8bpp"); - if (!inCM) - throw Exception("PixelTransformer: inPF has colorMap but no colour map specified"); - - // CM to CM/Cube - - if (cube) { - transFn = transSimpleFns[0][0]; - (*initSimpleCMtoCubeFns[0]) (&table, inPF, inCM, cube); - } else { - transFn = noTransFn; - setColourMapEntries(0, 256); - } - return; - } - - // TC to CM/Cube - - ColourCube defaultCube(6,6,6); - if (!cube) cube = &defaultCube; - - if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) { - transFn = transRGBCubeFns[inPF.bpp/32][0]; - (*initRGBTCtoCubeFns[0]) (&table, inPF, cube); - } else { - transFn = transSimpleFns[inPF.bpp/16][0]; - (*initSimpleTCtoCubeFns[0]) (&table, inPF, cube); - } - - if (cube != &defaultCube) - return; - - if (!cmCallback) - throw Exception("PixelTransformer: Neither colour map callback nor colour cube provided"); - - cmCallback(0, 216, cube, cbData); - cube = 0; - return; - } - if (inPF.equal(outPF)) { transFn = noTransFn; return; } - if (!inPF.trueColour) { - - // CM to TC - - if (inPF.bpp != 8) - throw Exception("PixelTransformer: inPF has colorMap but not 8bpp"); - if (!inCM) - throw Exception("PixelTransformer: inPF has colorMap but no colour map specified"); - - transFn = transSimpleFns[0][outPF.bpp/16]; - (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, inCM, outPF); - return; - } - - // TC to TC - if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) { transFn = transRGBFns[inPF.bpp/32][outPF.bpp/16]; - (*initRGBTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF); + (*initRGBFns[outPF.bpp/16]) (&table, inPF, outPF); } else { transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16]; - (*initSimpleTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF); + (*initSimpleFns[outPF.bpp/16]) (&table, inPF, outPF); } } @@ -256,39 +158,11 @@ const PixelFormat &PixelTransformer::getInPF() const return inPF; } -const ColourMap *PixelTransformer::getInColourMap() const -{ - return inCM; -} - const PixelFormat &PixelTransformer::getOutPF() const { return outPF; } -const ColourCube *PixelTransformer::getOutColourCube() const -{ - return cube; -} - -void PixelTransformer::setColourMapEntries(int firstCol, int nCols) -{ - if (nCols == 0) - nCols = (1 << inPF.depth) - firstCol; - - if (inPF.trueColour) return; // shouldn't be called in this case - - if (outPF.trueColour) { - (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, inCM, outPF); - } else if (cube) { - (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, inPF, inCM, cube); - } else { - if (!cmCallback) - throw Exception("PixelTransformer: Neither colour map callback nor colour cube provided"); - cmCallback(firstCol, nCols, inCM, cbData); - } -} - void PixelTransformer::translatePixels(const void* inPtr, void* outPtr, int nPixels) const { diff --git a/common/rfb/PixelTransformer.h b/common/rfb/PixelTransformer.h index 88ec7c40..818daf66 100644 --- a/common/rfb/PixelTransformer.h +++ b/common/rfb/PixelTransformer.h @@ -33,11 +33,7 @@ namespace rfb { int outStride, int width, int height); class SMsgWriter; - class ColourMap; class PixelBuffer; - class ColourCube; - - typedef void (*setCMFnType)(int firstColour, int nColours, ColourMap* cm, void* data); class PixelTransformer { public: @@ -47,32 +43,12 @@ namespace rfb { // init() is called to initialise the translation tables. The inPF and // inCM arguments give the source format details, outPF gives the - // target pixel format. If the target has a colour map, then the you - // must specify either a colour map callback or a colour cube to indicate - // how the target colour map should be handled. If both are specified - // then the cube will be used. + // target pixel format. - void init(const PixelFormat& inPF, ColourMap* inCM, - const PixelFormat& outPF, ColourCube* cube = NULL, - setCMFnType cmCallback = NULL, void *cbData = NULL); + void init(const PixelFormat& inPF, const PixelFormat& outPF); const PixelFormat &getInPF() const; - const ColourMap *getInColourMap() const; - const PixelFormat &getOutPF() const; - const ColourCube *getOutColourCube() const; - - // setColourMapEntries() is called when the colour map specified to init() - // has changed. firstColour and nColours specify which part of the - // colour map has changed. If nColours is 0, this means the rest of the - // colour map. If the target also has a colour map, then the callback or - // cube specified to init() will be used. If the target is true colour - // then instead we update the internal translation table - in this case - // the caller should also make sure that the target surface receives an - // update of the relevant parts (the simplest thing to do is just update - // the whole framebuffer, though it is possible to be smarter than this). - - void setColourMapEntries(int firstColour, int nColours); // translatePixels() translates the given number of pixels from inPtr, // putting it into the buffer pointed to by outPtr. The pixels at inPtr @@ -91,12 +67,7 @@ namespace rfb { bool economic; PixelFormat inPF; - ColourMap* inCM; - PixelFormat outPF; - setCMFnType cmCallback; - void *cbData; - ColourCube* cube; rdr::U8* table; transFnType transFn; diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index b81a4a82..ecc97136 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -16,14 +16,12 @@ * USA. */ #include <rfb/CMsgReader.h> +#include <rfb/CConnection.h> #include <rfb/CMsgHandler.h> #include <rfb/RREDecoder.h> using namespace rfb; -#define EXTRA_ARGS CMsgHandler* handler -#define FILL_RECT(r, p) handler->fillRect(r, p) -#define IMAGE_RECT(r, p) handler->imageRect(r, p) #define BPP 8 #include <rfb/rreDecode.h> #undef BPP @@ -34,7 +32,7 @@ using namespace rfb; #include <rfb/rreDecode.h> #undef BPP -RREDecoder::RREDecoder(CMsgReader* reader_) : reader(reader_) +RREDecoder::RREDecoder(CConnection* conn) : Decoder(conn) { } @@ -44,8 +42,8 @@ RREDecoder::~RREDecoder() void RREDecoder::readRect(const Rect& r, CMsgHandler* handler) { - rdr::InStream* is = reader->getInStream(); - switch (reader->bpp()) { + rdr::InStream* is = conn->getInStream(); + switch (conn->cp.pf().bpp) { case 8: rreDecode8 (r, is, handler); break; case 16: rreDecode16(r, is, handler); break; case 32: rreDecode32(r, is, handler); break; diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h index 98abf982..7b6cc458 100644 --- a/common/rfb/RREDecoder.h +++ b/common/rfb/RREDecoder.h @@ -24,11 +24,9 @@ namespace rfb { class RREDecoder : public Decoder { public: - RREDecoder(CMsgReader* reader); + RREDecoder(CConnection* conn); virtual ~RREDecoder(); virtual void readRect(const Rect& r, CMsgHandler* handler); - private: - CMsgReader* reader; }; } #endif diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index 36d46955..a7af25db 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -19,6 +19,7 @@ #include <rfb/TransImageGetter.h> #include <rfb/encodings.h> #include <rfb/SMsgWriter.h> +#include <rfb/SConnection.h> #include <rfb/RREEncoder.h> using namespace rfb; @@ -33,7 +34,7 @@ using namespace rfb; #include <rfb/rreEncode.h> #undef BPP -RREEncoder::RREEncoder(SMsgWriter* writer_) : writer(writer_) +RREEncoder::RREEncoder(SConnection* conn) : RawEncoder(conn) { } @@ -41,30 +42,30 @@ RREEncoder::~RREEncoder() { } -bool RREEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) +void RREEncoder::writeRect(const Rect& r, TransImageGetter* ig) { int w = r.width(); int h = r.height(); - rdr::U8* imageBuf = writer->getImageBuf(w*h); + rdr::U8* imageBuf = conn->writer()->getImageBuf(w*h); ig->getImage(imageBuf, r); mos.clear(); int nSubrects = -1; - switch (writer->bpp()) { + switch (conn->cp.pf().bpp) { case 8: nSubrects = rreEncode8(imageBuf, w, h, &mos); break; case 16: nSubrects = rreEncode16(imageBuf, w, h, &mos); break; case 32: nSubrects = rreEncode32(imageBuf, w, h, &mos); break; } if (nSubrects < 0) { - return writer->writeRect(r, encodingRaw, ig, actual); + RawEncoder::writeRect(r, ig); + return; } - writer->startRect(r, encodingRRE); - rdr::OutStream* os = writer->getOutStream(); + conn->writer()->startRect(r, encodingRRE); + rdr::OutStream* os = conn->getOutStream(); os->writeU32(nSubrects); os->writeBytes(mos.data(), mos.length()); - writer->endRect(); - return true; + conn->writer()->endRect(); } diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h index f7d576eb..487344f2 100644 --- a/common/rfb/RREEncoder.h +++ b/common/rfb/RREEncoder.h @@ -19,17 +19,16 @@ #define __RFB_RREENCODER_H__ #include <rdr/MemOutStream.h> -#include <rfb/Encoder.h> +#include <rfb/RawEncoder.h> namespace rfb { - class RREEncoder : public Encoder { + class RREEncoder : public RawEncoder { public: - RREEncoder(SMsgWriter* writer); + RREEncoder(SConnection* conn); virtual ~RREEncoder(); - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); + virtual void writeRect(const Rect& r, TransImageGetter* ig); private: - SMsgWriter* writer; rdr::MemOutStream mos; }; } diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx index 5fd3b7c1..6ca02026 100644 --- a/common/rfb/RawDecoder.cxx +++ b/common/rfb/RawDecoder.cxx @@ -17,12 +17,13 @@ */ #include <rdr/InStream.h> #include <rfb/CMsgReader.h> +#include <rfb/CConnection.h> #include <rfb/CMsgHandler.h> #include <rfb/RawDecoder.h> using namespace rfb; -RawDecoder::RawDecoder(CMsgReader* reader_) : reader(reader_) +RawDecoder::RawDecoder(CConnection* conn) : Decoder(conn) { } @@ -37,12 +38,12 @@ void RawDecoder::readRect(const Rect& r, CMsgHandler* handler) int w = r.width(); int h = r.height(); int nPixels; - rdr::U8* imageBuf = reader->getImageBuf(w, w*h, &nPixels); - int bytesPerRow = w * (reader->bpp() / 8); + rdr::U8* imageBuf = conn->reader()->getImageBuf(w, w*h, &nPixels); + int bytesPerRow = w * (conn->cp.pf().bpp / 8); while (h > 0) { int nRows = nPixels / w; if (nRows > h) nRows = h; - reader->getInStream()->readBytes(imageBuf, nRows * bytesPerRow); + conn->getInStream()->readBytes(imageBuf, nRows * bytesPerRow); handler->imageRect(Rect(x, y, x+w, y+nRows), imageBuf); h -= nRows; y += nRows; diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h index e09cca2d..ca7c4017 100644 --- a/common/rfb/RawDecoder.h +++ b/common/rfb/RawDecoder.h @@ -24,11 +24,9 @@ namespace rfb { class RawDecoder : public Decoder { public: - RawDecoder(CMsgReader* reader); + RawDecoder(CConnection* conn); virtual ~RawDecoder(); virtual void readRect(const Rect& r, CMsgHandler* handler); - private: - CMsgReader* reader; }; } #endif diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx index 4b8de6ba..f7a4f3b8 100644 --- a/common/rfb/RawEncoder.cxx +++ b/common/rfb/RawEncoder.cxx @@ -19,11 +19,12 @@ #include <rfb/TransImageGetter.h> #include <rfb/encodings.h> #include <rfb/SMsgWriter.h> +#include <rfb/SConnection.h> #include <rfb/RawEncoder.h> using namespace rfb; -RawEncoder::RawEncoder(SMsgWriter* writer_) : writer(writer_) +RawEncoder::RawEncoder(SConnection* conn) : Encoder(conn) { } @@ -31,24 +32,23 @@ RawEncoder::~RawEncoder() { } -bool RawEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) +void RawEncoder::writeRect(const Rect& r, TransImageGetter* ig) { int x = r.tl.x; int y = r.tl.y; int w = r.width(); int h = r.height(); int nPixels; - rdr::U8* imageBuf = writer->getImageBuf(w, w*h, &nPixels); - int bytesPerRow = w * (writer->bpp() / 8); - writer->startRect(r, encodingRaw); + rdr::U8* imageBuf = conn->writer()->getImageBuf(w, w*h, &nPixels); + int bytesPerRow = w * (conn->cp.pf().bpp / 8); + conn->writer()->startRect(r, encodingRaw); while (h > 0) { int nRows = nPixels / w; if (nRows > h) nRows = h; ig->getImage(imageBuf, Rect(x, y, x+w, y+nRows)); - writer->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow); + conn->getOutStream()->writeBytes(imageBuf, nRows * bytesPerRow); h -= nRows; y += nRows; } - writer->endRect(); - return true; + conn->writer()->endRect(); } diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h index 22d45dbf..59e3a6de 100644 --- a/common/rfb/RawEncoder.h +++ b/common/rfb/RawEncoder.h @@ -24,11 +24,9 @@ namespace rfb { class RawEncoder : public Encoder { public: - RawEncoder(SMsgWriter* writer); + RawEncoder(SConnection* conn); virtual ~RawEncoder(); - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); - private: - SMsgWriter* writer; + virtual void writeRect(const Rect& r, TransImageGetter* ig); }; } #endif diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index ee573365..48acf0ac 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -22,8 +22,8 @@ #include <rfb/Security.h> #include <rfb/msgTypes.h> #include <rfb/fenceTypes.h> -#include <rfb/SMsgReaderV3.h> -#include <rfb/SMsgWriterV3.h> +#include <rfb/SMsgReader.h> +#include <rfb/SMsgWriter.h> #include <rfb/SConnection.h> #include <rfb/ServerCore.h> @@ -297,8 +297,8 @@ void SConnection::approveConnection(bool accept, const char* reason) if (accept) { state_ = RFBSTATE_INITIALISATION; - reader_ = new SMsgReaderV3(this, is); - writer_ = new SMsgWriterV3(&cp, os); + reader_ = new SMsgReader(this, is); + writer_ = new SMsgWriter(&cp, os); authSuccess(); } else { state_ = RFBSTATE_INVALID; @@ -306,10 +306,6 @@ void SConnection::approveConnection(bool accept, const char* reason) } } -void SConnection::setInitialColourMap() -{ -} - void SConnection::clientInit(bool shared) { writer_->writeServerInit(); @@ -320,6 +316,8 @@ void SConnection::setPixelFormat(const PixelFormat& pf) { SMsgHandler::setPixelFormat(pf); readyForSetColourMapEntries = true; + if (!pf.trueColour) + writeFakeColourMap(); } void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental) @@ -327,7 +325,7 @@ void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental) if (!readyForSetColourMapEntries) { readyForSetColourMapEntries = true; if (!cp.pf().trueColour) { - setInitialColourMap(); + writeFakeColourMap(); } } } @@ -347,3 +345,14 @@ void SConnection::enableContinuousUpdates(bool enable, int x, int y, int w, int h) { } + +void SConnection::writeFakeColourMap(void) +{ + int i; + rdr::U16 red[256], green[256], blue[256]; + + for (i = 0;i < 256;i++) + cp.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]); + + writer()->writeSetColourMapEntries(0, 256, red, green, blue); +} diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index a3a9fc8f..b6ff7cd5 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -102,11 +102,6 @@ namespace rfb { // SConnection::framebufferUpdateRequest(). virtual void framebufferUpdateRequest(const Rect& r, bool incremental); - // setInitialColourMap() is called when the client needs an initial - // SetColourMapEntries message. In fact this only happens when the client - // accepts the server's default pixel format and it uses a colour map. - virtual void setInitialColourMap(); - // fence() is called when we get a fence request or response. By default // it responds directly to requests (stating it doesn't support any // synchronisation) and drops responses. Override to implement more proper @@ -180,6 +175,7 @@ namespace rfb { protected: void setState(stateEnum s) { state_ = s; } + void writeFakeColourMap(void); bool readyForSetColourMapEntries; diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index 57ceb076..546506a9 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -93,11 +93,11 @@ namespace rfb { SStaticDesktop(const Point& size) : server(0), buffer(0) { PixelFormat pf; buffer = new ManagedPixelBuffer(pf, size.x, size.y); - if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y)); + if (buffer) buffer->fillRect(buffer->getRect(), 0); } SStaticDesktop(const Point& size, const PixelFormat& pf) : buffer(0) { buffer = new ManagedPixelBuffer(pf, size.x, size.y); - if (buffer) memset(buffer->data, 0, (pf.bpp/8) * (size.x*size.y)); + if (buffer) buffer->fillRect(buffer->getRect(), 0); } virtual ~SStaticDesktop() { if (buffer) delete buffer; diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 49d8dcf1..89c9a8fd 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -17,6 +18,7 @@ */ #include <stdio.h> #include <rdr/InStream.h> +#include <rfb/msgTypes.h> #include <rfb/Exception.h> #include <rfb/util.h> #include <rfb/SMsgHandler.h> @@ -39,6 +41,49 @@ SMsgReader::~SMsgReader() { } +void SMsgReader::readClientInit() +{ + bool shared = is->readU8(); + handler->clientInit(shared); +} + +void SMsgReader::readMsg() +{ + int msgType = is->readU8(); + switch (msgType) { + case msgTypeSetPixelFormat: + readSetPixelFormat(); + break; + case msgTypeSetEncodings: + readSetEncodings(); + break; + case msgTypeSetDesktopSize: + readSetDesktopSize(); + break; + case msgTypeFramebufferUpdateRequest: + readFramebufferUpdateRequest(); + break; + case msgTypeEnableContinuousUpdates: + readEnableContinuousUpdates(); + break; + case msgTypeClientFence: + readFence(); + break; + case msgTypeKeyEvent: + readKeyEvent(); + break; + case msgTypePointerEvent: + readPointerEvent(); + break; + case msgTypeClientCutText: + readClientCutText(); + break; + default: + fprintf(stderr, "unknown message type %d\n", msgType); + throw Exception("unknown message type"); + } +} + void SMsgReader::readSetPixelFormat() { is->skip(3); @@ -57,6 +102,36 @@ void SMsgReader::readSetEncodings() handler->setEncodings(nEncodings, encodings.buf); } +void SMsgReader::readSetDesktopSize() +{ + int width, height; + int screens, i; + rdr::U32 id, flags; + int sx, sy, sw, sh; + ScreenSet layout; + + is->skip(1); + + width = is->readU16(); + height = is->readU16(); + + screens = is->readU8(); + is->skip(1); + + for (i = 0;i < screens;i++) { + id = is->readU32(); + sx = is->readU16(); + sy = is->readU16(); + sw = is->readU16(); + sh = is->readU16(); + flags = is->readU32(); + + layout.add_screen(Screen(id, sx, sy, sw, sh, flags)); + } + + handler->setDesktopSize(width, height, layout); +} + void SMsgReader::readFramebufferUpdateRequest() { bool inc = is->readU8(); @@ -67,6 +142,43 @@ void SMsgReader::readFramebufferUpdateRequest() handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc); } +void SMsgReader::readEnableContinuousUpdates() +{ + bool enable; + int x, y, w, h; + + enable = is->readU8(); + + x = is->readU16(); + y = is->readU16(); + w = is->readU16(); + h = is->readU16(); + + handler->enableContinuousUpdates(enable, x, y, w, h); +} + +void SMsgReader::readFence() +{ + rdr::U32 flags; + rdr::U8 len; + char data[64]; + + is->skip(3); + + flags = is->readU32(); + + len = is->readU8(); + if (len > sizeof(data)) { + fprintf(stderr, "Ignoring fence with too large payload\n"); + is->skip(len); + return; + } + + is->readBytes(data, len); + + handler->fence(flags, len, data); +} + void SMsgReader::readKeyEvent() { bool down = is->readU8(); diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h index e6e40448..00cb3031 100644 --- a/common/rfb/SMsgReader.h +++ b/common/rfb/SMsgReader.h @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -30,24 +31,29 @@ namespace rfb { class SMsgReader { public: + SMsgReader(SMsgHandler* handler, rdr::InStream* is); virtual ~SMsgReader(); - virtual void readClientInit()=0; + void readClientInit(); // readMsg() reads a message, calling the handler as appropriate. - virtual void readMsg()=0; + void readMsg(); rdr::InStream* getInStream() { return is; } protected: - virtual void readSetPixelFormat(); - virtual void readSetEncodings(); - virtual void readFramebufferUpdateRequest(); - virtual void readKeyEvent(); - virtual void readPointerEvent(); - virtual void readClientCutText(); + void readSetPixelFormat(); + void readSetEncodings(); + void readSetDesktopSize(); - SMsgReader(SMsgHandler* handler, rdr::InStream* is); + void readFramebufferUpdateRequest(); + void readEnableContinuousUpdates(); + + void readFence(); + + void readKeyEvent(); + void readPointerEvent(); + void readClientCutText(); SMsgHandler* handler; rdr::InStream* is; diff --git a/common/rfb/SMsgReaderV3.cxx b/common/rfb/SMsgReaderV3.cxx deleted file mode 100644 index cd957b9a..00000000 --- a/common/rfb/SMsgReaderV3.cxx +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#include <stdio.h> -#include <rfb/PixelFormat.h> -#include <rfb/msgTypes.h> -#include <rfb/Exception.h> -#include <rdr/InStream.h> -#include <rfb/SMsgReaderV3.h> -#include <rfb/SMsgHandler.h> -#include <rfb/ScreenSet.h> - -using namespace rfb; - -SMsgReaderV3::SMsgReaderV3(SMsgHandler* handler, rdr::InStream* is) - : SMsgReader(handler, is) -{ -} - -SMsgReaderV3::~SMsgReaderV3() -{ -} - -void SMsgReaderV3::readClientInit() -{ - bool shared = is->readU8(); - handler->clientInit(shared); -} - -void SMsgReaderV3::readMsg() -{ - int msgType = is->readU8(); - switch (msgType) { - case msgTypeSetPixelFormat: readSetPixelFormat(); break; - case msgTypeSetEncodings: readSetEncodings(); break; - case msgTypeFramebufferUpdateRequest: readFramebufferUpdateRequest(); break; - case msgTypeKeyEvent: readKeyEvent(); break; - case msgTypePointerEvent: readPointerEvent(); break; - case msgTypeClientCutText: readClientCutText(); break; - case msgTypeSetDesktopSize: readSetDesktopSize(); break; - case msgTypeClientFence: readFence(); break; - case msgTypeEnableContinuousUpdates: readEnableContinuousUpdates(); break; - - default: - fprintf(stderr, "unknown message type %d\n", msgType); - throw Exception("unknown message type"); - } -} - -void SMsgReaderV3::readSetDesktopSize() -{ - int width, height; - int screens, i; - rdr::U32 id, flags; - int sx, sy, sw, sh; - ScreenSet layout; - - is->skip(1); - - width = is->readU16(); - height = is->readU16(); - - screens = is->readU8(); - is->skip(1); - - for (i = 0;i < screens;i++) { - id = is->readU32(); - sx = is->readU16(); - sy = is->readU16(); - sw = is->readU16(); - sh = is->readU16(); - flags = is->readU32(); - - layout.add_screen(Screen(id, sx, sy, sw, sh, flags)); - } - - handler->setDesktopSize(width, height, layout); -} - -void SMsgReaderV3::readFence() -{ - rdr::U32 flags; - rdr::U8 len; - char data[64]; - - is->skip(3); - - flags = is->readU32(); - - len = is->readU8(); - if (len > sizeof(data)) { - fprintf(stderr, "Ignoring fence with too large payload\n"); - is->skip(len); - return; - } - - is->readBytes(data, len); - - handler->fence(flags, len, data); -} - -void SMsgReaderV3::readEnableContinuousUpdates() -{ - bool enable; - int x, y, w, h; - - enable = is->readU8(); - - x = is->readU16(); - y = is->readU16(); - w = is->readU16(); - h = is->readU16(); - - handler->enableContinuousUpdates(enable, x, y, w, h); -} diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 509ffbf5..40e6d7f6 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -1,5 +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 * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,9 +21,11 @@ #include <assert.h> #include <rdr/OutStream.h> #include <rfb/msgTypes.h> -#include <rfb/ColourMap.h> +#include <rfb/fenceTypes.h> +#include <rfb/Exception.h> #include <rfb/ConnParams.h> #include <rfb/UpdateTracker.h> +#include <rfb/Encoder.h> #include <rfb/SMsgWriter.h> #include <rfb/LogWriter.h> @@ -31,12 +34,14 @@ using namespace rfb; static LogWriter vlog("SMsgWriter"); SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_) - : imageBufIdealSize(0), cp(cp_), os(os_), lenBeforeRect(0), - currentEncoding(0), updatesSent(0), rawBytesEquivalent(0), + : imageBufIdealSize(0), cp(cp_), os(os_), currentEncoding(0), + nRectsInUpdate(0), nRectsInHeader(0), + wsccb(0), needSetDesktopSize(false), + needExtendedDesktopSize(false), needSetDesktopName(false), + lenBeforeRect(0), updatesSent(0), rawBytesEquivalent(0), imageBuf(0), imageBufSize(0) { for (int i = 0; i <= encodingMax; i++) { - encoders[i] = 0; bytesSent[i] = 0; rectsSent[i] = 0; } @@ -47,7 +52,6 @@ SMsgWriter::~SMsgWriter() vlog.info("framebuffer updates %d",updatesSent); int bytes = 0; for (int i = 0; i <= encodingMax; i++) { - delete encoders[i]; if (i != encodingCopyRect) bytes += bytesSent[i]; if (rectsSent[i]) @@ -59,19 +63,28 @@ SMsgWriter::~SMsgWriter() delete [] imageBuf; } +void SMsgWriter::writeServerInit() +{ + os->writeU16(cp->width); + os->writeU16(cp->height); + cp->pf().write(os); + os->writeString(cp->name()); + endMsg(); +} + void SMsgWriter::writeSetColourMapEntries(int firstColour, int nColours, - ColourMap* cm) + const rdr::U16 red[], + const rdr::U16 green[], + const rdr::U16 blue[]) { startMsg(msgTypeSetColourMapEntries); os->pad(1); os->writeU16(firstColour); os->writeU16(nColours); for (int i = firstColour; i < firstColour+nColours; i++) { - int r, g, b; - cm->lookup(i, &r, &g, &b); - os->writeU16(r); - os->writeU16(g); - os->writeU16(b); + os->writeU16(red[i]); + os->writeU16(green[i]); + os->writeU16(blue[i]); } endMsg(); } @@ -91,83 +104,204 @@ void SMsgWriter::writeServerCutText(const char* str, int len) endMsg(); } -void SMsgWriter::setupCurrentEncoder() +void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) { - int encoding = cp->currentEncoding(); + if (!cp->supportsFence) + throw Exception("Client does not support fences"); + if (len > 64) + throw Exception("Too large fence payload"); + if ((flags & ~fenceFlagsSupported) != 0) + throw Exception("Unknown fence flags"); - // FIXME: Code duplication, see writeRect(). - if (!encoders[encoding]) { - encoders[encoding] = Encoder::createEncoder(encoding, this); - assert(encoders[encoding]); - } + startMsg(msgTypeServerFence); + os->pad(3); + + os->writeU32(flags); + + os->writeU8(len); + os->writeBytes(data, len); + + endMsg(); +} + +void SMsgWriter::writeEndOfContinuousUpdates() +{ + if (!cp->supportsContinuousUpdates) + throw Exception("Client does not support continuous updates"); + + startMsg(msgTypeEndOfContinuousUpdates); + endMsg(); +} + +bool SMsgWriter::writeSetDesktopSize() { + if (!cp->supportsDesktopResize) + return false; + + needSetDesktopSize = true; + + return true; +} + +bool SMsgWriter::writeExtendedDesktopSize() { + if (!cp->supportsExtendedDesktopSize) + return false; + + needExtendedDesktopSize = true; + + return true; +} + +bool SMsgWriter::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, + int fb_width, int fb_height, + const ScreenSet& layout) { + ExtendedDesktopSizeMsg msg; - encoders[encoding]->setCompressLevel(cp->compressLevel); - encoders[encoding]->setQualityLevel(cp->qualityLevel); - encoders[encoding]->setFineQualityLevel(cp->fineQualityLevel, - cp->subsampling); + if (!cp->supportsExtendedDesktopSize) + return false; + + msg.reason = reason; + msg.result = result; + msg.fb_width = fb_width; + msg.fb_height = fb_height; + msg.layout = layout; + + extendedDesktopSizeMsgs.push_back(msg); + + return true; +} + +bool SMsgWriter::writeSetDesktopName() { + if (!cp->supportsDesktopRename) + return false; + + needSetDesktopName = true; + + return true; } -int SMsgWriter::getNumRects(const Rect &r) +void SMsgWriter::cursorChange(WriteSetCursorCallback* cb) { - int encoding = cp->currentEncoding(); + wsccb = cb; +} + +void SMsgWriter::writeSetCursor(int width, int height, const Point& hotspot, + void* data, void* mask) +{ + if (!wsccb) + return; - if (!encoders[encoding]) - setupCurrentEncoder(); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetCursor: nRects out of sync"); - return encoders[encoding]->getNumRects(r); + os->writeS16(hotspot.x); + os->writeS16(hotspot.y); + os->writeU16(width); + os->writeU16(height); + os->writeU32(pseudoEncodingCursor); + os->writeBytes(data, width * height * (cp->pf().bpp/8)); + os->writeBytes(mask, (width+7)/8 * height); +} + +void SMsgWriter::writeSetXCursor(int width, int height, int hotspotX, + int hotspotY, void* data, void* mask) +{ + if (!wsccb) + return; + + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetXCursor: nRects out of sync"); + + os->writeS16(hotspotX); + os->writeS16(hotspotY); + os->writeU16(width); + os->writeU16(height); + os->writeU32(pseudoEncodingXCursor); + // FIXME: We only support black and white cursors, currently. We + // could pass the correct color by using the pix0/pix1 values + // returned from getBitmap, in writeSetCursorCallback. However, we + // would then need to undo the conversion from rgb to Pixel that is + // done by FakeAllocColor. + if (width * height) { + os->writeU8(0); + os->writeU8(0); + os->writeU8(0); + os->writeU8(255); + os->writeU8(255); + os->writeU8(255); + os->writeBytes(data, (width+7)/8 * height); + os->writeBytes(mask, (width+7)/8 * height); + } } bool SMsgWriter::needFakeUpdate() { - return false; + return wsccb || needSetDesktopName || needNoDataUpdate(); } bool SMsgWriter::needNoDataUpdate() { - return false; + return needSetDesktopSize || needExtendedDesktopSize || + !extendedDesktopSizeMsgs.empty(); } void SMsgWriter::writeNoDataUpdate() { - // This class has no pseudo-rectangles so there is nothing to do here - vlog.error("writeNoDataUpdate() called"); -} + int nRects; -void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig, - Region* updatedRegion) -{ - std::vector<Rect> rects; - std::vector<Rect>::const_iterator i; - updatedRegion->copyFrom(ui.changed); - updatedRegion->assign_union(ui.copied); + nRects = 0; - ui.copied.get_rects(&rects, ui.copy_delta.x <= 0, ui.copy_delta.y <= 0); - for (i = rects.begin(); i != rects.end(); i++) - writeCopyRect(*i, i->tl.x - ui.copy_delta.x, i->tl.y - ui.copy_delta.y); + if (needSetDesktopSize) + nRects++; + if (needExtendedDesktopSize) + nRects++; + if (!extendedDesktopSizeMsgs.empty()) + nRects += extendedDesktopSizeMsgs.size(); - ui.changed.get_rects(&rects); - for (i = rects.begin(); i != rects.end(); i++) { - Rect actual; - if (!writeRect(*i, ig, &actual)) { - updatedRegion->assign_subtract(*i); - updatedRegion->assign_union(actual); - } - } + writeFramebufferUpdateStart(nRects); + writeNoDataRects(); + writeFramebufferUpdateEnd(); } -bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) +void SMsgWriter::writeFramebufferUpdateStart(int nRects) { - return writeRect(r, cp->currentEncoding(), ig, actual); + startMsg(msgTypeFramebufferUpdate); + os->pad(1); + + if (nRects != 0xFFFF) { + if (wsccb) + nRects++; + if (needSetDesktopName) + nRects++; + } + + os->writeU16(nRects); + + nRectsInUpdate = 0; + if (nRects == 0xFFFF) + nRectsInHeader = 0; + else + nRectsInHeader = nRects; + + writePseudoRects(); } -bool SMsgWriter::writeRect(const Rect& r, int encoding, - TransImageGetter* ig, Rect* actual) +void SMsgWriter::writeFramebufferUpdateEnd() { - if (!encoders[encoding]) { - encoders[encoding] = Encoder::createEncoder(encoding, this); - assert(encoders[encoding]); + if (nRectsInUpdate != nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeFramebufferUpdateEnd: " + "nRects out of sync"); + + if (nRectsInHeader == 0) { + // Send last rect. marker + os->writeS16(0); + os->writeS16(0); + os->writeU16(0); + os->writeU16(0); + os->writeU32(pseudoEncodingLastRect); } - return encoders[encoding]->writeRect(r, ig, actual); + + updatesSent++; + endMsg(); } void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY) @@ -178,6 +312,31 @@ void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY) endRect(); } +void SMsgWriter::startRect(const Rect& r, int encoding) +{ + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::startRect: nRects out of sync"); + + currentEncoding = encoding; + lenBeforeRect = os->length(); + if (encoding != encodingCopyRect) + rawBytesEquivalent += 12 + r.width() * r.height() * (cp->pf().bpp/8); + + os->writeS16(r.tl.x); + os->writeS16(r.tl.y); + os->writeU16(r.width()); + os->writeU16(r.height()); + os->writeU32(encoding); +} + +void SMsgWriter::endRect() +{ + if (currentEncoding <= encodingMax) { + bytesSent[currentEncoding] += os->length() - lenBeforeRect; + rectsSent[currentEncoding]++; + } +} + rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels) { int requiredBytes = required * (cp->pf().bpp / 8); @@ -198,7 +357,115 @@ rdr::U8* SMsgWriter::getImageBuf(int required, int requested, int* nPixels) return imageBuf; } -int SMsgWriter::bpp() +void SMsgWriter::startMsg(int type) +{ + os->writeU8(type); +} + +void SMsgWriter::endMsg() +{ + os->flush(); +} + +void SMsgWriter::writePseudoRects() +{ + if (wsccb) { + wsccb->writeSetCursorCallback(); + wsccb = 0; + } + + if (needSetDesktopName) { + writeSetDesktopNameRect(cp->name()); + needSetDesktopName = false; + } +} + +void SMsgWriter::writeNoDataRects() { - return cp->pf().bpp; + // Start with specific ExtendedDesktopSize messages + if (!extendedDesktopSizeMsgs.empty()) { + std::list<ExtendedDesktopSizeMsg>::const_iterator ri; + + for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) { + writeExtendedDesktopSizeRect(ri->reason, ri->result, + ri->fb_width, ri->fb_height, ri->layout); + } + + extendedDesktopSizeMsgs.clear(); + } + + // Send this before SetDesktopSize to make life easier on the clients + if (needExtendedDesktopSize) { + writeExtendedDesktopSizeRect(0, 0, cp->width, cp->height, + cp->screenLayout); + needExtendedDesktopSize = false; + } + + // Some clients assume this is the last rectangle so don't send anything + // more after this + if (needSetDesktopSize) { + writeSetDesktopSizeRect(cp->width, cp->height); + needSetDesktopSize = false; + } +} + +void SMsgWriter::writeSetDesktopSizeRect(int width, int height) +{ + if (!cp->supportsDesktopResize) + throw Exception("Client does not support desktop resize"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync"); + + os->writeS16(0); + os->writeS16(0); + os->writeU16(width); + os->writeU16(height); + os->writeU32(pseudoEncodingDesktopSize); +} + +void SMsgWriter::writeExtendedDesktopSizeRect(rdr::U16 reason, + rdr::U16 result, + int fb_width, + int fb_height, + const ScreenSet& layout) +{ + ScreenSet::const_iterator si; + + if (!cp->supportsExtendedDesktopSize) + throw Exception("Client does not support extended desktop resize"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync"); + + os->writeU16(reason); + os->writeU16(result); + os->writeU16(fb_width); + os->writeU16(fb_height); + os->writeU32(pseudoEncodingExtendedDesktopSize); + + os->writeU8(layout.num_screens()); + os->pad(3); + + for (si = layout.begin();si != layout.end();++si) { + os->writeU32(si->id); + os->writeU16(si->dimensions.tl.x); + os->writeU16(si->dimensions.tl.y); + os->writeU16(si->dimensions.width()); + os->writeU16(si->dimensions.height()); + os->writeU32(si->flags); + } +} + +void SMsgWriter::writeSetDesktopNameRect(const char *name) +{ + if (!cp->supportsDesktopRename) + throw Exception("Client does not support desktop rename"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetDesktopNameRect: nRects out of sync"); + + os->writeS16(0); + os->writeS16(0); + os->writeU16(0); + os->writeU16(0); + os->writeU32(pseudoEncodingDesktopName); + os->writeString(name); } diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index edf29447..c3ee4577 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB + * Copyright 2009-2014 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 @@ -25,21 +25,14 @@ #include <rdr/types.h> #include <rfb/encodings.h> -#include <rfb/screenTypes.h> -#include <rfb/Encoder.h> -#include <rfb/PixelBuffer.h> #include <rfb/ScreenSet.h> namespace rdr { class OutStream; } namespace rfb { - class PixelFormat; class ConnParams; - class ImageGetter; - class ColourMap; - class Region; - class UpdateInfo; + class ScreenSet; class WriteSetCursorCallback { public: @@ -48,111 +41,86 @@ namespace rfb { class SMsgWriter { public: + SMsgWriter(ConnParams* cp, rdr::OutStream* os); virtual ~SMsgWriter(); // writeServerInit() must only be called at the appropriate time in the // protocol initialisation. - virtual void writeServerInit()=0; + void writeServerInit(); // Methods to write normal protocol messages // writeSetColourMapEntries() writes a setColourMapEntries message, using - // the given ColourMap object to lookup the RGB values of the given range - // of colours. - virtual void writeSetColourMapEntries(int firstColour, int nColours, - ColourMap* cm); + // the given colour entries. + void writeSetColourMapEntries(int firstColour, int nColours, + const rdr::U16 red[], + const rdr::U16 green[], + const rdr::U16 blue[]); // writeBell() and writeServerCutText() do the obvious thing. - virtual void writeBell(); - virtual void writeServerCutText(const char* str, int len); + void writeBell(); + void writeServerCutText(const char* str, int len); // writeFence() sends a new fence request or response to the client. - virtual void writeFence(rdr::U32 flags, unsigned len, const char data[])=0; + void writeFence(rdr::U32 flags, unsigned len, const char data[]); // writeEndOfContinuousUpdates() indicates that we have left continuous // updates mode. - virtual void writeEndOfContinuousUpdates()=0; - - // setupCurrentEncoder() should be called before each framebuffer update, - // prior to calling getNumRects() or writeFramebufferUpdateStart(). - void setupCurrentEncoder(); - - // getNumRects() computes the number of sub-rectangles that will compose a - // given rectangle, for current encoder. - int getNumRects(const Rect &r); + void writeEndOfContinuousUpdates(); - // writeSetDesktopSize() on a V3 writer won't actually write immediately, - // but will write the relevant pseudo-rectangle as part of the next update. - virtual bool writeSetDesktopSize()=0; + // writeSetDesktopSize() won't actually write immediately, but will + // write the relevant pseudo-rectangle as part of the next update. + bool writeSetDesktopSize(); // Same thing for the extended version. The first version queues up a // generic update of the current server state, but the second queues a // specific message. - virtual bool writeExtendedDesktopSize()=0; - virtual bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, - int fb_width, int fb_height, - const ScreenSet& layout)=0; + bool writeExtendedDesktopSize(); + bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, + int fb_width, int fb_height, + const ScreenSet& layout); - virtual bool writeSetDesktopName()=0; + bool writeSetDesktopName(); // Like setDesktopSize, we can't just write out a setCursor message - // immediately on a V3 writer. Instead of calling writeSetCursor() - // directly, you must call cursorChange(), and then invoke writeSetCursor() - // in response to the writeSetCursorCallback() callback. For a V3 writer - // this will happen when the next update is sent. - virtual void cursorChange(WriteSetCursorCallback* cb)=0; - virtual void writeSetCursor(int width, int height, const Point& hotspot, - void* data, void* mask)=0; - virtual void writeSetXCursor(int width, int height, int hotspotX, - int hotspotY, void* data, void* mask)=0; + // immediately. Instead of calling writeSetCursor() directly, + // you must call cursorChange(), and then invoke writeSetCursor() + // in response to the writeSetCursorCallback() callback. This will + // happen when the next update is sent. + void cursorChange(WriteSetCursorCallback* cb); + void writeSetCursor(int width, int height, const Point& hotspot, + void* data, void* mask); + void writeSetXCursor(int width, int height, int hotspotX, int hotspotY, + void* data, void* mask); // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. - virtual bool needFakeUpdate(); + bool needFakeUpdate(); // needNoDataUpdate() returns true when an update without any // framebuffer changes need to be sent (using writeNoDataUpdate()). // Commonly this is an update that modifies the size of the framebuffer // or the screen layout. - virtual bool needNoDataUpdate(); + bool needNoDataUpdate(); // writeNoDataUpdate() write a framebuffer update containing only // pseudo-rectangles. - virtual void writeNoDataUpdate(); - - // writeRects() accepts an UpdateInfo (changed & copied regions) and an - // ImageGetter to fetch pixels from. It then calls writeCopyRect() and - // writeRect() as appropriate. writeFramebufferUpdateStart() must be used - // before the first writeRects() call and writeFrameBufferUpdateEnd() after - // the last one. It returns the actual region sent to the client, which - // may be smaller than the update passed in. - virtual void writeRects(const UpdateInfo& update, TransImageGetter* ig, - Region* updatedRegion); - - // To construct a framebuffer update you can call - // writeFramebufferUpdateStart(), followed by a number of writeCopyRect()s - // and writeRect()s, finishing with writeFramebufferUpdateEnd(). If you - // know the exact number of rectangles ahead of time you can specify it to - // writeFramebufferUpdateStart() which can be more efficient. - virtual void writeFramebufferUpdateStart(int nRects)=0; - virtual void writeFramebufferUpdateStart()=0; - virtual void writeFramebufferUpdateEnd()=0; - - // writeRect() tries to write the given rectangle. If it is unable to - // write the whole rectangle it returns false and sets actual to the actual - // rectangle which was updated. - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); - virtual bool writeRect(const Rect& r, int encoding, - TransImageGetter* ig, Rect* actual); - - virtual void writeCopyRect(const Rect& r, int srcX, int srcY); - - virtual void startRect(const Rect& r, int enc)=0; - virtual void endRect()=0; - - ConnParams* getConnParams() { return cp; } - rdr::OutStream* getOutStream() { return os; } + void writeNoDataUpdate(); + + // writeFramebufferUpdateStart() initiates an update which you can fill + // in using writeCopyRect() and encoders. Finishing the update by calling + // writeFramebufferUpdateEnd(). + void writeFramebufferUpdateStart(int nRects); + void writeFramebufferUpdateEnd(); + + // There is no explicit encoder for CopyRect rects. + void writeCopyRect(const Rect& r, int srcX, int srcY); + + // Encoders should call these to mark the start and stop of individual + // rects. + void startRect(const Rect& r, int enc); + void endRect(); + rdr::U8* getImageBuf(int required, int requested=0, int* nPixels=0); - int bpp(); int getUpdatesSent() { return updatesSent; } int getRectsSent(int encoding) { return rectsSent[encoding]; } @@ -162,17 +130,34 @@ namespace rfb { int imageBufIdealSize; protected: - SMsgWriter(ConnParams* cp, rdr::OutStream* os); + void startMsg(int type); + void endMsg(); + + void writePseudoRects(); + void writeNoDataRects(); - virtual void startMsg(int type)=0; - virtual void endMsg()=0; + void writeSetDesktopSizeRect(int width, int height); + void writeExtendedDesktopSizeRect(rdr::U16 reason, rdr::U16 result, + int fb_width, int fb_height, + const ScreenSet& layout); + void writeSetDesktopNameRect(const char *name); ConnParams* cp; rdr::OutStream* os; - Encoder* encoders[encodingMax+1]; - int lenBeforeRect; int currentEncoding; + + int nRectsInUpdate; + int nRectsInHeader; + + WriteSetCursorCallback* wsccb; + + bool needSetDesktopSize; + bool needExtendedDesktopSize; + bool needSetDesktopName; + bool needLastRect; + + int lenBeforeRect; int updatesSent; int bytesSent[encodingMax+1]; int rectsSent[encodingMax+1]; @@ -180,6 +165,14 @@ namespace rfb { rdr::U8* imageBuf; int imageBufSize; + + typedef struct { + rdr::U16 reason, result; + int fb_width, fb_height; + ScreenSet layout; + } ExtendedDesktopSizeMsg; + + std::list<ExtendedDesktopSizeMsg> extendedDesktopSizeMsgs; }; } #endif diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx deleted file mode 100644 index 86f35078..00000000 --- a/common/rfb/SMsgWriterV3.cxx +++ /dev/null @@ -1,399 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB - * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#include <rdr/OutStream.h> -#include <rdr/MemOutStream.h> -#include <rfb/msgTypes.h> -#include <rfb/screenTypes.h> -#include <rfb/fenceTypes.h> -#include <rfb/Exception.h> -#include <rfb/ConnParams.h> -#include <rfb/SMsgWriterV3.h> - -using namespace rfb; - -SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os) - : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0), - nRectsInHeader(0), wsccb(0), needSetDesktopSize(false), - needExtendedDesktopSize(false), needSetDesktopName(false) -{ -} - -SMsgWriterV3::~SMsgWriterV3() -{ - delete updateOS; -} - -void SMsgWriterV3::writeServerInit() -{ - os->writeU16(cp->width); - os->writeU16(cp->height); - cp->pf().write(os); - os->writeString(cp->name()); - endMsg(); -} - -void SMsgWriterV3::startMsg(int type) -{ - if (os != realOS) - throw Exception("startMsg called while writing an update?"); - - os->writeU8(type); -} - -void SMsgWriterV3::endMsg() -{ - os->flush(); -} - -void SMsgWriterV3::writeFence(rdr::U32 flags, unsigned len, const char data[]) -{ - if (!cp->supportsFence) - throw Exception("Client does not support fences"); - if (len > 64) - throw Exception("Too large fence payload"); - if ((flags & ~fenceFlagsSupported) != 0) - throw Exception("Unknown fence flags"); - - startMsg(msgTypeServerFence); - os->pad(3); - - os->writeU32(flags); - - os->writeU8(len); - os->writeBytes(data, len); - - endMsg(); -} - -void SMsgWriterV3::writeEndOfContinuousUpdates() -{ - if (!cp->supportsContinuousUpdates) - throw Exception("Client does not support continuous updates"); - - startMsg(msgTypeEndOfContinuousUpdates); - endMsg(); -} - -bool SMsgWriterV3::writeSetDesktopSize() { - if (!cp->supportsDesktopResize) return false; - needSetDesktopSize = true; - return true; -} - -bool SMsgWriterV3::writeExtendedDesktopSize() { - if (!cp->supportsExtendedDesktopSize) return false; - needExtendedDesktopSize = true; - return true; -} - -bool SMsgWriterV3::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, - int fb_width, int fb_height, - const ScreenSet& layout) { - ExtendedDesktopSizeMsg msg; - - if (!cp->supportsExtendedDesktopSize) return false; - - msg.reason = reason; - msg.result = result; - msg.fb_width = fb_width; - msg.fb_height = fb_height; - msg.layout = layout; - - extendedDesktopSizeMsgs.push_back(msg); - - return true; -} - -bool SMsgWriterV3::writeSetDesktopName() { - if (!cp->supportsDesktopRename) return false; - needSetDesktopName = true; - return true; -} - -void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb) -{ - wsccb = cb; -} - -void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot, - void* data, void* mask) -{ - if (!wsccb) return; - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync"); - os->writeS16(hotspot.x); - os->writeS16(hotspot.y); - os->writeU16(width); - os->writeU16(height); - os->writeU32(pseudoEncodingCursor); - os->writeBytes(data, width * height * (cp->pf().bpp/8)); - os->writeBytes(mask, (width+7)/8 * height); -} - -void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX, - int hotspotY, void* data, void* mask) -{ - if (!wsccb) return; - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync"); - os->writeS16(hotspotX); - os->writeS16(hotspotY); - os->writeU16(width); - os->writeU16(height); - os->writeU32(pseudoEncodingXCursor); - // FIXME: We only support black and white cursors, currently. We - // could pass the correct color by using the pix0/pix1 values - // returned from getBitmap, in writeSetCursorCallback. However, we - // would then need to undo the conversion from rgb to Pixel that is - // done by FakeAllocColor. - if (width * height) { - os->writeU8(0); - os->writeU8(0); - os->writeU8(0); - os->writeU8(255); - os->writeU8(255); - os->writeU8(255); - os->writeBytes(data, (width+7)/8 * height); - os->writeBytes(mask, (width+7)/8 * height); - } -} - -bool SMsgWriterV3::needFakeUpdate() -{ - return wsccb || needSetDesktopName || needNoDataUpdate(); -} - -bool SMsgWriterV3::needNoDataUpdate() -{ - return needSetDesktopSize || needExtendedDesktopSize || - !extendedDesktopSizeMsgs.empty(); -} - -void SMsgWriterV3::writeNoDataUpdate() -{ - int nRects; - - nRects = 0; - - if (needSetDesktopSize) - nRects++; - if (needExtendedDesktopSize) - nRects++; - if (!extendedDesktopSizeMsgs.empty()) - nRects += extendedDesktopSizeMsgs.size(); - - writeFramebufferUpdateStart(nRects); - writeNoDataRects(); - writeFramebufferUpdateEnd(); -} - -void SMsgWriterV3::writeFramebufferUpdateStart(int nRects) -{ - startMsg(msgTypeFramebufferUpdate); - os->pad(1); - - if (nRects != 0xFFFF) { - if (wsccb) - nRects++; - if (needSetDesktopName) - nRects++; - } - - os->writeU16(nRects); - - nRectsInUpdate = 0; - if (nRects == 0xFFFF) - nRectsInHeader = 0; - else - nRectsInHeader = nRects; - - writePseudoRects(); -} - -void SMsgWriterV3::writeFramebufferUpdateStart() -{ - nRectsInUpdate = nRectsInHeader = 0; - - if (!updateOS) - updateOS = new rdr::MemOutStream; - os = updateOS; - - writePseudoRects(); -} - -void SMsgWriterV3::writeFramebufferUpdateEnd() -{ - if (nRectsInUpdate != nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: " - "nRects out of sync"); - - if (nRectsInHeader == 0) { - // Send last rect. marker - os->writeS16(0); - os->writeS16(0); - os->writeU16(0); - os->writeU16(0); - os->writeU32(pseudoEncodingLastRect); - } - - if (os == updateOS) { - os = realOS; - startMsg(msgTypeFramebufferUpdate); - os->pad(1); - os->writeU16(nRectsInUpdate); - os->writeBytes(updateOS->data(), updateOS->length()); - updateOS->clear(); - } - - updatesSent++; - endMsg(); -} - -void SMsgWriterV3::startRect(const Rect& r, int encoding) -{ - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3::startRect: nRects out of sync"); - - currentEncoding = encoding; - lenBeforeRect = os->length(); - if (encoding != encodingCopyRect) - rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8); - - os->writeS16(r.tl.x); - os->writeS16(r.tl.y); - os->writeU16(r.width()); - os->writeU16(r.height()); - os->writeU32(encoding); -} - -void SMsgWriterV3::endRect() -{ - if (currentEncoding <= encodingMax) { - bytesSent[currentEncoding] += os->length() - lenBeforeRect; - rectsSent[currentEncoding]++; - } -} - -void SMsgWriterV3::writePseudoRects() -{ - if (wsccb) { - wsccb->writeSetCursorCallback(); - wsccb = 0; - } - - if (needSetDesktopName) { - if (!cp->supportsDesktopRename) - throw Exception("Client does not support desktop rename"); - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync"); - - os->writeS16(0); - os->writeS16(0); - os->writeU16(0); - os->writeU16(0); - os->writeU32(pseudoEncodingDesktopName); - os->writeString(cp->name()); - - needSetDesktopName = false; - } -} - -void SMsgWriterV3::writeNoDataRects() -{ - // Start with specific ExtendedDesktopSize messages - if (!extendedDesktopSizeMsgs.empty()) { - std::list<ExtendedDesktopSizeMsg>::const_iterator ri; - ScreenSet::const_iterator si; - - if (!cp->supportsExtendedDesktopSize) - throw Exception("Client does not support extended desktop resize"); - if ((nRectsInUpdate += extendedDesktopSizeMsgs.size()) > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3 SetDesktopSize reply: nRects out of sync"); - - for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) { - os->writeU16(ri->reason); - os->writeU16(ri->result); - os->writeU16(ri->fb_width); - os->writeU16(ri->fb_height); - os->writeU32(pseudoEncodingExtendedDesktopSize); - - os->writeU8(ri->layout.num_screens()); - os->pad(3); - - for (si = ri->layout.begin();si != ri->layout.end();++si) { - os->writeU32(si->id); - os->writeU16(si->dimensions.tl.x); - os->writeU16(si->dimensions.tl.y); - os->writeU16(si->dimensions.width()); - os->writeU16(si->dimensions.height()); - os->writeU32(si->flags); - } - } - - extendedDesktopSizeMsgs.clear(); - } - - // Send this before SetDesktopSize to make life easier on the clients - if (needExtendedDesktopSize) { - if (!cp->supportsExtendedDesktopSize) - throw Exception("Client does not support extended desktop resize"); - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync"); - - os->writeU16(0); - os->writeU16(0); - os->writeU16(cp->width); - os->writeU16(cp->height); - os->writeU32(pseudoEncodingExtendedDesktopSize); - - os->writeU8(cp->screenLayout.num_screens()); - os->pad(3); - - ScreenSet::const_iterator iter; - for (iter = cp->screenLayout.begin();iter != cp->screenLayout.end();++iter) { - os->writeU32(iter->id); - os->writeU16(iter->dimensions.tl.x); - os->writeU16(iter->dimensions.tl.y); - os->writeU16(iter->dimensions.width()); - os->writeU16(iter->dimensions.height()); - os->writeU32(iter->flags); - } - - needExtendedDesktopSize = false; - } - - // Some clients assume this is the last rectangle so don't send anything - // more after this - if (needSetDesktopSize) { - if (!cp->supportsDesktopResize) - throw Exception("Client does not support desktop resize"); - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync"); - - os->writeS16(0); - os->writeS16(0); - os->writeU16(cp->width); - os->writeU16(cp->height); - os->writeU32(pseudoEncodingDesktopSize); - - needSetDesktopSize = false; - } -} - diff --git a/common/rfb/SMsgWriterV3.h b/common/rfb/SMsgWriterV3.h deleted file mode 100644 index 6710fa6b..00000000 --- a/common/rfb/SMsgWriterV3.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#ifndef __RFB_SMSGWRITERV3_H__ -#define __RFB_SMSGWRITERV3_H__ - -#include <list> -#include <utility> - -#include <rfb/SMsgWriter.h> - -namespace rdr { class MemOutStream; } - -namespace rfb { - class SMsgWriterV3 : public SMsgWriter { - public: - SMsgWriterV3(ConnParams* cp, rdr::OutStream* os); - virtual ~SMsgWriterV3(); - - virtual void writeServerInit(); - virtual void startMsg(int type); - virtual void endMsg(); - virtual void writeFence(rdr::U32 flags, unsigned len, const char data[]); - virtual void writeEndOfContinuousUpdates(); - virtual bool writeSetDesktopSize(); - virtual bool writeExtendedDesktopSize(); - virtual bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, - int fb_width, int fb_height, - const ScreenSet& layout); - virtual bool writeSetDesktopName(); - virtual void cursorChange(WriteSetCursorCallback* cb); - virtual void writeSetCursor(int width, int height, const Point& hotspot, - void* data, void* mask); - virtual void writeSetXCursor(int width, int height, int hotspotX, - int hotspotY, void* data, void* mask); - virtual bool needFakeUpdate(); - virtual bool needNoDataUpdate(); - virtual void writeNoDataUpdate(); - virtual void writeFramebufferUpdateStart(int nRects); - virtual void writeFramebufferUpdateStart(); - virtual void writeFramebufferUpdateEnd(); - virtual void startRect(const Rect& r, int encoding); - virtual void endRect(); - - protected: - virtual void writePseudoRects(); - virtual void writeNoDataRects(); - - private: - rdr::MemOutStream* updateOS; - rdr::OutStream* realOS; - int nRectsInUpdate; - int nRectsInHeader; - WriteSetCursorCallback* wsccb; - bool needSetDesktopSize; - bool needExtendedDesktopSize; - bool needSetDesktopName; - bool needLastRect; - - typedef struct { - rdr::U16 reason, result; - int fb_width, fb_height; - ScreenSet layout; - } ExtendedDesktopSizeMsg; - std::list<ExtendedDesktopSizeMsg> extendedDesktopSizeMsgs; - - }; -} -#endif diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index d4ee877f..bfc3352b 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -18,6 +18,7 @@ * USA. */ #include <rfb/CMsgReader.h> +#include <rfb/CConnection.h> #include <rfb/CMsgHandler.h> #include <rfb/TightDecoder.h> @@ -25,8 +26,6 @@ using namespace rfb; #define TIGHT_MAX_WIDTH 2048 -#define FILL_RECT(r, p) handler->fillRect(r, p) -#define IMAGE_RECT(r, p) handler->imageRect(r, p) #define BPP 8 #include <rfb/tightDecode.h> #undef BPP @@ -37,7 +36,7 @@ using namespace rfb; #include <rfb/tightDecode.h> #undef BPP -TightDecoder::TightDecoder(CMsgReader* reader_) : reader(reader_) +TightDecoder::TightDecoder(CConnection* conn) : Decoder(conn) { } @@ -47,7 +46,7 @@ TightDecoder::~TightDecoder() void TightDecoder::readRect(const Rect& r, CMsgHandler* handler) { - is = reader->getInStream(); + is = conn->getInStream(); this->handler = handler; clientpf = handler->getPreferredPF(); serverpf = handler->cp.pf(); @@ -69,3 +68,22 @@ void TightDecoder::readRect(const Rect& r, CMsgHandler* handler) tightDecode32(r); break; } } + +rdr::U32 TightDecoder::readCompact(rdr::InStream* is) +{ + rdr::U8 b; + rdr::U32 result; + + b = is->readU8(); + result = (int)b & 0x7F; + if (b & 0x80) { + b = is->readU8(); + result |= ((int)b & 0x7F) << 7; + if (b & 0x80) { + b = is->readU8(); + result |= ((int)b & 0xFF) << 14; + } + } + + return result; +} diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index 8200d2b8..2ca4ecd6 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -28,11 +28,13 @@ namespace rfb { class TightDecoder : public Decoder { public: - TightDecoder(CMsgReader* reader); + TightDecoder(CConnection* conn); virtual ~TightDecoder(); virtual void readRect(const Rect& r, CMsgHandler* handler); private: + rdr::U32 readCompact(rdr::InStream* is); + void tightDecode8(const Rect& r); void tightDecode16(const Rect& r); void tightDecode32(const Rect& r); @@ -54,7 +56,6 @@ namespace rfb { void directFillRect16(const Rect& r, Pixel pix); void directFillRect32(const Rect& r, Pixel pix); - CMsgReader* reader; CMsgHandler* handler; rdr::InStream* is; rdr::ZlibInStream zis[4]; diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index 733365e0..c3f87dab 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -18,9 +18,11 @@ */ #include <rdr/OutStream.h> #include <rfb/TransImageGetter.h> +#include <rfb/PixelBuffer.h> #include <rfb/encodings.h> #include <rfb/ConnParams.h> #include <rfb/SMsgWriter.h> +#include <rfb/SConnection.h> #include <rfb/TightEncoder.h> using namespace rfb; @@ -92,7 +94,7 @@ const int TightEncoder::defaultCompressLevel = 2; #include <rfb/tightEncode.h> #undef BPP -TightEncoder::TightEncoder(SMsgWriter* writer_) : writer(writer_) +TightEncoder::TightEncoder(SConnection* conn) : Encoder(conn) { setCompressLevel(defaultCompressLevel); setQualityLevel(-1); @@ -225,7 +227,7 @@ void TightEncoder::extendSolidArea(const Rect& r, rdr::U32 colorValue, int TightEncoder::getNumRects(const Rect &r) { - ConnParams* cp = writer->getConnParams(); + ConnParams* cp = &conn->cp; const unsigned int w = r.width(); const unsigned int h = r.height(); @@ -285,12 +287,11 @@ void TightEncoder::sendRectSimple(const Rect& r) } } -bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, - Rect* actual) +void TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig) { ig = _ig; serverpf = ig->getPixelBuffer()->getPF(); - ConnParams* cp = writer->getConnParams(); + ConnParams* cp = &conn->cp; clientpf = cp->pf(); // Shortcuts to rectangle coordinates and dimensions. @@ -303,7 +304,7 @@ bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, // Encode small rects as is. if (!cp->supportsLastRect || w * h < TIGHT_MIN_SPLIT_RECT_SIZE) { sendRectSimple(r); - return true; + return; } // Split big rects into separately encoded subrects. @@ -338,9 +339,9 @@ bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, if (checkSolidTile(sr, &colorValue, false)) { if (jpegSubsampling == subsampleGray && jpegQuality != -1) { - Colour rgb; - serverpf.rgbFromPixel(colorValue, NULL, &rgb); - rdr::U32 lum = ((257 * rgb.r) + (504 * rgb.g) + (98 * rgb.b) + rdr::U16 r, g, b; + serverpf.rgbFromPixel(colorValue, &r, &g, &b); + rdr::U32 lum = ((257 * r) + (504 * g) + (98 * b) + 16500) / 1000; colorValue = lum + (lum << 8) + (lum << 16); } @@ -365,7 +366,7 @@ bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, } if (bestr.tl.x != x) { sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height()); - writeRect(sr, _ig, NULL); + writeRect(sr, _ig); } // Send solid-color rectangle. @@ -375,21 +376,21 @@ bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig, if (bestr.br.x != r.br.x) { sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x, bestr.height()); - writeRect(sr, _ig, NULL); + writeRect(sr, _ig); } if (bestr.br.y != r.br.y) { sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y); - writeRect(sr, _ig, NULL); + writeRect(sr, _ig); } - return true; + return; } } } // No suitable solid-color rectangles found. sendRectSimple(r); - return true; + return; } void TightEncoder::writeSubrect(const Rect& r, bool forceSolid) @@ -405,8 +406,26 @@ void TightEncoder::writeSubrect(const Rect& r, bool forceSolid) tightEncode32(r, &mos, forceSolid); break; } - writer->startRect(r, encodingTight); - rdr::OutStream* os = writer->getOutStream(); + conn->writer()->startRect(r, encodingTight); + rdr::OutStream* os = conn->getOutStream(); os->writeBytes(mos.data(), mos.length()); - writer->endRect(); + conn->writer()->endRect(); +} + +void TightEncoder::writeCompact(rdr::OutStream* os, rdr::U32 value) +{ + rdr::U8 b; + b = value & 0x7F; + if (value <= 0x7F) { + os->writeU8(b); + } else { + os->writeU8(b | 0x80); + b = value >> 7 & 0x7F; + if (value <= 0x3FFF) { + os->writeU8(b); + } else { + os->writeU8(b | 0x80); + os->writeU8(value >> 14 & 0xFF); + } + } } diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h index 3632539d..8a58985e 100644 --- a/common/rfb/TightEncoder.h +++ b/common/rfb/TightEncoder.h @@ -23,6 +23,7 @@ #include <rdr/ZlibOutStream.h> #include <rfb/Encoder.h> #include <rfb/JpegCompressor.h> +#include <rfb/Palette.h> // FIXME: Check if specifying extern "C" is really necessary. #include <stdio.h> @@ -45,28 +46,6 @@ namespace rfb { }; // - // C-style structures to store palette entries and compression paramentes. - // Such code probably should be converted into C++ classes. - // - - struct TIGHT_COLOR_LIST { - TIGHT_COLOR_LIST *next; - int idx; - rdr::U32 rgb; - }; - - struct TIGHT_PALETTE_ENTRY { - TIGHT_COLOR_LIST *listNode; - int numPixels; - }; - - struct TIGHT_PALETTE { - TIGHT_PALETTE_ENTRY entry[256]; - TIGHT_COLOR_LIST *hash[256]; - TIGHT_COLOR_LIST list[256]; - }; - - // // Compression level stuff. The following array contains various // encoder parameters for each of 10 compression levels (0..9). // Last three parameters correspond to JPEG quality levels (0..9). @@ -79,14 +58,14 @@ namespace rfb { class TightEncoder : public Encoder { public: - TightEncoder(SMsgWriter* writer); + TightEncoder(SConnection* conn); virtual ~TightEncoder(); virtual void setCompressLevel(int level); virtual void setQualityLevel(int level); virtual void setFineQualityLevel(int quality, int subsampling); virtual int getNumRects(const Rect &r); - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); + virtual void writeRect(const Rect& r, TransImageGetter* ig); private: bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor); @@ -95,13 +74,12 @@ namespace rfb { void sendRectSimple(const Rect& r); void writeSubrect(const Rect& r, bool forceSolid = false); + void writeCompact(rdr::OutStream* os, rdr::U32 value); + void compressData(const void *buf, unsigned int length, rdr::ZlibOutStream *zos, int zlibLevel, rdr::OutStream *os); - int paletteInsert(rdr::U32 rgb, int numPixels, int bpp); - void paletteReset(void); - void fastFillPalette8(const rdr::U8 *data, int stride, const Rect &r); void fastFillPalette16(const rdr::U16 *data, int stride, const Rect &r); void fastFillPalette32(const rdr::U32 *data, int stride, const Rect &r); @@ -142,7 +120,6 @@ namespace rfb { void encodeJpegRect32(rdr::U32 *buf, int stride, const Rect& r, rdr::OutStream *os); - SMsgWriter* writer; rdr::MemOutStream mos; rdr::ZlibOutStream zos[4]; JpegCompressor jc; @@ -150,9 +127,8 @@ namespace rfb { PixelFormat serverpf, clientpf; bool pack24; - int palMaxColors, palNumColors; - rdr::U32 monoBackground, monoForeground; - TIGHT_PALETTE palette; + int palMaxColors; + Palette palette; static const int defaultCompressLevel; static const TIGHT_CONF conf[]; diff --git a/common/rfb/TightPalette.cxx b/common/rfb/TightPalette.cxx deleted file mode 100644 index c4ed04e4..00000000 --- a/common/rfb/TightPalette.cxx +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -// TightPalette class implementation. -// - -#include <rfb/TightPalette.h> - -using namespace rfb; - -TightPalette::TightPalette(int maxColors) -{ - setMaxColors(maxColors); - reset(); -} - -void TightPalette::reset() -{ - m_numColors = 0; - memset(m_hash, 0, 256 * sizeof(TightColorList *)); -} - -void TightPalette::setMaxColors(int maxColors) -{ - m_maxColors = maxColors; - if (m_maxColors < 0) { - m_maxColors = 0; - } else if (m_maxColors > 254) { - m_maxColors = 254; - } -} - -int TightPalette::insert(rdr::U32 rgb, int numPixels) -{ - TightColorList *pnode; - TightColorList *prev_pnode = NULL; - int hash_key, idx, new_idx, count; - - hash_key = hashFunc(rgb); - - pnode = m_hash[hash_key]; - - while (pnode != NULL) { - if (pnode->rgb == rgb) { - // Such palette entry already exists. - new_idx = idx = pnode->idx; - count = m_entry[idx].numPixels + numPixels; - if (new_idx && m_entry[new_idx-1].numPixels < count) { - do { - m_entry[new_idx] = m_entry[new_idx-1]; - m_entry[new_idx].listNode->idx = new_idx; - new_idx--; - } - while (new_idx && m_entry[new_idx-1].numPixels < count); - - m_entry[new_idx].listNode = pnode; - pnode->idx = new_idx; - } - m_entry[new_idx].numPixels = count; - return m_numColors; - } - prev_pnode = pnode; - pnode = pnode->next; - } - - // Check if the palette is full. - if (m_numColors == 256 || m_numColors == m_maxColors) { - m_numColors = 0; - return 0; - } - - // Move palette entries with lesser pixel counts. - for ( idx = m_numColors; - idx > 0 && m_entry[idx-1].numPixels < numPixels; - idx-- ) { - m_entry[idx] = m_entry[idx-1]; - m_entry[idx].listNode->idx = idx; - } - - // Add new palette entry into the freed slot. - pnode = &m_list[m_numColors]; - if (prev_pnode != NULL) { - prev_pnode->next = pnode; - } else { - m_hash[hash_key] = pnode; - } - pnode->next = NULL; - pnode->idx = idx; - pnode->rgb = rgb; - m_entry[idx].listNode = pnode; - m_entry[idx].numPixels = numPixels; - - return ++m_numColors; -} diff --git a/common/rfb/TightPalette.h b/common/rfb/TightPalette.h deleted file mode 100644 index 2f6448ea..00000000 --- a/common/rfb/TightPalette.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -// -// TightPalette class is a container for ordered color values. Colors -// are keys in a hash where values are frequency counts. Also, there -// is a list where colors are always sorted by these counts (more -// frequent first). -// - -#ifndef __RFB_TIGHTPALETTE_H__ -#define __RFB_TIGHTPALETTE_H__ - -#include <string.h> -#include <rdr/types.h> - -namespace rfb { - - struct TightColorList { - TightColorList *next; - int idx; - rdr::U32 rgb; - }; - - struct TightPaletteEntry { - TightColorList *listNode; - int numPixels; - }; - - class TightPalette { - - protected: - - // FIXME: Bigger hash table? Better hash function? - inline static int hashFunc(rdr::U32 rgb) { - return (rgb ^ (rgb >> 13)) & 0xFF; - } - - public: - - TightPalette(int maxColors = 254); - - // - // Re-initialize the object. This does not change maximum number - // of colors. - // - void reset(); - - // - // Set limit on the number of colors in the palette. Note that - // this value cannot exceed 254. - // - void setMaxColors(int maxColors); - - // - // Insert new color into the palette, or increment its counter if - // the color is already there. Returns new number of colors, or - // zero if the palette is full. If the palette becomes full, it - // reports zero colors and cannot be used any more without calling - // reset(). - // - int insert(rdr::U32 rgb, int numPixels); - - // - // Return number of colors in the palette. - // - inline int getNumColors() const { - return m_numColors; - } - - // - // Return the color specified by its index in the palette. - // - inline rdr::U32 getEntry(int i) const { - return (i < m_numColors) ? m_entry[i].listNode->rgb : (rdr::U32)-1; - } - - // - // Return the pixel counter of the color specified by its index. - // - inline int getCount(int i) const { - return (i < m_numColors) ? m_entry[i].numPixels : 0; - } - - // - // Return the index of a specified color. - // - inline rdr::U8 getIndex(rdr::U32 rgb) const { - TightColorList *pnode = m_hash[hashFunc(rgb)]; - while (pnode != NULL) { - if (pnode->rgb == rgb) { - return (rdr::U8)pnode->idx; - } - pnode = pnode->next; - } - return 0xFF; // no such color - } - - protected: - - int m_maxColors; - int m_numColors; - - TightPaletteEntry m_entry[256]; - TightColorList *m_hash[256]; - TightColorList m_list[256]; - - }; - -} // namespace rfb - -#endif // __RFB_TIGHTPALETTE_H__ diff --git a/common/rfb/TransImageGetter.cxx b/common/rfb/TransImageGetter.cxx index 3900d065..05df1a98 100644 --- a/common/rfb/TransImageGetter.cxx +++ b/common/rfb/TransImageGetter.cxx @@ -24,10 +24,7 @@ #include <rfb/Exception.h> #include <rfb/ConnParams.h> #include <rfb/SMsgWriter.h> -#include <rfb/ColourMap.h> -#include <rfb/TrueColourMap.h> #include <rfb/PixelBuffer.h> -#include <rfb/ColourCube.h> #include <rfb/TransImageGetter.h> using namespace rfb; @@ -42,18 +39,12 @@ TransImageGetter::~TransImageGetter() } void TransImageGetter::init(PixelBuffer* pb_, const PixelFormat& out, - SMsgWriter* writer_, ColourCube* cube_) + SMsgWriter* writer_) { pb = pb_; writer = writer_; - PixelTransformer::init(pb->getPF(), pb->getColourMap(), out, cube_, - cmCallback, this); -} - -void TransImageGetter::setColourMapEntries(int firstCol, int nCols) -{ - PixelTransformer::setColourMapEntries(firstCol, nCols); + PixelTransformer::init(pb->getPF(), out); } const rdr::U8 *TransImageGetter::getRawBufferR(const Rect &r, int *stride) @@ -74,15 +65,3 @@ void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride) translateRect((void*)inPtr, inStride, Rect(0, 0, r.width(), r.height()), outPtr, outStride, Point(0, 0)); } - -void TransImageGetter::cmCallback(int firstColour, int nColours, - ColourMap* cm, void* data) -{ - TransImageGetter *self; - - assert(data); - self = (TransImageGetter*)data; - - if (self->writer) - self->writer->writeSetColourMapEntries(firstColour, nColours, cm); -} diff --git a/common/rfb/TransImageGetter.h b/common/rfb/TransImageGetter.h index b241b83c..bfd9c2fa 100644 --- a/common/rfb/TransImageGetter.h +++ b/common/rfb/TransImageGetter.h @@ -27,17 +27,13 @@ #include <rfb/Rect.h> #include <rfb/PixelFormat.h> #include <rfb/PixelTransformer.h> -#include <rfb/ImageGetter.h> namespace rfb { class SMsgWriter; - class ColourMap; class PixelBuffer; - class ColourCube; - class TransImageGetter : public ImageGetter, - public PixelTransformer { + class TransImageGetter : public PixelTransformer { public: TransImageGetter(bool econ=false); @@ -45,25 +41,9 @@ namespace rfb { // init() is called to initialise the translation tables. The PixelBuffer // argument gives the source data and format details, outPF gives the - // client's pixel format. If the client has a colour map, then the writer - // argument is used to send a SetColourMapEntries message to the client. + // client's pixel format. - void init(PixelBuffer* pb, const PixelFormat& outPF, SMsgWriter* writer=0, - ColourCube* cube=0); - - // setColourMapEntries() is called when the PixelBuffer has a colour map - // which has changed. firstColour and nColours specify which part of the - // colour map has changed. If nColours is 0, this means the rest of the - // colour map. The PixelBuffer previously passed to init() must have a - // valid ColourMap object. If the client also has a colour map, then the - // writer argument is used to send a SetColourMapEntries message to the - // client. If the client is true colour then instead we update the - // internal translation table - in this case the caller should also make - // sure that the client receives an update of the relevant parts of the - // framebuffer (the simplest thing to do is just update the whole - // framebuffer, though it is possible to be smarter than this). - - void setColourMapEntries(int firstColour, int nColours); + void init(PixelBuffer* pb, const PixelFormat& outPF, SMsgWriter* writer=0); // getImage() gets the given rectangle of data from the PixelBuffer, // translates it into the client's pixel format and puts it in the buffer @@ -90,17 +70,12 @@ namespace rfb { void setOffset(const Point& offset_) { offset = offset_; } private: - static void cmCallback(int firstColour, int nColours, - ColourMap* cm, void* data); - - private: bool economic; PixelBuffer* pb; PixelFormat outPF; SMsgWriter* writer; rdr::U8* table; transFnType transFn; - ColourCube* cube; Point offset; }; } diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 381ee216..fcb678ad 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB + * Copyright 2009-2014 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 @@ -37,6 +37,7 @@ #include <rfb/ServerCore.h> #include <rfb/ComparingUpdateTracker.h> #include <rfb/KeyRemapper.h> +#include <rfb/Encoder.h> #define XK_MISCELLANY #define XK_XKB_KEYS #include <rfb/keysymdef.h> @@ -81,6 +82,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, peerEndpoint.buf = sock->getPeerEndpoint(); VNCServerST::connectionsLog.write(1,"accepted: %s", peerEndpoint.buf); + memset(encoders, 0, sizeof(encoders)); + // Configure the socket setSocketTimeouts(); lastEventTime = time(0); @@ -106,6 +109,9 @@ VNCSConnectionST::~VNCSConnectionST() // Remove this client from the server server->clients.remove(this); + for (int i = 0; i <= encodingMax; i++) + delete encoders[i]; + delete [] fenceData; } @@ -253,15 +259,6 @@ void VNCSConnectionST::screenLayoutChangeOrClose(rdr::U16 reason) } } -void VNCSConnectionST::setColourMapEntriesOrClose(int firstColour,int nColours) -{ - try { - setColourMapEntries(firstColour, nColours); - } catch(rdr::Exception& e) { - close(e.str()); - } -} - void VNCSConnectionST::bellOrClose() { try { @@ -625,11 +622,6 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height, writeFramebufferUpdate(); } -void VNCSConnectionST::setInitialColourMap() -{ - setColourMapEntries(0, 0); -} - void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[]) { if (flags & fenceFlagRequest) { @@ -745,13 +737,19 @@ void VNCSConnectionST::writeSetCursorCallback() } // Use RichCursor - rdr::U8* transData = writer()->getImageBuf(server->cursor.area()); - image_getter.translatePixels(server->cursor.data, transData, - server->cursor.area()); + rdr::U8* transBuffer; + int stride; + const rdr::U8* buffer; + + transBuffer = writer()->getImageBuf(server->cursor.area()); + + buffer = server->cursor.getBuffer(server->cursor.getRect(), &stride); + image_getter.translatePixels(buffer, transBuffer, server->cursor.area()); + writer()->writeSetCursor(server->cursor.width(), server->cursor.height(), server->cursor.hotspot, - transData, server->cursor.mask.buf); + transBuffer, server->cursor.mask.buf); } @@ -1074,18 +1072,30 @@ void VNCSConnectionST::writeFramebufferUpdate() } if (!ui.is_empty() || writer()->needFakeUpdate() || drawRenderedCursor) { + std::vector<Rect> rects; + std::vector<Rect>::const_iterator i; + int encoding; + + // Make sure the encoder has the latest settings + encoding = cp.currentEncoding(); + + if (!encoders[encoding]) + encoders[encoding] = Encoder::createEncoder(encoding, this); + + encoders[encoding]->setCompressLevel(cp.compressLevel); + encoders[encoding]->setQualityLevel(cp.qualityLevel); + encoders[encoding]->setFineQualityLevel(cp.fineQualityLevel, + cp.subsampling); + // Compute the number of rectangles. Tight encoder makes the things more // complicated as compared to the original VNC4. - writer()->setupCurrentEncoder(); int nRects = (ui.copied.numRects() + (drawRenderedCursor ? 1 : 0)); - std::vector<Rect> rects; - std::vector<Rect>::const_iterator i; ui.changed.get_rects(&rects); for (i = rects.begin(); i != rects.end(); i++) { if (i->width() && i->height()) { - int nUpdateRects = writer()->getNumRects(*i); + int nUpdateRects = encoders[encoding]->getNumRects(*i); if (nUpdateRects == 0 && cp.currentEncoding() == encodingTight) { // With Tight encoding and LastRect support, the client does not // care about the number of rectangles in the update - it will @@ -1102,18 +1112,33 @@ void VNCSConnectionST::writeFramebufferUpdate() writer()->writeFramebufferUpdateStart(nRects); - Region updatedRegion; - writer()->writeRects(ui, &image_getter, &updatedRegion); - updates.subtract(updatedRegion); + ui.copied.get_rects(&rects); + for (i = rects.begin(); i != rects.end(); i++) + writer()->writeCopyRect(*i, i->tl.x - ui.copy_delta.x, + i->tl.y - ui.copy_delta.y); + + ui.changed.get_rects(&rects); + for (i = rects.begin(); i != rects.end(); i++) + encoders[encoding]->writeRect(*i, &image_getter); + + if (drawRenderedCursor) { + image_getter.setPixelBuffer(&server->renderedCursor); + image_getter.setOffset(server->renderedCursorTL); + + encoders[encoding]->writeRect(renderedCursorRect, &image_getter); - if (drawRenderedCursor) - writeRenderedCursorRect(); + image_getter.setPixelBuffer(server->pb); + image_getter.setOffset(Point(0,0)); + + drawRenderedCursor = false; + } writer()->writeFramebufferUpdateEnd(); writeRTTPing(); requested.clear(); + updates.clear(); } out: @@ -1121,23 +1146,6 @@ out: } -// writeRenderedCursorRect() writes a single rectangle drawing the rendered -// cursor on the client. - -void VNCSConnectionST::writeRenderedCursorRect() -{ - image_getter.setPixelBuffer(&server->renderedCursor); - image_getter.setOffset(server->renderedCursorTL); - - Rect actual; - writer()->writeRect(renderedCursorRect, &image_getter, &actual); - - image_getter.setPixelBuffer(server->pb); - image_getter.setOffset(Point(0,0)); - - drawRenderedCursor = false; -} - void VNCSConnectionST::screenLayoutChange(rdr::U16 reason) { if (!authenticated()) @@ -1153,21 +1161,6 @@ void VNCSConnectionST::screenLayoutChange(rdr::U16 reason) writeFramebufferUpdate(); } -void VNCSConnectionST::setColourMapEntries(int firstColour, int nColours) -{ - if (!readyForSetColourMapEntries) - return; - if (server->pb->getPF().trueColour) - return; - - image_getter.setColourMapEntries(firstColour, nColours); - - if (cp.pf().trueColour) { - updates.add_changed(server->pb->getRect()); - writeFramebufferUpdate(); - } -} - // setCursor() is called whenever the cursor has changed shape or pixel format. // If the client supports local cursor then it will arrange for the cursor to diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 5eb908ab..ca5c4f01 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -37,6 +37,8 @@ struct RTTInfo; namespace rfb { + class Encoder; + class VNCSConnectionST : public SConnection, public WriteSetCursorCallback, public Timer::Callback { @@ -71,7 +73,6 @@ namespace rfb { // Wrappers to make these methods "safe" for VNCServerST. void writeFramebufferUpdateOrClose(); void screenLayoutChangeOrClose(rdr::U16 reason); - void setColourMapEntriesOrClose(int firstColour, int nColours); void setCursorOrClose(); void bellOrClose(); void serverCutTextOrClose(const char *str, int len); @@ -138,7 +139,6 @@ namespace rfb { virtual void framebufferUpdateRequest(const Rect& r, bool incremental); virtual void setDesktopSize(int fb_width, int fb_height, const ScreenSet& layout); - virtual void setInitialColourMap(); virtual void fence(rdr::U32 flags, unsigned len, const char data[]); virtual void enableContinuousUpdates(bool enable, int x, int y, int w, int h); @@ -171,9 +171,7 @@ namespace rfb { void writeFramebufferUpdate(); - void writeRenderedCursorRect(); void screenLayoutChange(rdr::U16 reason); - void setColourMapEntries(int firstColour, int nColours); void setCursor(); void setDesktopName(const char *name); void setSocketTimeouts(); @@ -205,6 +203,7 @@ namespace rfb { Rect renderedCursorRect; bool continuousUpdates; Region cuRegion; + Encoder* encoders[encodingMax+1]; Timer updateTimer; diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h index 280b68b4..c76e5c9c 100644 --- a/common/rfb/VNCServer.h +++ b/common/rfb/VNCServer.h @@ -52,12 +52,6 @@ namespace rfb { // getPixelBuffer() returns a pointer to the PixelBuffer object. virtual PixelBuffer* getPixelBuffer() const = 0; - // setColourMapEntries() tells the server that some entries in the colour - // map have changed. The server will retrieve them via the PixelBuffer's - // ColourMap object. This may result in protocol messages being sent. - // If nColours is 0, this means the rest of the colour map. - virtual void setColourMapEntries(int firstColour=0, int nColours=0) = 0; - // serverCutText() tells the server that the cut text has changed. This // will normally be sent to all clients. virtual void serverCutText(const char* str, int len) = 0; @@ -79,7 +73,7 @@ namespace rfb { // in left-to-right order. The server takes its own copy of the data in // cursorData and mask. virtual void setCursor(int width, int height, const Point& hotspot, - void* cursorData, void* mask) = 0; + const void* cursorData, const void* mask) = 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 b07f5c35..f1e378ed 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2009-2014 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 @@ -359,15 +360,6 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout) } } -void VNCServerST::setColourMapEntries(int firstColour, int nColours) -{ - std::list<VNCSConnectionST*>::iterator ci, ci_next; - for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { - ci_next = ci; ci_next++; - (*ci)->setColourMapEntriesOrClose(firstColour, nColours); - } -} - void VNCServerST::bell() { std::list<VNCSConnectionST*>::iterator ci, ci_next; @@ -417,11 +409,11 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta) } void VNCServerST::setCursor(int width, int height, const Point& newHotspot, - void* data, void* mask) + const void* data, const void* mask) { cursor.hotspot = newHotspot; cursor.setSize(width, height); - memcpy(cursor.data, data, cursor.dataLen()); + cursor.imageRect(cursor.getRect(), data); memcpy(cursor.mask.buf, mask, cursor.maskLen()); cursor.crop(); @@ -630,11 +622,17 @@ bool VNCServerST::checkUpdate() comparer->getUpdateInfo(&ui, pb->getRect()); if (renderCursor) { - pb->getImage(renderedCursor.data, - renderedCursor.getRect(renderedCursorTL)); + const rdr::U8* buffer; + int stride; + + buffer = pb->getBuffer(renderedCursor.getRect(renderedCursorTL), &stride); + renderedCursor.imageRect(renderedCursor.getRect(), buffer, stride); + + buffer = cursor.getBuffer(cursor.getRect(), &stride); renderedCursor.maskRect(cursor.getRect(cursorTL() .subtract(renderedCursorTL)), - cursor.data, cursor.mask.buf); + buffer, cursor.mask.buf); + renderedCursorInvalid = false; } diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index e75954fc..ed7833ab 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -88,12 +88,11 @@ namespace rfb { virtual void setPixelBuffer(PixelBuffer* pb); virtual void setScreenLayout(const ScreenSet& layout); virtual PixelBuffer* getPixelBuffer() const { return pb; } - virtual void setColourMapEntries(int firstColour=0, int nColours=0); virtual void serverCutText(const char* str, int len); 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, - void* cursorData, void* mask); + const void* cursorData, const void* mask); virtual void setCursorPos(const Point& p); virtual void bell(); diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index 111e2de6..7e933a8f 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -16,14 +16,32 @@ * USA. */ #include <rfb/CMsgReader.h> +#include <rfb/CConnection.h> #include <rfb/CMsgHandler.h> #include <rfb/ZRLEDecoder.h> using namespace rfb; -#define EXTRA_ARGS CMsgHandler* handler -#define FILL_RECT(r, p) handler->fillRect(r, p) -#define IMAGE_RECT(r, p) handler->imageRect(r, p) +static inline rdr::U32 readOpaque24A(rdr::InStream* is) +{ + is->check(3); + rdr::U32 r=0; + ((rdr::U8*)&r)[0] = is->readU8(); + ((rdr::U8*)&r)[1] = is->readU8(); + ((rdr::U8*)&r)[2] = is->readU8(); + return r; + +} +static inline rdr::U32 readOpaque24B(rdr::InStream* is) +{ + is->check(3); + rdr::U32 r=0; + ((rdr::U8*)&r)[1] = is->readU8(); + ((rdr::U8*)&r)[2] = is->readU8(); + ((rdr::U8*)&r)[3] = is->readU8(); + return r; +} + #define BPP 8 #include <rfb/zrleDecode.h> #undef BPP @@ -40,7 +58,7 @@ using namespace rfb; #undef CPIXEL #undef BPP -ZRLEDecoder::ZRLEDecoder(CMsgReader* reader_) : reader(reader_) +ZRLEDecoder::ZRLEDecoder(CConnection* conn) : Decoder(conn) { } @@ -50,9 +68,9 @@ ZRLEDecoder::~ZRLEDecoder() void ZRLEDecoder::readRect(const Rect& r, CMsgHandler* handler) { - rdr::InStream* is = reader->getInStream(); - rdr::U8* buf = reader->getImageBuf(64 * 64 * 4); - switch (reader->bpp()) { + rdr::InStream* is = conn->getInStream(); + rdr::U8* buf = conn->reader()->getImageBuf(64 * 64 * 4); + switch (conn->cp.pf().bpp) { case 8: zrleDecode8 (r, is, &zis, (rdr::U8*) buf, handler); break; case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, handler); break; case 32: diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h index 2128ab91..e7e2b8cb 100644 --- a/common/rfb/ZRLEDecoder.h +++ b/common/rfb/ZRLEDecoder.h @@ -25,11 +25,10 @@ namespace rfb { class ZRLEDecoder : public Decoder { public: - ZRLEDecoder(CMsgReader* reader); + ZRLEDecoder(CConnection* conn); virtual ~ZRLEDecoder(); virtual void readRect(const Rect& r, CMsgHandler* handler); private: - CMsgReader* reader; rdr::ZlibInStream zis; }; } diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index e70706b5..968edcfb 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -21,6 +21,7 @@ #include <rfb/encodings.h> #include <rfb/ConnParams.h> #include <rfb/SMsgWriter.h> +#include <rfb/SConnection.h> #include <rfb/ZRLEEncoder.h> #include <rfb/Configuration.h> @@ -28,8 +29,21 @@ using namespace rfb; IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1); -#define EXTRA_ARGS ImageGetter* ig -#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r); +static inline void writeOpaque24A(rdr::OutStream* os, rdr::U32 u) +{ + os->check(3); + os->writeU8(((rdr::U8*)&u)[0]); + os->writeU8(((rdr::U8*)&u)[1]); + os->writeU8(((rdr::U8*)&u)[2]); +} +static inline void writeOpaque24B(rdr::OutStream* os, rdr::U32 u) +{ + os->check(3); + os->writeU8(((rdr::U8*)&u)[1]); + os->writeU8(((rdr::U8*)&u)[2]); + os->writeU8(((rdr::U8*)&u)[3]); +} + #define BPP 8 #include <rfb/zrleEncode.h> #undef BPP @@ -46,8 +60,8 @@ IntParameter zlibLevel("ZlibLevel","Zlib compression level",-1); #undef CPIXEL #undef BPP -ZRLEEncoder::ZRLEEncoder(SMsgWriter* writer_) - : writer(writer_), zos(0,0,zlibLevel), mos(129*1024) +ZRLEEncoder::ZRLEEncoder(SConnection* conn) + : Encoder(conn), zos(0,0,zlibLevel), mos(129*1024) { } @@ -55,23 +69,21 @@ ZRLEEncoder::~ZRLEEncoder() { } -bool ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) +void ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig) { - rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4); + rdr::U8* imageBuf = conn->writer()->getImageBuf(64 * 64 * 4 + 4); mos.clear(); - bool wroteAll = true; - *actual = r; - switch (writer->bpp()) { + switch (conn->cp.pf().bpp) { case 8: - wroteAll = zrleEncode8(r, &mos, &zos, imageBuf, actual, ig); + zrleEncode8(r, &mos, &zos, imageBuf, ig); break; case 16: - wroteAll = zrleEncode16(r, &mos, &zos, imageBuf, actual, ig); + zrleEncode16(r, &mos, &zos, imageBuf, ig); break; case 32: { - const PixelFormat& pf = writer->getConnParams()->pf(); + const PixelFormat& pf = conn->cp.pf(); Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1); bool fitsInLS3Bytes = maxPixel < (1<<24); @@ -80,25 +92,24 @@ bool ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual) if ((fitsInLS3Bytes && pf.isLittleEndian()) || (fitsInMS3Bytes && pf.isBigEndian())) { - wroteAll = zrleEncode24A(r, &mos, &zos, imageBuf, actual, ig); + zrleEncode24A(r, &mos, &zos, imageBuf, ig); } else if ((fitsInLS3Bytes && pf.isBigEndian()) || (fitsInMS3Bytes && pf.isLittleEndian())) { - wroteAll = zrleEncode24B(r, &mos, &zos, imageBuf, actual, ig); + zrleEncode24B(r, &mos, &zos, imageBuf, ig); } else { - wroteAll = zrleEncode32(r, &mos, &zos, imageBuf, actual, ig); + zrleEncode32(r, &mos, &zos, imageBuf, ig); } break; } } - writer->startRect(*actual, encodingZRLE); - rdr::OutStream* os = writer->getOutStream(); + conn->writer()->startRect(r, encodingZRLE); + rdr::OutStream* os = conn->getOutStream(); os->writeU32(mos.length()); os->writeBytes(mos.data(), mos.length()); - writer->endRect(); - return wroteAll; + conn->writer()->endRect(); } diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index e3517c13..d285967e 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -26,11 +26,10 @@ namespace rfb { class ZRLEEncoder : public Encoder { public: - ZRLEEncoder(SMsgWriter* writer); + ZRLEEncoder(SConnection* conn); virtual ~ZRLEEncoder(); - virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual); + virtual void writeRect(const Rect& r, TransImageGetter* ig); private: - SMsgWriter* writer; rdr::ZlibOutStream zos; rdr::MemOutStream mos; }; diff --git a/common/rfb/hextileDecode.h b/common/rfb/hextileDecode.h index 7aa04d91..518a6063 100644 --- a/common/rfb/hextileDecode.h +++ b/common/rfb/hextileDecode.h @@ -18,11 +18,8 @@ // // Hextile decoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// FILL_RECT - fill a rectangle with a single colour -// IMAGE_RECT - draw a rectangle of pixel data from a buffer #include <rdr/InStream.h> #include <rfb/hextileConstants.h> @@ -40,11 +37,8 @@ namespace rfb { #define READ_PIXEL CONCAT2E(readOpaque,BPP) #define HEXTILE_DECODE CONCAT2E(hextileDecode,BPP) -void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf, + CMsgHandler* handler) { Rect t; PIXEL_T bg = 0; @@ -62,7 +56,7 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf if (tileType & hextileRaw) { is->readBytes(buf, t.area() * (BPP/8)); - IMAGE_RECT(t, buf); + handler->imageRect(t, buf); continue; } @@ -100,7 +94,7 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf } } } - IMAGE_RECT(t, buf); + handler->imageRect(t, buf); } } } diff --git a/common/rfb/hextileEncode.h b/common/rfb/hextileEncode.h index 0d2e8aba..7e5b2db7 100644 --- a/common/rfb/hextileEncode.h +++ b/common/rfb/hextileEncode.h @@ -19,10 +19,8 @@ // // Hextile encoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer #include <rdr/OutStream.h> #include <rfb/hextileConstants.h> @@ -46,11 +44,7 @@ int TEST_TILE_TYPE (PIXEL_T* data, int w, int h, PIXEL_T* bg, PIXEL_T* fg); int HEXTILE_ENCODE_TILE (PIXEL_T* data, int w, int h, int tileType, rdr::U8* encoded, PIXEL_T bg); -void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig) { Rect t; PIXEL_T buf[256]; @@ -67,7 +61,7 @@ void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os t.br.x = __rfbmin(r.br.x, t.tl.x + 16); - GET_IMAGE_INTO_BUF(t,buf); + ig->getImage(buf, t); PIXEL_T bg = 0, fg = 0; int tileType = TEST_TILE_TYPE(buf, t.width(), t.height(), &bg, &fg); @@ -96,7 +90,7 @@ void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os encoded, bg); if (encodedLen < 0) { - GET_IMAGE_INTO_BUF(t,buf); + ig->getImage(buf, t); os->writeU8(hextileRaw); os->writeBytes(buf, t.width() * t.height() * (BPP/8)); oldBgValid = oldFgValid = false; diff --git a/common/rfb/hextileEncodeBetter.h b/common/rfb/hextileEncodeBetter.h index 2b6b160a..3a96ab63 100644 --- a/common/rfb/hextileEncodeBetter.h +++ b/common/rfb/hextileEncodeBetter.h @@ -19,14 +19,12 @@ // // Hextile encoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer #include <rdr/OutStream.h> #include <rfb/hextileConstants.h> -#include <rfb/TightPalette.h> +#include <rfb/Palette.h> #include <assert.h> @@ -114,13 +112,13 @@ class HEXTILE_TILE { private: bool m_processed[16][16]; - TightPalette m_pal; + Palette m_pal; }; HEXTILE_TILE::HEXTILE_TILE() : m_tile(NULL), m_width(0), m_height(0), m_size(0), m_flags(0), m_background(0), m_foreground(0), - m_numSubrects(0), m_pal(48 + 2 * BPP) + m_numSubrects(0) { } @@ -156,7 +154,7 @@ void HEXTILE_TILE::analyze() PIXEL_T *colorsPtr = m_colors; rdr::U8 *coordsPtr = m_coords; - m_pal.reset(); + m_pal.clear(); m_numSubrects = 0; // Have we found the first subrect already? @@ -200,7 +198,7 @@ void HEXTILE_TILE::analyze() *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F)); *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F)); - if (m_pal.insert(color, 1) == 0) { + if (!m_pal.insert(color, 1) || (m_pal.size() > (48 + 2 * BPP))) { // Handle palette overflow m_flags = hextileRaw; m_size = 0; @@ -221,16 +219,16 @@ void HEXTILE_TILE::analyze() } // Save number of colors in this tile (should be no less than 2) - int numColors = m_pal.getNumColors(); + int numColors = m_pal.size(); assert(numColors >= 2); - m_background = (PIXEL_T)m_pal.getEntry(0); + m_background = (PIXEL_T)m_pal.getColour(0); m_flags = hextileAnySubrects; int numSubrects = m_numSubrects - m_pal.getCount(0); if (numColors == 2) { // Monochrome tile - m_foreground = (PIXEL_T)m_pal.getEntry(1); + m_foreground = (PIXEL_T)m_pal.getColour(1); m_size = 1 + 2 * numSubrects; } else { // Colored tile @@ -277,11 +275,7 @@ void HEXTILE_TILE::encode(rdr::U8 *dst) const // Main encoding function. // -void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os, TransImageGetter *ig) { Rect t; PIXEL_T buf[256]; @@ -300,7 +294,7 @@ void HEXTILE_ENCODE(const Rect& r, rdr::OutStream* os t.br.x = __rfbmin(r.br.x, t.tl.x + 16); - GET_IMAGE_INTO_BUF(t,buf); + ig->getImage(buf, t); tile.newTile(buf, t.width(), t.height()); int tileType = tile.getFlags(); diff --git a/common/rfb/rreDecode.h b/common/rfb/rreDecode.h index 1f5bdf8b..d37461f9 100644 --- a/common/rfb/rreDecode.h +++ b/common/rfb/rreDecode.h @@ -18,10 +18,8 @@ // // RRE decoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// FILL_RECT - fill a rectangle with a single colour #include <rdr/InStream.h> @@ -38,15 +36,11 @@ namespace rfb { #define READ_PIXEL CONCAT2E(readOpaque,BPP) #define RRE_DECODE CONCAT2E(rreDecode,BPP) -void RRE_DECODE (const Rect& r, rdr::InStream* is -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void RRE_DECODE (const Rect& r, rdr::InStream* is, CMsgHandler* handler) { int nSubrects = is->readU32(); PIXEL_T bg = is->READ_PIXEL(); - FILL_RECT(r, bg); + handler->fillRect(r, bg); for (int i = 0; i < nSubrects; i++) { PIXEL_T pix = is->READ_PIXEL(); @@ -54,7 +48,7 @@ void RRE_DECODE (const Rect& r, rdr::InStream* is int y = is->readU16(); int w = is->readU16(); int h = is->readU16(); - FILL_RECT(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix); + handler->fillRect(Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix); } } diff --git a/common/rfb/rreEncode.h b/common/rfb/rreEncode.h index 3f834877..e3710575 100644 --- a/common/rfb/rreEncode.h +++ b/common/rfb/rreEncode.h @@ -18,7 +18,7 @@ // // RRE encoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 // // The data argument to RRE_ENCODE contains the pixel data, and it writes the diff --git a/common/rfb/tightDecode.h b/common/rfb/tightDecode.h index 06c84775..a5963119 100644 --- a/common/rfb/tightDecode.h +++ b/common/rfb/tightDecode.h @@ -21,11 +21,8 @@ // // Tight decoding functions. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// FILL_RECT - fill a rectangle with a single color -// IMAGE_RECT - draw a rectangle of pixel data from a buffer #include <rdr/InStream.h> #include <rdr/ZlibInStream.h> @@ -76,11 +73,11 @@ void TIGHT_DECODE (const Rect& r) if (cutZeros) { rdr::U8 bytebuf[3]; is->readBytes(bytebuf, 3); - serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1); } else { pix = is->READ_PIXEL(); } - FILL_RECT(r, pix); + handler->fillRect(r, pix); return; } @@ -110,7 +107,7 @@ void TIGHT_DECODE (const Rect& r) if (cutZeros) { rdr::U8 tightPalette[256 * 3]; is->readBytes(tightPalette, palSize * 3); - serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize, NULL); + serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize); } else { is->readBytes(palette, palSize * sizeof(PIXEL_T)); } @@ -141,7 +138,7 @@ void TIGHT_DECODE (const Rect& r) if (dataSize < TIGHT_MIN_TO_COMPRESS) { input = is; } else { - int length = is->readCompactLength(); + int length = readCompact(is); streamId = comp_ctl & 0x03; zis[streamId].setUnderlying(is, length); input = &zis[streamId]; @@ -157,7 +154,7 @@ void TIGHT_DECODE (const Rect& r) PIXEL_T *buf; int stride = r.width(); if (directDecode) buf = (PIXEL_T *)handler->getRawBufferRW(r, &stride); - else buf = (PIXEL_T *)reader->getImageBuf(r.area()); + else buf = (PIXEL_T *)conn->reader()->getImageBuf(r.area()); if (palSize == 0) { // Truecolor data @@ -178,7 +175,7 @@ void TIGHT_DECODE (const Rect& r) int w = r.width(); if (cutZeros) { while (h > 0) { - serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w, NULL); + serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w); ptr += stride; srcPtr += w * 3; h--; @@ -229,7 +226,7 @@ void TIGHT_DECODE (const Rect& r) } if (directDecode) handler->releaseRawBuffer(r); - else IMAGE_RECT(r, buf); + else handler->imageRect(r, buf); delete [] netbuf; @@ -242,7 +239,7 @@ void DECOMPRESS_JPEG_RECT(const Rect& r) { // Read length - int compressedLen = is->readCompactLength(); + int compressedLen = readCompact(is); if (compressedLen <= 0) { throw Exception("Incorrect data received from the server.\n"); } @@ -287,7 +284,7 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c]; thisRow[c] = pix[c]; } - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { @@ -301,7 +298,7 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride, pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c]; thisRow[x*3+c] = pix[c]; } - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); } memcpy(prevRow, thisRow, sizeof(prevRow)); @@ -327,13 +324,13 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) for (y = 0; y < rectHeight; y++) { /* First pixel in a row */ - serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1, NULL); + serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth], 1); for (c = 0; c < 3; c++) pix[c] += prevRow[c]; memcpy(thisRow, pix, sizeof(pix)); - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1); /* Remaining pixels of a row */ for (x = 1; x < rectWidth; x++) { @@ -346,13 +343,13 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r) } } - serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1, NULL); + serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1); for (c = 0; c < 3; c++) pix[c] += est[c]; memcpy(&thisRow[x*3], pix, sizeof(pix)); - serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1, NULL); + serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1); } memcpy(prevRow, thisRow, sizeof(prevRow)); diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h index c121b7aa..5d32cce3 100644 --- a/common/rfb/tightEncode.h +++ b/common/rfb/tightEncode.h @@ -1,5 +1,6 @@ /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2014 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 @@ -20,10 +21,8 @@ // // tightEncode.h - Tight encoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer // #include <assert.h> @@ -54,82 +53,6 @@ namespace rfb { #define TIGHT_ONCE // -// Functions to operate on palette structures. -// - -#define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF)) -#define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF)) - -void TightEncoder::paletteReset(void) -{ - palNumColors = 0; - memset(palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *)); -} - -int TightEncoder::paletteInsert(rdr::U32 rgb, int numPixels, int bpp) -{ - TIGHT_COLOR_LIST *pnode; - TIGHT_COLOR_LIST *prev_pnode = NULL; - int hash_key, idx, new_idx, count; - - hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb); - - pnode = palette.hash[hash_key]; - - while (pnode != NULL) { - if (pnode->rgb == rgb) { - // Such palette entry already exists. - new_idx = idx = pnode->idx; - count = palette.entry[idx].numPixels + numPixels; - if (new_idx && palette.entry[new_idx-1].numPixels < count) { - do { - palette.entry[new_idx] = palette.entry[new_idx-1]; - palette.entry[new_idx].listNode->idx = new_idx; - new_idx--; - } - while (new_idx && - palette.entry[new_idx-1].numPixels < count); - palette.entry[new_idx].listNode = pnode; - pnode->idx = new_idx; - } - palette.entry[new_idx].numPixels = count; - return palNumColors; - } - prev_pnode = pnode; - pnode = pnode->next; - } - - // Check if palette is full. - if ( palNumColors == 256 || palNumColors == palMaxColors ) { - palNumColors = 0; - return 0; - } - - // Move palette entries with lesser pixel counts. - for ( idx = palNumColors; - idx > 0 && palette.entry[idx-1].numPixels < numPixels; - idx-- ) { - palette.entry[idx] = palette.entry[idx-1]; - palette.entry[idx].listNode->idx = idx; - } - - // Add new palette entry into the freed slot. - pnode = &palette.list[palNumColors]; - if (prev_pnode != NULL) { - prev_pnode->next = pnode; - } else { - palette.hash[hash_key] = pnode; - } - pnode->next = NULL; - pnode->idx = idx; - pnode->rgb = rgb; - palette.entry[idx].listNode = pnode; - palette.entry[idx].numPixels = numPixels; - - return (++palNumColors); -} - -// // Compress the data (but do not perform actual compression if the data // size is less than TIGHT_MIN_TO_COMPRESS bytes. // @@ -151,7 +74,7 @@ void TightEncoder::compressData(const void *buf, unsigned int length, zos->writeBytes(buf, length); zos->flush(); zos->setUnderlying(NULL); - os->writeCompactLength(mem_os.length()); + writeCompact(os, mem_os.length()); os->writeBytes(mem_os.data(), mem_os.length()); } } @@ -176,7 +99,7 @@ unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count) rdr::U8 *dst = (rdr::U8 *)buf; for (unsigned int i = 0; i < count; i++) { pix = *buf++; - clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL); + clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1); dst += 3; } return count * 3; @@ -203,9 +126,10 @@ void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid) if (forceSolid) { // Subrectangle has already been determined to be solid. - palNumColors = 1; ig->translatePixels(rawPixels, &solidColor, 1); pixels = (PIXEL_T *)&solidColor; + palette.clear(); + palette.insert(solidColor, 1); } else { // Analyze subrectangle's colors to determine best encoding method. palMaxColors = r.area() / pconf->idxMaxColorsDivisor; @@ -217,29 +141,29 @@ void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid) if (clientpf.equal(serverpf) && clientpf.bpp >= 16) { // Count the colors in the raw buffer, so we can avoid unnecessary pixel // translation when encoding with JPEG. - if (grayScaleJPEG) palNumColors = 0; + if (grayScaleJPEG) palette.clear(); else FAST_FILL_PALETTE(rawPixels, stride, r); // JPEG can read from the raw buffer, but for the other methods, we need // to translate the raw pixels into an intermediate buffer. - if(palNumColors != 0 || jpegQuality == -1) { - pixels = (PIXEL_T *)writer->getImageBuf(r.area()); + if(palette.size() != 0 || jpegQuality == -1) { + pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); stride = r.width(); ig->getImage(pixels, r); } } else { // Pixel translation will be required, so create an intermediate buffer, // translate the raw pixels into it, and count its colors. - pixels = (PIXEL_T *)writer->getImageBuf(r.area()); + pixels = (PIXEL_T *)conn->writer()->getImageBuf(r.area()); stride = r.width(); ig->getImage(pixels, r); - if (grayScaleJPEG) palNumColors = 0; + if (grayScaleJPEG) palette.clear(); else FILL_PALETTE(pixels, r.area()); } } - switch (palNumColors) { + switch (palette.size()) { case 0: // Truecolor image #if (BPP != 8) @@ -297,7 +221,8 @@ void ENCODE_MONO_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os) os->writeU8(0x01); // Write the palette - PIXEL_T pal[2] = { (PIXEL_T)monoBackground, (PIXEL_T)monoForeground }; + PIXEL_T pal[2] = { (PIXEL_T)palette.getColour(0), + (PIXEL_T)palette.getColour(1) }; os->writeU8(1); os->writeBytes(pal, PACK_PIXELS(pal, 2)); @@ -311,7 +236,7 @@ void ENCODE_MONO_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os) int aligned_width; int x, y, bg_bits; - bg = (PIXEL_T) monoBackground; + bg = (PIXEL_T) pal[0]; aligned_width = w - w % 8; for (y = 0; y < h; y++) { @@ -365,10 +290,10 @@ void ENCODE_INDEXED_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os) // Write the palette { PIXEL_T pal[256]; - for (int i = 0; i < palNumColors; i++) - pal[i] = (PIXEL_T)palette.entry[i].listNode->rgb; - os->writeU8((rdr::U8)(palNumColors - 1)); - os->writeBytes(pal, PACK_PIXELS(pal, palNumColors)); + for (int i = 0; i < palette.size(); i++) + pal[i] = (PIXEL_T)palette.getColour(i); + os->writeU8((rdr::U8)(palette.size() - 1)); + os->writeBytes(pal, PACK_PIXELS(pal, palette.size())); } // Encode data in-place @@ -376,25 +301,19 @@ void ENCODE_INDEXED_RECT (PIXEL_T *buf, const Rect& r, rdr::OutStream *os) rdr::U8 *dst = (rdr::U8 *)buf; int count = r.area(); PIXEL_T rgb; - TIGHT_COLOR_LIST *pnode; int rep = 0; + unsigned char idx; while (count--) { rgb = *src++; while (count && *src == rgb) { rep++, src++, count--; } - pnode = palette.hash[HASH_FUNCTION(rgb)]; - while (pnode != NULL) { - if ((PIXEL_T)pnode->rgb == rgb) { - *dst++ = (rdr::U8)pnode->idx; - while (rep) { - *dst++ = (rdr::U8)pnode->idx; - rep--; - } - break; - } - pnode = pnode->next; + idx = palette.lookup(rgb); + *dst++ = idx; + while (rep) { + *dst++ = idx; + rep--; } } @@ -415,7 +334,7 @@ void ENCODE_JPEG_RECT (PIXEL_T *buf, int stride, const Rect& r, jc.compress((rdr::U8 *)buf, stride, r, clientpf, jpegQuality, jpegSubsampling); os->writeU8(0x09 << 4); - os->writeCompactLength(jc.length()); + writeCompact(os, jc.length()); os->writeBytes(jc.data(), jc.length()); } #endif // #if (BPP != 8) @@ -431,12 +350,12 @@ void FILL_PALETTE (PIXEL_T *data, int count) PIXEL_T c0, c1; int i, n0, n1; - palNumColors = 0; + palette.clear(); c0 = data[0]; for (i = 1; i < count && data[i] == c0; i++); if (i == count) { - palNumColors = 1; + palette.insert(c0, i); return; // Solid rectangle } @@ -455,14 +374,8 @@ void FILL_PALETTE (PIXEL_T *data, int count) break; } if (i == count) { - if (n0 > n1) { - monoBackground = (rdr::U32)c0; - monoForeground = (rdr::U32)c1; - } else { - monoBackground = (rdr::U32)c1; - monoForeground = (rdr::U32)c0; - } - palNumColors = 2; // Two colors + palette.insert(c0, n0); // Two colors + palette.insert(c1, n1); } } @@ -477,17 +390,17 @@ void FILL_PALETTE (PIXEL_T *data, int count) PIXEL_T c0, c1, ci = 0; int i, n0, n1, ni; + palette.clear(); + c0 = data[0]; for (i = 1; i < count && data[i] == c0; i++); if (i >= count) { - palNumColors = 1; // Solid rectangle + palette.insert(c0, i); // Solid rectangle return; } - if (palMaxColors < 2) { - palNumColors = 0; // Full-color format preferred - return; - } + if (palMaxColors < 2) + return; // Full-color format preferred n0 = i; c1 = data[i]; @@ -501,34 +414,26 @@ void FILL_PALETTE (PIXEL_T *data, int count) } else break; } - if (i >= count) { - if (n0 > n1) { - monoBackground = (rdr::U32)c0; - monoForeground = (rdr::U32)c1; - } else { - monoBackground = (rdr::U32)c1; - monoForeground = (rdr::U32)c0; - } - palNumColors = 2; // Two colors - return; - } - - paletteReset(); - paletteInsert (c0, (rdr::U32)n0, BPP); - paletteInsert (c1, (rdr::U32)n1, BPP); + palette.insert(c0, n0); + palette.insert(c1, n1); + if (i >= count) + return; // Two colors ni = 1; for (i++; i < count; i++) { if (data[i] == ci) { ni++; } else { - if (!paletteInsert (ci, (rdr::U32)ni, BPP)) + if (!palette.insert (ci, ni) || (palette.size() > palMaxColors)) { + palette.clear(); return; + } ci = data[i]; ni = 1; } } - paletteInsert (ci, (rdr::U32)ni, BPP); + if (!palette.insert (ci, ni) || (palette.size() > palMaxColors)) + palette.clear(); } void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) @@ -542,6 +447,8 @@ void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) serverpf.bufferFromPixel((rdr::U8*)&mask, ~0); + palette.clear(); + c0 = data[0] & mask; n0 = 0; for (rowptr = data; rowptr < dataend; rowptr += stride) { @@ -554,13 +461,11 @@ void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) soliddone: if (rowptr >= dataend) { - palNumColors = 1; // Solid rectangle - return; - } - if (palMaxColors < 2) { - palNumColors = 0; // Full-color format preferred + palette.insert(c0, 1); // Solid rectangle return; } + if (palMaxColors < 2) + return; // Full-color format preferred c1 = *colptr & mask; n1 = 0; @@ -592,21 +497,11 @@ void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) c0t = c0; c1t = c1; } - if (colptr2 >= dataend) { - if (n0 > n1) { - monoBackground = (rdr::U32)c0t; - monoForeground = (rdr::U32)c1t; - } else { - monoBackground = (rdr::U32)c1t; - monoForeground = (rdr::U32)c0t; - } - palNumColors = 2; // Two colors - return; - } + palette.insert(c0t, n0); + palette.insert(c1t, n1); - paletteReset(); - paletteInsert (c0t, (rdr::U32)n0, BPP); - paletteInsert (c1t, (rdr::U32)n1, BPP); + if (colptr2 >= dataend) + return; // Two colors ni = 1; colptr2++; @@ -623,8 +518,10 @@ void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) ig->translatePixels(&ci, &cit, 1); else cit = ci; - if (!paletteInsert (cit, (rdr::U32)ni, BPP)) + if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) { + palette.clear(); return; + } ci = (*colptr) & mask; ni = 1; } @@ -633,7 +530,8 @@ void FAST_FILL_PALETTE (const PIXEL_T *data, int stride, const Rect& r) colptr = rowptr; } ig->translatePixels(&ci, &cit, 1); - paletteInsert (cit, (rdr::U32)ni, BPP); + if (!palette.insert (cit, ni) || (palette.size() > palMaxColors)) + palette.clear(); } #endif // #if (BPP == 8) diff --git a/common/rfb/transInitTempl.h b/common/rfb/transInitTempl.h index 464cfdfc..348f12b9 100644 --- a/common/rfb/transInitTempl.h +++ b/common/rfb/transInitTempl.h @@ -46,12 +46,8 @@ namespace rfb { #define OUTPIXEL rdr::CONCAT2E(U,BPPOUT) #define SWAPOUT CONCAT2E(SWAP,BPPOUT) -#define initSimpleCMtoTCOUT CONCAT2E(initSimpleCMtoTC,BPPOUT) -#define initSimpleTCtoTCOUT CONCAT2E(initSimpleTCtoTC,BPPOUT) -#define initSimpleCMtoCubeOUT CONCAT2E(initSimpleCMtoCube,BPPOUT) -#define initSimpleTCtoCubeOUT CONCAT2E(initSimpleTCtoCube,BPPOUT) -#define initRGBTCtoTCOUT CONCAT2E(initRGBTCtoTC,BPPOUT) -#define initRGBTCtoCubeOUT CONCAT2E(initRGBTCtoCube,BPPOUT) +#define initSimpleOUT CONCAT2E(initSimple,BPPOUT) +#define initRGBOUT CONCAT2E(initRGB,BPPOUT) #define initOneRGBTableOUT CONCAT2E(initOneRGBTable,BPPOUT) #define initOneRGBCubeTableOUT CONCAT2E(initOneRGBCubeTable,BPPOUT) @@ -61,34 +57,8 @@ namespace rfb { static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1; #endif -void initSimpleCMtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF, - ColourMap* cm, const PixelFormat& outPF) -{ - if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) - throw Exception("Internal error: inPF is not native endian"); - - int size = 1 << inPF.bpp; - - delete [] *tablep; - *tablep = new rdr::U8[size * sizeof(OUTPIXEL)]; - OUTPIXEL* table = (OUTPIXEL*)*tablep; - - for (int i = 0; i < size; i++) { - int r,g,b; - cm->lookup(i,&r,&g,&b); - - table[i] = ((((r * outPF.redMax + 32767) / 65535) << outPF.redShift) | - (((g * outPF.greenMax + 32767) / 65535) << outPF.greenShift) | - (((b * outPF.blueMax + 32767) / 65535) << outPF.blueShift)); -#if (BPPOUT != 8) - if (outPF.bigEndian != nativeBigEndian) - table[i] = SWAPOUT (table[i]); -#endif - } -} - -void initSimpleTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF, - const PixelFormat& outPF) +void initSimpleOUT (rdr::U8** tablep, const PixelFormat& inPF, + const PixelFormat& outPF) { if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) throw Exception("Internal error: inPF is not native endian"); @@ -118,55 +88,8 @@ void initSimpleTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF, } } -void initSimpleCMtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF, - ColourMap* cm, ColourCube* cube) -{ - if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) - throw Exception("Internal error: inPF is not native endian"); - - int size = 1 << inPF.bpp; - - delete [] *tablep; - *tablep = new rdr::U8[size * sizeof(OUTPIXEL)]; - OUTPIXEL* table = (OUTPIXEL*)*tablep; - - for (int i = 0; i < size; i++) { - int r,g,b; - cm->lookup(i,&r,&g,&b); - r = (r * (cube->nRed-1) + 32767) / 65535; - g = (g * (cube->nGreen-1) + 32767) / 65535; - b = (b * (cube->nBlue-1) + 32767) / 65535; - table[i] = cube->lookup(r, g, b); - } -} - -void initSimpleTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF, - ColourCube* cube) -{ - if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) - throw Exception("Internal error: inPF is not native endian"); - - int size = 1 << inPF.bpp; - - delete [] *tablep; - *tablep = new rdr::U8[size * sizeof(OUTPIXEL)]; - OUTPIXEL* table = (OUTPIXEL*)*tablep; - - for (int i = 0; i < size; i++) { - int r = (i >> inPF.redShift) & inPF.redMax; - int g = (i >> inPF.greenShift) & inPF.greenMax; - int b = (i >> inPF.blueShift) & inPF.blueMax; - - r = (r * (cube->nRed-1) + inPF.redMax/2) / inPF.redMax; - g = (g * (cube->nGreen-1) + inPF.greenMax/2) / inPF.greenMax; - b = (b * (cube->nBlue-1) + inPF.blueMax/2) / inPF.blueMax; - - table[i] = cube->lookup(r, g, b); - } -} - -void initOneRGBTableOUT (OUTPIXEL* table, int inMax, int outMax, - int outShift, bool swap) +static void initOneRGBTableOUT (OUTPIXEL* table, int inMax, int outMax, + int outShift, bool swap) { int size = inMax + 1; @@ -179,8 +102,8 @@ void initOneRGBTableOUT (OUTPIXEL* table, int inMax, int outMax, } } -void initRGBTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF, - const PixelFormat& outPF) +void initRGBOUT (rdr::U8** tablep, const PixelFormat& inPF, + const PixelFormat& outPF) { if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) throw Exception("Internal error: inPF is not native endian"); @@ -205,50 +128,8 @@ void initRGBTCtoTCOUT (rdr::U8** tablep, const PixelFormat& inPF, } -void initOneRGBCubeTableOUT (OUTPIXEL* table, int inMax, int outMax, - int outMult) -{ - int size = inMax + 1; - - for (int i = 0; i < size; i++) { - table[i] = ((i * outMax + inMax / 2) / inMax) * outMult; - } -} - -void initRGBTCtoCubeOUT (rdr::U8** tablep, const PixelFormat& inPF, - ColourCube* cube) -{ - if (inPF.bpp != 8 && inPF.bigEndian != nativeBigEndian) - throw Exception("Internal error: inPF is not native endian"); - - int size = inPF.redMax + inPF.greenMax + inPF.blueMax + 3 + cube->size(); - - delete [] *tablep; - *tablep = new rdr::U8[size * sizeof(OUTPIXEL)]; - - OUTPIXEL* redTable = (OUTPIXEL*)*tablep; - OUTPIXEL* greenTable = redTable + inPF.redMax + 1; - OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1; - OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1; - - initOneRGBCubeTableOUT (redTable, inPF.redMax, cube->nRed-1, - cube->redMult()); - initOneRGBCubeTableOUT (greenTable, inPF.greenMax, cube->nGreen-1, - cube->greenMult()); - initOneRGBCubeTableOUT (blueTable, inPF.blueMax, cube->nBlue-1, - cube->blueMult()); - for (int i = 0; i < cube->size(); i++) { - cubeTable[i] = cube->table[i]; - } -} - #undef OUTPIXEL -#undef initSimpleCMtoTCOUT -#undef initSimpleTCtoTCOUT -#undef initSimpleCMtoCubeOUT -#undef initSimpleTCtoCubeOUT -#undef initRGBTCtoTCOUT -#undef initRGBTCtoCubeOUT +#undef initSimpleOUT +#undef initRGBOUT #undef initOneRGBTableOUT -#undef initOneRGBCubeTableOUT } diff --git a/common/rfb/transTempl.h b/common/rfb/transTempl.h index b133e869..49edb0ac 100644 --- a/common/rfb/transTempl.h +++ b/common/rfb/transTempl.h @@ -42,7 +42,6 @@ #define OUTPIXEL rdr::CONCAT2E(U,BPPOUT) #define transSimpleINtoOUT CONCAT4E(transSimple,BPPIN,to,BPPOUT) #define transRGBINtoOUT CONCAT4E(transRGB,BPPIN,to,BPPOUT) -#define transRGBCubeINtoOUT CONCAT4E(transRGBCube,BPPIN,to,BPPOUT) #if (BPPIN <= 16) @@ -111,41 +110,9 @@ void transRGBINtoOUT (void* table, } } -// transRGBCubeINtoOUT is similar to transRGBINtoOUT but also looks up the -// colour cube index in a fourth table to yield a pixel value. - -void transRGBCubeINtoOUT (void* table, - const PixelFormat& inPF, const void* inPtr, int inStride, - const PixelFormat& outPF, void* outPtr, - int outStride, int width, int height) -{ - OUTPIXEL* redTable = (OUTPIXEL*)table; - OUTPIXEL* greenTable = redTable + inPF.redMax + 1; - OUTPIXEL* blueTable = greenTable + inPF.greenMax + 1; - OUTPIXEL* cubeTable = blueTable + inPF.blueMax + 1; - INPIXEL* ip = (INPIXEL*)inPtr; - OUTPIXEL* op = (OUTPIXEL*)outPtr; - int inExtra = inStride - width; - int outExtra = outStride - width; - - while (height > 0) { - OUTPIXEL* opEndOfRow = op + width; - while (op < opEndOfRow) { - *op++ = cubeTable[(redTable [(*ip >> inPF.redShift) & inPF.redMax] + - greenTable[(*ip >> inPF.greenShift) & inPF.greenMax] + - blueTable [(*ip >> inPF.blueShift) & inPF.blueMax])]; - ip++; - } - ip += inExtra; - op += outExtra; - height--; - } -} - #endif #undef INPIXEL #undef OUTPIXEL #undef transSimpleINtoOUT #undef transRGBINtoOUT -#undef transRGBCubeINtoOUT diff --git a/common/rfb/zrleDecode.h b/common/rfb/zrleDecode.h index d26d4d3e..4bcbf1f0 100644 --- a/common/rfb/zrleDecode.h +++ b/common/rfb/zrleDecode.h @@ -19,11 +19,8 @@ // // ZRLE decoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// FILL_RECT - fill a rectangle with a single colour -// IMAGE_RECT - draw a rectangle of pixel data from a buffer #include <stdio.h> #include <rdr/InStream.h> @@ -41,20 +38,17 @@ namespace rfb { #ifdef CPIXEL #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL CONCAT2E(readOpaque,CPIXEL) +#define READ_PIXEL(is) CONCAT2E(readOpaque,CPIXEL)(is) #define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL) #else #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define READ_PIXEL CONCAT2E(readOpaque,BPP) +#define READ_PIXEL(is) is->CONCAT2E(readOpaque,BPP)() #define ZRLE_DECODE CONCAT2E(zrleDecode,BPP) #endif void ZRLE_DECODE (const Rect& r, rdr::InStream* is, - rdr::ZlibInStream* zis, PIXEL_T* buf -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) + rdr::ZlibInStream* zis, PIXEL_T* buf, + CMsgHandler* handler) { int length = is->readU32(); zis->setUnderlying(is, length); @@ -74,12 +68,12 @@ void ZRLE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T palette[128]; for (int i = 0; i < palSize; i++) { - palette[i] = zis->READ_PIXEL(); + palette[i] = READ_PIXEL(zis); } if (palSize == 1) { PIXEL_T pix = palette[0]; - FILL_RECT(t,pix); + handler->fillRect(t, pix); continue; } @@ -90,7 +84,7 @@ void ZRLE_DECODE (const Rect& r, rdr::InStream* is, #ifdef CPIXEL for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) { - *ptr = zis->READ_PIXEL(); + *ptr = READ_PIXEL(zis); } #else zis->readBytes(buf, t.area() * (BPP / 8)); @@ -130,7 +124,7 @@ void ZRLE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* ptr = buf; PIXEL_T* end = ptr + t.area(); while (ptr < end) { - PIXEL_T pix = zis->READ_PIXEL(); + PIXEL_T pix = READ_PIXEL(zis); int len = 1; int b; do { @@ -179,7 +173,7 @@ void ZRLE_DECODE (const Rect& r, rdr::InStream* is, //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n", //t.width(),t.height(),t.tl.x,t.tl.y); - IMAGE_RECT(t,buf); + handler->imageRect(t, buf); } } diff --git a/common/rfb/zrleEncode.h b/common/rfb/zrleEncode.h index 0c622b88..8767d541 100644 --- a/common/rfb/zrleEncode.h +++ b/common/rfb/zrleEncode.h @@ -19,10 +19,8 @@ // // zrleEncode.h - zrle encoding function. // -// This file is #included after having set the following macros: +// This file is #included after having set the following macro: // BPP - 8, 16 or 32 -// EXTRA_ARGS - optional extra arguments -// GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer // // Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel // bigger than the largest tile of pixel data, since the ZRLE encoding @@ -31,6 +29,7 @@ #include <rdr/OutStream.h> #include <rdr/ZlibOutStream.h> +#include <rfb/Palette.h> #include <assert.h> namespace rfb { @@ -44,13 +43,13 @@ namespace rfb { #ifdef CPIXEL #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,CPIXEL) +#define WRITE_PIXEL(os, u) CONCAT2E(writeOpaque,CPIXEL)(os, u) #define ZRLE_ENCODE CONCAT2E(zrleEncode,CPIXEL) #define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,CPIXEL) #define BPPOUT 24 #else #define PIXEL_T rdr::CONCAT2E(U,BPP) -#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP) +#define WRITE_PIXEL(os, u) os->CONCAT2E(writeOpaque,BPP)(u) #define ZRLE_ENCODE CONCAT2E(zrleEncode,BPP) #define ZRLE_ENCODE_TILE CONCAT2E(zrleEncodeTile,BPP) #define BPPOUT BPP @@ -61,65 +60,13 @@ namespace rfb { static const int bitsPerPackedPixel[] = { 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; - -// The PaletteHelper class helps us build up the palette from pixel data by -// storing a reverse index using a simple hash-table - -class PaletteHelper { -public: - enum { MAX_SIZE = 127 }; - - PaletteHelper() - { - memset(index, 255, sizeof(index)); - size = 0; - } - - inline int hash(rdr::U32 pix) - { - return (pix ^ (pix >> 17)) & 4095; - } - - inline void insert(rdr::U32 pix) - { - if (size < MAX_SIZE) { - int i = hash(pix); - while (index[i] != 255 && key[i] != pix) - i++; - if (index[i] != 255) return; - - index[i] = size; - key[i] = pix; - palette[size] = pix; - } - size++; - } - - inline int lookup(rdr::U32 pix) - { - assert(size <= MAX_SIZE); - int i = hash(pix); - while (index[i] != 255 && key[i] != pix) - i++; - if (index[i] != 255) return index[i]; - return -1; - } - - rdr::U32 palette[MAX_SIZE]; - rdr::U8 index[4096+MAX_SIZE]; - rdr::U32 key[4096+MAX_SIZE]; - int size; -}; #endif void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os); -bool ZRLE_ENCODE (const Rect& r, rdr::OutStream* os, - rdr::ZlibOutStream* zos, void* buf, Rect* actual -#ifdef EXTRA_ARGS - , EXTRA_ARGS -#endif - ) +void ZRLE_ENCODE (const Rect& r, rdr::OutStream* os, + rdr::ZlibOutStream* zos, void* buf, + TransImageGetter *ig) { zos->setUnderlying(os); // RLE overhead is at worst 1 byte per 64x64 (4Kpixel) block @@ -132,28 +79,17 @@ bool ZRLE_ENCODE (const Rect& r, rdr::OutStream* os, t.br.y = __rfbmin(r.br.y, t.tl.y + 64); - // enough for width 16384 32-bit pixels - if (os->length() + worstCaseLine > 4097 * 1024) { - if (t.tl.y == r.tl.y) - throw Exception("ZRLE: not enough space for first line?"); - actual->tl = r.tl; - actual->br.x = r.br.x; - actual->br.y = t.tl.y; - return false; - } - for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) { t.br.x = __rfbmin(r.br.x, t.tl.x + 64); - GET_IMAGE_INTO_BUF(t,buf); + ig->getImage(buf, t); ZRLE_ENCODE_TILE((PIXEL_T*)buf, t.width(), t.height(), zos); } zos->flush(); } - return true; } @@ -161,7 +97,7 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) { // First find the palette and the number of runs - PaletteHelper ph; + Palette palette; int runs = 0; int singlePixels = 0; @@ -178,7 +114,7 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) while (*++ptr == pix) ; runs++; } - ph.insert(pix); + palette.insert(pix, 1); } //fprintf(stderr,"runs %d, single pixels %d, paletteSize %d\n", @@ -186,9 +122,9 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) // Solid tile is a special case - if (ph.size == 1) { + if (palette.size() == 1) { os->writeU8(1); - os->WRITE_PIXEL(ph.palette[0]); + WRITE_PIXEL(os, palette.getColour(0)); return; } @@ -209,8 +145,8 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) estimatedBytes = plainRleBytes; } - if (ph.size < 128) { - int paletteRleBytes = (BPPOUT/8) * ph.size + 2 * runs + singlePixels; + if (palette.size() < 128) { + int paletteRleBytes = (BPPOUT/8) * palette.size() + 2 * runs + singlePixels; if (paletteRleBytes < estimatedBytes) { useRle = true; @@ -218,9 +154,9 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) estimatedBytes = paletteRleBytes; } - if (ph.size < 17) { - int packedBytes = ((BPPOUT/8) * ph.size + - w * h * bitsPerPackedPixel[ph.size-1] / 8); + if (palette.size() < 17) { + int packedBytes = ((BPPOUT/8) * palette.size() + + w * h * bitsPerPackedPixel[palette.size()-1] / 8); if (packedBytes < estimatedBytes) { useRle = false; @@ -230,12 +166,12 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) } } - if (!usePalette) ph.size = 0; + if (!usePalette) palette.clear(); - os->writeU8((useRle ? 128 : 0) | ph.size); + os->writeU8((useRle ? 128 : 0) | palette.size()); - for (int i = 0; i < ph.size; i++) { - os->WRITE_PIXEL(ph.palette[i]); + for (int i = 0; i < palette.size(); i++) { + WRITE_PIXEL(os, palette.getColour(i)); } if (useRle) { @@ -251,17 +187,17 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) ptr++; int len = ptr - runStart; if (len <= 2 && usePalette) { - int index = ph.lookup(pix); + int index = palette.lookup(pix); if (len == 2) os->writeU8(index); os->writeU8(index); continue; } if (usePalette) { - int index = ph.lookup(pix); + int index = palette.lookup(pix); os->writeU8(index | 128); } else { - os->WRITE_PIXEL(pix); + WRITE_PIXEL(os, pix); } len -= 1; while (len >= 255) { @@ -279,9 +215,9 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) // packed pixels - assert (ph.size < 17); + assert (palette.size() < 17); - int bppp = bitsPerPackedPixel[ph.size-1]; + int bppp = bitsPerPackedPixel[palette.size()-1]; PIXEL_T* ptr = data; @@ -293,7 +229,7 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) while (ptr < eol) { PIXEL_T pix = *ptr++; - rdr::U8 index = ph.lookup(pix); + rdr::U8 index = palette.lookup(pix); byte = (byte << bppp) | index; nbits += bppp; if (nbits >= 8) { @@ -312,7 +248,7 @@ void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, rdr::OutStream* os) #ifdef CPIXEL for (PIXEL_T* ptr = data; ptr < data+w*h; ptr++) { - os->WRITE_PIXEL(*ptr); + WRITE_PIXEL(os, *ptr); } #else os->writeBytes(data, w*h*(BPP/8)); diff --git a/tests/pixelconv.cxx b/tests/pixelconv.cxx index ef9d3aac..1d19b88e 100644 --- a/tests/pixelconv.cxx +++ b/tests/pixelconv.cxx @@ -101,7 +101,7 @@ static void doTests(rfb::PixelFormat &dstpf, rfb::PixelFormat &srcpf) if (srcpf.isLittleEndian()) { delete pt; pt = new rfb::PixelTransformer; - pt->init(srcpf, NULL, dstpf); + pt->init(srcpf, dstpf); } printf("%s,%s", srcb, dstb); diff --git a/unix/x0vncserver/XPixelBuffer.cxx b/unix/x0vncserver/XPixelBuffer.cxx index aa52620a..f4641825 100644 --- a/unix/x0vncserver/XPixelBuffer.cxx +++ b/unix/x0vncserver/XPixelBuffer.cxx @@ -29,14 +29,13 @@ using namespace rfb; XPixelBuffer::XPixelBuffer(Display *dpy, ImageFactory &factory, - const Rect &rect, ColourMap* cm) + const Rect &rect) : FullFramePixelBuffer(), m_poller(0), m_dpy(dpy), m_image(factory.newImage(dpy, rect.width(), rect.height())), m_offsetLeft(rect.tl.x), - m_offsetTop(rect.tl.y), - m_stride(0) + m_offsetTop(rect.tl.y) { // Fill in the PixelFormat structure of the parent class. format = PixelFormat(m_image->xim->bits_per_pixel, @@ -54,11 +53,10 @@ XPixelBuffer::XPixelBuffer(Display *dpy, ImageFactory &factory, width_ = rect.width(); height_ = rect.height(); data = (rdr::U8 *)m_image->xim->data; - colourmap = cm; // Calculate the distance in pixels between two subsequent scan // lines of the framebuffer. This may differ from image width. - m_stride = m_image->xim->bytes_per_line * 8 / m_image->xim->bits_per_pixel; + stride = m_image->xim->bytes_per_line * 8 / m_image->xim->bits_per_pixel; // Get initial screen image from the X display. m_image->get(DefaultRootWindow(m_dpy), m_offsetLeft, m_offsetTop); diff --git a/unix/x0vncserver/XPixelBuffer.h b/unix/x0vncserver/XPixelBuffer.h index 29ae94a8..da031615 100644 --- a/unix/x0vncserver/XPixelBuffer.h +++ b/unix/x0vncserver/XPixelBuffer.h @@ -37,8 +37,7 @@ using namespace rfb; class XPixelBuffer : public FullFramePixelBuffer { public: - XPixelBuffer(Display *dpy, ImageFactory &factory, - const Rect &rect, ColourMap* cm); + XPixelBuffer(Display *dpy, ImageFactory &factory, const Rect &rect); virtual ~XPixelBuffer(); // Provide access to the underlying Image object. @@ -47,9 +46,6 @@ public: // Detect changed pixels, notify the server. inline void poll(VNCServer *server) { m_poller->poll(server); } - // Override PixelBuffer::getStride(). - virtual int getStride() const { return m_stride; } - // Override PixelBuffer::grabRegion(). virtual void grabRegion(const rfb::Region& region); @@ -61,9 +57,6 @@ protected: int m_offsetLeft; int m_offsetTop; - // The number of pixels in a row, with padding included. - int m_stride; - // Copy pixels from the screen to the pixel buffer, // for the specified rectangular area of the buffer. inline void grabRect(const Rect &r) { diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx index 165441fe..ee39fae1 100644 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@ -135,7 +135,7 @@ private: }; -class XDesktop : public SDesktop, public ColourMap, public TXGlobalEventHandler +class XDesktop : public SDesktop, public TXGlobalEventHandler { public: XDesktop(Display* dpy_, Geometry *geometry_) @@ -199,7 +199,7 @@ public: ImageFactory factory((bool)useShm, (bool)useOverlay); // Create pixel buffer and provide it to the server object. - pb = new XPixelBuffer(dpy, factory, geometry->getRect(), this); + pb = new XPixelBuffer(dpy, factory, geometry->getRect()); vlog.info("Allocated %s", pb->getImage()->classDesc()); server = (VNCServerST *)vs; @@ -269,20 +269,6 @@ public: return Point(pb->width(), pb->height()); } - // -=- ColourMap callbacks - virtual void lookup(int index, int* r, int* g, int* b) { - XColor xc; - xc.pixel = index; - if (index < DisplayCells(dpy,DefaultScreen(dpy))) { - XQueryColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), &xc); - } else { - xc.red = xc.green = xc.blue = 0; - } - *r = xc.red; - *g = xc.green; - *b = xc.blue; - } - // -=- TXGlobalEventHandler interface virtual bool handleGlobalEvent(XEvent* ev) { diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 8f426cce..e5cc3dc1 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -51,7 +51,6 @@ extern "C" { extern char *display; -#include "colormapst.h" #ifdef RANDR #include "randrstr.h" #endif @@ -143,14 +142,11 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, : pScreen(pScreen_), server(0), httpServer(0), listener(listener_), httpListener(httpListener_), - cmap(0), deferredUpdateTimerSet(false), + deferredUpdateTimerSet(false), grabbing(false), ignoreHooks_(false), directFbptr(true), queryConnectId(0) { format = pf; - colourmap = this; - - serverReset(pScreen); server = new VNCServerST(name, this); setFramebuffer(pScreen->width, pScreen->height, fbptr, stride); @@ -168,24 +164,6 @@ XserverDesktop::~XserverDesktop() delete server; } -void XserverDesktop::serverReset(ScreenPtr pScreen_) -{ - pScreen = pScreen_; - int i; - pointer retval; - -#if XORG >= 17 -#define dixLookupResource dixLookupResourceByType -#endif - i = dixLookupResource(&retval, pScreen->defColormap, RT_COLORMAP, NullClient, - DixReadAccess); - - /* Handle suspicious conditions */ - assert(i == Success); - - cmap = (ColormapPtr) retval; -} - void XserverDesktop::blockUpdates() { server->blockUpdates(); @@ -196,7 +174,7 @@ void XserverDesktop::unblockUpdates() server->unblockUpdates(); } -void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride) +void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride_) { ScreenSet layout; @@ -210,12 +188,12 @@ void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride) if (!fbptr) { fbptr = new rdr::U8[w * h * (format.bpp/8)]; - stride = w; + stride_ = w; directFbptr = false; } data = (rdr::U8*)fbptr; - stride_ = stride; + stride = stride_; layout = computeScreenLayout(); @@ -376,44 +354,6 @@ XserverDesktop::queryConnection(network::Socket* sock, return rfb::VNCServerST::PENDING; } - -void XserverDesktop::setColormap(ColormapPtr cmap_) -{ - if (cmap != cmap_) { - cmap = cmap_; - setColourMapEntries(0, 0); - } -} - -void XserverDesktop::setColourMapEntries(ColormapPtr pColormap, int ndef, - xColorItem* pdef) -{ - if (cmap != pColormap || ndef <= 0) return; - - unsigned int first = pdef[0].pixel; - unsigned int n = 1; - - for (int i = 1; i < ndef; i++) { - if (first + n == pdef[i].pixel) { - n++; - } else { - setColourMapEntries(first, n); - first = pdef[i].pixel; - n = 1; - } - } - setColourMapEntries(first, n); -} - -void XserverDesktop::setColourMapEntries(int firstColour, int nColours) -{ - try { - server->setColourMapEntries(firstColour, nColours); - } catch (rdr::Exception& e) { - vlog.error("XserverDesktop::setColourMapEntries: %s",e.str()); - } -} - void XserverDesktop::bell() { server->bell(); @@ -466,7 +406,7 @@ void XserverDesktop::setCursor(CursorPtr cursor) rgb[1] = (*in >> 8) & 0xff; rgb[2] = (*in >> 0) & 0xff; - getPF().bufferFromRGB(out, rgb, 1, this); + getPF().bufferFromRGB(out, rgb, 1); if (((*in >> 24) & 0xff) > 127) cursorMask[y * rfbMaskBytesPerRow + x/8] |= 0x80>>(x%8); @@ -477,42 +417,42 @@ void XserverDesktop::setCursor(CursorPtr cursor) } } else { #endif - xColorItem fg, bg; - fg.red = cursor->foreRed; - fg.green = cursor->foreGreen; - fg.blue = cursor->foreBlue; - FakeAllocColor(cmap, &fg); - bg.red = cursor->backRed; - bg.green = cursor->backGreen; - bg.blue = cursor->backBlue; - FakeAllocColor(cmap, &bg); - FakeFreeColor(cmap, fg.pixel); - FakeFreeColor(cmap, bg.pixel); + rdr::U8 rgb[3]; + rdr::U8 fg[4], bg[4]; + + rdr::U8* buffer; + + rgb[0] = cursor->foreRed; + rgb[1] = cursor->foreGreen; + rgb[2] = cursor->foreBlue; + getPF().bufferFromRGB(fg, rgb, 1); + + rgb[0] = cursor->backRed; + rgb[1] = cursor->backGreen; + rgb[2] = cursor->backBlue; + getPF().bufferFromRGB(bg, rgb, 1); int xMaskBytesPerRow = BitmapBytePad(w); + buffer = cursorData; + for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { + rdr::U8 *pixel; int byte = y * xMaskBytesPerRow + x / 8; #if (BITMAP_BIT_ORDER == MSBFirst) int bit = 7 - x % 8; #else int bit = x % 8; #endif - switch (getPF().bpp) { - case 8: - ((rdr::U8*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - case 16: - ((rdr::U16*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - case 32: - ((rdr::U32*)cursorData)[y * w + x] - = (cursor->bits->source[byte] & (1 << bit)) ? fg.pixel : bg.pixel; - break; - } + + if (cursor->bits->source[byte] & (1 << bit)) + pixel = fg; + else + pixel = bg; + + memcpy(buffer, pixel, getPF().bpp/8); + buffer += getPF().bpp/8; } } @@ -1105,33 +1045,6 @@ void XserverDesktop::grabRegion(const rfb::Region& region) grabbing = false; } -int XserverDesktop::getStride() const -{ - return stride_; -} - -void XserverDesktop::lookup(int index, int* r, int* g, int* b) -{ - if ((cmap->c_class | DynamicClass) == DirectColor) { - VisualPtr v = cmap->pVisual; - *r = cmap->red [(index & v->redMask ) >> v->offsetRed ].co.local.red; - *g = cmap->green[(index & v->greenMask) >> v->offsetGreen].co.local.green; - *b = cmap->blue [(index & v->blueMask ) >> v->offsetBlue ].co.local.blue; - } else { - EntryPtr pent; - pent = (EntryPtr)&cmap->red[index]; - if (pent->fShared) { - *r = pent->co.shco.red->color; - *g = pent->co.shco.green->color; - *b = pent->co.shco.blue->color; - } else { - *r = pent->co.local.red; - *g = pent->co.local.green; - *b = pent->co.local.blue; - } - } -} - void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) { if (down) diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 20c89dc5..5b4c2300 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -54,7 +54,7 @@ namespace rfb { namespace network { class TcpListener; class Socket; } class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, - public rfb::ColourMap, public rdr::Substitutor, + public rdr::Substitutor, public rfb::VNCServerST::QueryConnectionHandler { public: @@ -65,13 +65,10 @@ public: virtual ~XserverDesktop(); // methods called from X server code - void serverReset(ScreenPtr pScreen); void blockUpdates(); void unblockUpdates(); void setFramebuffer(int w, int h, void* fbptr, int stride); void refreshScreenLayout(); - void setColormap(ColormapPtr cmap); - void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef); void bell(); void serverCutText(const char* str, int len); void setDesktopName(const char* name); @@ -112,10 +109,6 @@ public: // rfb::PixelBuffer callbacks virtual void grabRegion(const rfb::Region& r); - virtual int getStride() const; - - // rfb::ColourMap callbacks - virtual void lookup(int index, int* r, int* g, int* b); // rdr::Substitutor callback virtual char* substitute(const char* varName); @@ -126,7 +119,6 @@ public: char** reason); private: - void setColourMapEntries(int firstColour, int nColours); rfb::ScreenSet computeScreenLayout(); #ifdef RANDR RRModePtr findRandRMode(RROutputPtr output, int width, int height); @@ -137,8 +129,6 @@ private: rfb::HTTPServer* httpServer; network::TcpListener* listener; network::TcpListener* httpListener; - ColormapPtr cmap; - int stride_; bool deferredUpdateTimerSet; bool grabbing; bool ignoreHooks_; diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc index a9fd0e9f..732fa69b 100644 --- a/unix/xserver/hw/vnc/vncExtInit.cc +++ b/unix/xserver/hw/vnc/vncExtInit.cc @@ -168,8 +168,10 @@ static PixelFormat vncGetPixelFormat(ScreenPtr pScreen) trueColour = (vis->c_class == TrueColor); - if (!trueColour && bpp != 8) - throw rfb::Exception("X server uses unsupported visual"); + if (!trueColour) { + fprintf(stderr,"pseudocolour not supported"); + abort(); + } redShift = ffs(vis->redMask) - 1; greenShift = ffs(vis->greenMask) - 1; @@ -266,9 +268,6 @@ void vncExtensionInit() desktop[scr]->addClient(sock, false); vlog.info("added inetd sock"); } - - } else { - desktop[scr]->serverReset(screenInfo.screens[scr]); } vncHooksInit(screenInfo.screens[scr], desktop[scr]); diff --git a/unix/xserver/hw/vnc/vncHooks.cc b/unix/xserver/hw/vnc/vncHooks.cc index 6756da7a..94693872 100644 --- a/unix/xserver/hw/vnc/vncHooks.cc +++ b/unix/xserver/hw/vnc/vncHooks.cc @@ -75,8 +75,6 @@ typedef struct { #if XORG < 110 RestoreAreasProcPtr RestoreAreas; #endif - InstallColormapProcPtr InstallColormap; - StoreColorsProcPtr StoreColors; DisplayCursorProcPtr DisplayCursor; ScreenBlockHandlerProcPtr BlockHandler; #ifdef RENDER @@ -132,9 +130,6 @@ static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w, #if XORG < 110 static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed); #endif -static void vncHooksInstallColormap(ColormapPtr pColormap); -static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, - xColorItem* pdef); static Bool vncHooksDisplayCursor( #if XORG >= 16 DeviceIntPtr pDev, @@ -289,8 +284,6 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) #if XORG < 110 vncHooksScreen->RestoreAreas = pScreen->RestoreAreas; #endif - vncHooksScreen->InstallColormap = pScreen->InstallColormap; - vncHooksScreen->StoreColors = pScreen->StoreColors; vncHooksScreen->DisplayCursor = pScreen->DisplayCursor; vncHooksScreen->BlockHandler = pScreen->BlockHandler; #ifdef RENDER @@ -318,8 +311,6 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop) #if XORG < 110 pScreen->RestoreAreas = vncHooksRestoreAreas; #endif - pScreen->InstallColormap = vncHooksInstallColormap; - pScreen->StoreColors = vncHooksStoreColors; pScreen->DisplayCursor = vncHooksDisplayCursor; pScreen->BlockHandler = vncHooksBlockHandler; #ifdef RENDER @@ -381,8 +372,6 @@ static Bool vncHooksCloseScreen(ScreenPtr pScreen_) #if XORG < 110 pScreen->RestoreAreas = vncHooksScreen->RestoreAreas; #endif - pScreen->InstallColormap = vncHooksScreen->InstallColormap; - pScreen->StoreColors = vncHooksScreen->StoreColors; pScreen->DisplayCursor = vncHooksScreen->DisplayCursor; pScreen->BlockHandler = vncHooksScreen->BlockHandler; #ifdef RENDER @@ -512,33 +501,6 @@ static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion) } #endif -// InstallColormap - get the new colormap - -static void vncHooksInstallColormap(ColormapPtr pColormap) -{ - SCREEN_UNWRAP(pColormap->pScreen, InstallColormap); - - (*pScreen->InstallColormap) (pColormap); - - vncHooksScreen->desktop->setColormap(pColormap); - - SCREEN_REWRAP(InstallColormap); -} - -// StoreColors - get the colormap changes - -static void vncHooksStoreColors(ColormapPtr pColormap, int ndef, - xColorItem* pdef) -{ - SCREEN_UNWRAP(pColormap->pScreen, StoreColors); - - (*pScreen->StoreColors) (pColormap, ndef, pdef); - - vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef); - - SCREEN_REWRAP(StoreColors); -} - // DisplayCursor - get the cursor shape static Bool vncHooksDisplayCursor( diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 789cf09e..db1a08a5 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2009-2014 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 @@ -29,6 +29,7 @@ #include <rfb/CMsgWriter.h> #include <rfb/encodings.h> +#include <rfb/Decoder.h> #include <rfb/Hostname.h> #include <rfb/LogWriter.h> #include <rfb/util.h> @@ -65,8 +66,9 @@ static const PixelFormat verylowColourPF(8, 3,false, true, // 64 colours (2 bits per component) static const PixelFormat lowColourPF(8, 6, false, true, 3, 3, 3, 4, 2, 0); -// 256 colours (palette) -static const PixelFormat mediumColourPF(8, 8, false, false); +// 256 colours (2-3 bits per component) +static const PixelFormat mediumColourPF(8, 8, false, true, + 7, 7, 3, 5, 2, 0); CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) : serverHost(0), serverPort(0), desktop(NULL), @@ -79,6 +81,8 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) setShared(::shared); sock = socket; + memset(decoders, 0, sizeof(decoders)); + int encNum = encodingNum(preferredEncoding); if (encNum != -1) currentEncoding = encNum; @@ -130,6 +134,9 @@ CConn::~CConn() { OptionsDialog::removeCallback(handleOptions); + for (int i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++) + delete decoders[i]; + if (desktop) delete desktop; @@ -342,7 +349,7 @@ void CConn::framebufferUpdateEnd() void CConn::setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs) { - desktop->setColourMapEntries(firstColour, nColours, rgbs); + vlog.error("Invalid SetColourMapEntries from server!"); } void CConn::bell() @@ -379,19 +386,27 @@ void CConn::serverCutText(const char* str, rdr::U32 len) delete [] buffer; } -// We start timing on beginRect and stop timing on endRect, to -// avoid skewing the bandwidth estimation as a result of the server -// being slow or the network having high latency -void CConn::beginRect(const Rect& r, int encoding) +void CConn::dataRect(const Rect& r, int encoding) { sock->inStream().startTiming(); - if (encoding != encodingCopyRect) { + + if (encoding != encodingCopyRect) lastServerEncoding = encoding; + + if (!Decoder::supported(encoding)) { + fprintf(stderr, "Unknown rect encoding %d\n", encoding); + throw Exception("Unknown rect encoding"); } -} -void CConn::endRect(const Rect& r, int encoding) -{ + if (!decoders[encoding]) { + decoders[encoding] = Decoder::createDecoder(encoding, this); + if (!decoders[encoding]) { + fprintf(stderr, "Unknown rect encoding %d\n", encoding); + throw Exception("Unknown rect encoding"); + } + } + decoders[encoding]->readRect(r, this); + sock->inStream().stopTiming(); } diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index 286a09ed..f7f560bc 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB + * Copyright 2009-2014 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 @@ -23,8 +23,11 @@ #include <FL/Fl.H> #include <rfb/CConnection.h> +#include <rfb/encodings.h> #include <network/Socket.h> +namespace rfb { class Decoder; } + class DesktopWindow; class CConn : public rfb::CConnection, @@ -62,8 +65,7 @@ public: void framebufferUpdateStart(); void framebufferUpdateEnd(); - void beginRect(const rfb::Rect& r, int encoding); - void endRect(const rfb::Rect& r, int encoding); + void dataRect(const rfb::Rect& r, int encoding); void fillRect(const rfb::Rect& r, rfb::Pixel p); void imageRect(const rfb::Rect& r, void* p); @@ -102,6 +104,8 @@ private: bool pendingPFChange; rfb::PixelFormat pendingPF; + rfb::Decoder *decoders[rfb::encodingMax+1]; + int currentEncoding, lastServerEncoding; bool formatChange; diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt index c1facc67..9b815a39 100644 --- a/vncviewer/CMakeLists.txt +++ b/vncviewer/CMakeLists.txt @@ -7,9 +7,11 @@ set(VNCVIEWER_SOURCES menukey.cxx CConn.cxx DesktopWindow.cxx + FLTKPixelBuffer.cxx UserDialog.cxx ServerDialog.cxx OptionsDialog.cxx + PlatformPixelBuffer.cxx Viewport.cxx parameters.cxx keysym2ucs.c diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 2a2f8734..3e9b57e6 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -216,12 +216,6 @@ void DesktopWindow::setName(const char *name) } -void DesktopWindow::setColourMapEntries(int firstColour, int nColours, - rdr::U16* rgbs) -{ - viewport->setColourMapEntries(firstColour, nColours, rgbs); -} - void DesktopWindow::fillRect(const rfb::Rect& r, rfb::Pixel pix) { viewport->fillRect(r, pix); } diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index 06f25f55..08a66522 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -50,8 +50,6 @@ public: // Methods forwarded from CConn void setName(const char *name); - void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs); - void fillRect(const rfb::Rect& r, rfb::Pixel pix); void imageRect(const rfb::Rect& r, void* pixels); void copyRect(const rfb::Rect& r, int srcX, int srcY); diff --git a/vncviewer/FLTKPixelBuffer.cxx b/vncviewer/FLTKPixelBuffer.cxx new file mode 100644 index 00000000..588e2f83 --- /dev/null +++ b/vncviewer/FLTKPixelBuffer.cxx @@ -0,0 +1,52 @@ +/* Copyright 2011-2014 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <FL/fl_draw.H> + +#include <rfb/Exception.h> + +#include "FLTKPixelBuffer.h" + +FLTKPixelBuffer::FLTKPixelBuffer(int width, int height) : + PlatformPixelBuffer(rfb::PixelFormat(32, 24, false, true, + 255, 255, 255, 0, 8, 16), + width, height, NULL, width) +{ + data = new rdr::U8[width * height * format.bpp/8]; + if (data == NULL) + throw rfb::Exception("Error: Not enough memory for framebuffer"); +} + +FLTKPixelBuffer::~FLTKPixelBuffer() +{ + delete [] data; +} + +void FLTKPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) +{ + int pixel_bytes, stride_bytes; + const uchar *buf_start; + + pixel_bytes = format.bpp/8; + stride_bytes = pixel_bytes * stride; + buf_start = data + + pixel_bytes * src_x + + stride_bytes * src_y; + + fl_draw_image(buf_start, x, y, w, h, pixel_bytes, stride_bytes); +} diff --git a/common/rfb/TrueColourMap.h b/vncviewer/FLTKPixelBuffer.h index d79647e3..148c6264 100644 --- a/common/rfb/TrueColourMap.h +++ b/vncviewer/FLTKPixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. +/* Copyright 2011-2014 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 @@ -15,27 +15,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#ifndef __RFB_TRUECOLOURMAP_H__ -#define __RFB_TRUECOLOURMAP_H__ -#include <rfb/ColourMap.h> +#ifndef __FLTKPIXELBUFFER_H__ +#define __FLTKPIXELBUFFER_H__ -namespace rfb { +#include "PlatformPixelBuffer.h" + +class FLTKPixelBuffer: public PlatformPixelBuffer { +public: + FLTKPixelBuffer(int width, int height); + ~FLTKPixelBuffer(); + + virtual void draw(int src_x, int src_y, int x, int y, int w, int h); +}; - class TrueColourMap : public ColourMap { - public: - TrueColourMap(const PixelFormat& pf_) : pf(pf_) {} - virtual void lookup(int i, int* r, int* g, int* b) - { - rdr::U16 _r, _g, _b; - pf.rgbFromPixel(i, NULL, &_r, &_g, &_b); - *r = _r; - *g = _g; - *b = _b; - } - private: - PixelFormat pf; - }; -} #endif diff --git a/vncviewer/OSXPixelBuffer.cxx b/vncviewer/OSXPixelBuffer.cxx index 0e03fc98..d196497f 100644 --- a/vncviewer/OSXPixelBuffer.cxx +++ b/vncviewer/OSXPixelBuffer.cxx @@ -1,4 +1,4 @@ -/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB +/* Copyright 2011-2014 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 @@ -34,16 +34,20 @@ using namespace rfb; -static rfb::LogWriter vlog("PlatformPixelBuffer"); +static rfb::LogWriter vlog("OSXPixelBuffer"); -PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : - ManagedPixelBuffer(rfb::PixelFormat(32, 24, false, true, - 255, 255, 255, 16, 8, 0), - width, height), +OSXPixelBuffer::OSXPixelBuffer(int width, int height) : + PlatformPixelBuffer(rfb::PixelFormat(32, 24, false, true, + 255, 255, 255, 16, 8, 0), + width, height, NULL, width), bitmap(NULL) { CGColorSpaceRef lut; + data = new rdr::U8[width * height * format.bpp/8]; + if (data == NULL) + throw rfb::Exception("Error: Not enough memory for framebuffer"); + lut = CGColorSpaceCreateDeviceRGB(); assert(lut); @@ -55,13 +59,14 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : } -PlatformPixelBuffer::~PlatformPixelBuffer() +OSXPixelBuffer::~OSXPixelBuffer() { CFRelease((CGContextRef)bitmap); + delete [] data; } -void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) +void OSXPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) { CGRect rect; CGContextRef gc; diff --git a/vncviewer/OSXPixelBuffer.h b/vncviewer/OSXPixelBuffer.h index e59015e5..8ae01848 100644 --- a/vncviewer/OSXPixelBuffer.h +++ b/vncviewer/OSXPixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB +/* Copyright 2011-2014 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 @@ -19,14 +19,14 @@ #ifndef __OSXPIXELBUFFER_H__ #define __OSXPIXELBUFFER_H__ -#include <rfb/PixelBuffer.h> +#include "PlatformPixelBuffer.h" -class PlatformPixelBuffer: public rfb::ManagedPixelBuffer { +class OSXPixelBuffer: public PlatformPixelBuffer { public: - PlatformPixelBuffer(int width, int height); - ~PlatformPixelBuffer(); + OSXPixelBuffer(int width, int height); + ~OSXPixelBuffer(); - void draw(int src_x, int src_y, int x, int y, int w, int h); + virtual void draw(int src_x, int src_y, int x, int y, int w, int h); protected: // This is really a CGContextRef, but Apple headers conflict with FLTK diff --git a/common/rfb/CMsgReaderV3.h b/vncviewer/PlatformPixelBuffer.cxx index bff70ef4..ced04467 100644 --- a/common/rfb/CMsgReaderV3.h +++ b/vncviewer/PlatformPixelBuffer.cxx @@ -1,5 +1,4 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2009-2011 Pierre Ossman for Cendio AB +/* Copyright 2011-2014 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 @@ -16,25 +15,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ -#ifndef __RFB_CMSGREADERV3_H__ -#define __RFB_CMSGREADERV3_H__ -#include <rfb/CMsgReader.h> +#include "PlatformPixelBuffer.h" -namespace rfb { - class CMsgReaderV3 : public CMsgReader { - public: - CMsgReaderV3(CMsgHandler* handler, rdr::InStream* is); - virtual ~CMsgReaderV3(); - virtual void readServerInit(); - virtual void readMsg(); - private: - virtual void readFramebufferUpdate(); - virtual void readSetDesktopName(int x, int y, int w, int h); - virtual void readExtendedDesktopSize(int x, int y, int w, int h); - virtual void readFence(); - virtual void readEndOfContinuousUpdates(); - int nUpdateRectsLeft; - }; +PlatformPixelBuffer::PlatformPixelBuffer(const rfb::PixelFormat& pf, + int width, int height, + rdr::U8* data, int stride) : + FullFramePixelBuffer(pf, width, height, data, stride) +{ } -#endif diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h index f634ccd4..03842ac8 100644 --- a/vncviewer/PlatformPixelBuffer.h +++ b/vncviewer/PlatformPixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB +/* Copyright 2011-2014 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 @@ -21,31 +21,13 @@ #include <rfb/PixelBuffer.h> -#include <FL/fl_draw.H> - -class PlatformPixelBuffer: public rfb::ManagedPixelBuffer { +class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { public: - PlatformPixelBuffer(int width, int height) : - rfb::ManagedPixelBuffer(rfb::PixelFormat(32, 24, false, true, - 255, 255, 255, 0, 8, 16), - width, height) - {}; - - inline void draw(int src_x, int src_y, int x, int y, int w, int h); -}; + PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height, + rdr::U8* data, int stride); -inline void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) -{ - int pixel_bytes, stride_bytes; - const uchar *buf_start; + virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0; - pixel_bytes = getPF().bpp/8; - stride_bytes = pixel_bytes * getStride(); - buf_start = data + - pixel_bytes * src_x + - stride_bytes * src_y; - - fl_draw_image(buf_start, x, y, w, h, pixel_bytes, stride_bytes); -} +}; #endif diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 0ac76024..d1d51622 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB + * Copyright 2011-2014 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 @@ -51,6 +51,9 @@ #include "menukey.h" #include "vncviewer.h" +#include "PlatformPixelBuffer.h" +#include "FLTKPixelBuffer.h" + #if defined(WIN32) #include "Win32PixelBuffer.h" #elif defined(__APPLE__) @@ -59,11 +62,6 @@ #include "X11PixelBuffer.h" #endif -// We also have a generic version of the above, using pure FLTK: -// -// #include "PlatformPixelBuffer.h" -// - #include <FL/fl_draw.H> #include <FL/fl_ask.H> @@ -87,7 +85,7 @@ enum { ID_EXIT, ID_FULLSCREEN, ID_RESIZE, Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL), - colourMapChange(false), lastPointerPos(0, 0), lastButtonMask(0), + lastPointerPos(0, 0), lastButtonMask(0), cursor(NULL), menuCtrlKey(false), menuAltKey(false) { // FLTK STR #2599 must be fixed for proper dead keys support @@ -100,7 +98,7 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) Fl::add_clipboard_notify(handleClipboardChange, this); #endif - frameBuffer = new PlatformPixelBuffer(w, h); + frameBuffer = createFramebuffer(w, h); assert(frameBuffer); setServerPF(serverPF); @@ -183,11 +181,11 @@ void Viewport::setServerPF(const rfb::PixelFormat& pf) PixelFormat fake_pf(pf.bpp, pf.depth, nativeBigEndian, pf.trueColour, pf.redMax, pf.greenMax, pf.blueMax, pf.redShift, pf.greenShift, pf.blueShift); - pixelTrans->init(fake_pf, &colourMap, getPreferredPF()); + pixelTrans->init(fake_pf, getPreferredPF()); return; } - pixelTrans->init(pf, &colourMap, getPreferredPF()); + pixelTrans->init(pf, getPreferredPF()); } @@ -197,21 +195,6 @@ const rfb::PixelFormat &Viewport::getPreferredPF() } -// setColourMapEntries() changes some of the entries in the colourmap. -// We don't actually act on these changes until we need to. This is -// because recalculating the internal translation table can be expensive. -// This also solves the issue of silly servers sending colour maps in -// multiple pieces. -void Viewport::setColourMapEntries(int firstColour, int nColours, - rdr::U16* rgbs) -{ - for (int i = 0; i < nColours; i++) - colourMap.set(firstColour+i, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]); - - colourMapChange = true; -} - - // Copy the areas of the framebuffer that have been changed (damaged) // to the displayed window. @@ -230,8 +213,6 @@ void Viewport::updateWindow() void Viewport::fillRect(const rfb::Rect& r, rfb::Pixel pix) { if (pixelTrans) { rfb::Pixel pix2; - if (colourMapChange) - commitColourMap(); pixelTrans->translatePixels(&pix, &pix2, 1); pix = pix2; } @@ -242,12 +223,12 @@ void Viewport::fillRect(const rfb::Rect& r, rfb::Pixel pix) { void Viewport::imageRect(const rfb::Rect& r, void* pixels) { if (pixelTrans) { - if (colourMapChange) - commitColourMap(); + rdr::U8* buffer; + int stride; + buffer = frameBuffer->getBufferRW(r, &stride); pixelTrans->translateRect(pixels, r.width(), rfb::Rect(0, 0, r.width(), r.height()), - frameBuffer->data, frameBuffer->getStride(), - r.tl); + buffer, stride, rfb::Point(0, 0)); } else { frameBuffer->imageRect(r, pixels); } @@ -327,7 +308,7 @@ void Viewport::setCursor(int width, int height, const Point& hotspot, m_width = (width+7)/8; for (int y = 0;y < height;y++) { for (int x = 0;x < width;x++) { - pf->rgbFromBuffer(o, i, 1, &colourMap); + pf->rgbFromBuffer(o, i, 1); if (m[(m_width*y)+(x/8)] & 0x80>>(x%8)) o[3] = 255; @@ -369,6 +350,9 @@ void Viewport::resize(int x, int y, int w, int h) PlatformPixelBuffer* newBuffer; rfb::Rect rect; + const rdr::U8* data; + int stride; + // FIXME: Resize should probably be a feature of the pixel buffer itself if ((w == frameBuffer->width()) && (h == frameBuffer->height())) @@ -377,13 +361,14 @@ void Viewport::resize(int x, int y, int w, int h) vlog.debug("Resizing framebuffer from %dx%d to %dx%d", frameBuffer->width(), frameBuffer->height(), w, h); - newBuffer = new PlatformPixelBuffer(w, h); + newBuffer = createFramebuffer(w, h); assert(newBuffer); rect.setXYWH(0, 0, __rfbmin(newBuffer->width(), frameBuffer->width()), __rfbmin(newBuffer->height(), frameBuffer->height())); - newBuffer->imageRect(rect, frameBuffer->data, frameBuffer->getStride()); + data = frameBuffer->getBuffer(frameBuffer->getRect(), &stride); + newBuffer->imageRect(rect, data, stride); // Black out any new areas @@ -519,26 +504,33 @@ int Viewport::handle(int event) } -void Viewport::handleUpdateTimeout(void *data) +PlatformPixelBuffer* Viewport::createFramebuffer(int w, int h) { - Viewport *self = (Viewport *)data; + PlatformPixelBuffer *fb; - assert(self); + try { +#if defined(WIN32) + fb = new Win32PixelBuffer(w, h); +#elif defined(__APPLE__) + fb = new OSXPixelBuffer(w, h); +#else + fb = new X11PixelBuffer(w, h); +#endif + } catch (rdr::Exception& e) { + fb = new FLTKPixelBuffer(w, h); + } - self->updateWindow(); + return fb; } -void Viewport::commitColourMap() +void Viewport::handleUpdateTimeout(void *data) { - if (pixelTrans == NULL) - return; - if (!colourMapChange) - return; + Viewport *self = (Viewport *)data; - colourMapChange = false; + assert(self); - pixelTrans->setColourMapEntries(0, 0); + self->updateWindow(); } diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index e83a14ba..bd17655a 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -26,7 +26,6 @@ #include <rfb/Region.h> #include <rfb/Pixel.h> -#include <rfb/ColourMap.h> class Fl_Menu_Button; class Fl_RGB_Image; @@ -52,8 +51,6 @@ public: // Methods forwarded from CConn - void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs); - void fillRect(const rfb::Rect& r, rfb::Pixel pix); void imageRect(const rfb::Rect& r, void* pixels); void copyRect(const rfb::Rect& r, int srcX, int srcY); @@ -75,9 +72,9 @@ public: private: - static void handleUpdateTimeout(void *data); + PlatformPixelBuffer* createFramebuffer(int w, int h); - void commitColourMap(); + static void handleUpdateTimeout(void *data); static void handleClipboardChange(int source, void *data); @@ -98,11 +95,7 @@ private: CConn* cc; PlatformPixelBuffer* frameBuffer; - rfb::PixelTransformer *pixelTrans; - rfb::SimpleColourMap colourMap; - bool colourMapChange; - rfb::Region damage; rfb::Point lastPointerPos; diff --git a/vncviewer/Win32PixelBuffer.cxx b/vncviewer/Win32PixelBuffer.cxx index 626bb967..9fb04145 100644 --- a/vncviewer/Win32PixelBuffer.cxx +++ b/vncviewer/Win32PixelBuffer.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB + * Copyright 2011-2014 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 @@ -35,12 +35,12 @@ using namespace rfb; -static rfb::LogWriter vlog("PlatformPixelBuffer"); +static rfb::LogWriter vlog("Win32PixelBuffer"); -PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : - FullFramePixelBuffer(rfb::PixelFormat(32, 24, false, true, - 255, 255, 255, 16, 8, 0), - width, height, NULL, NULL), +Win32PixelBuffer::Win32PixelBuffer(int width, int height) : + PlatformPixelBuffer(rfb::PixelFormat(32, 24, false, true, + 255, 255, 255, 16, 8, 0), + width, height, NULL, width), bitmap(NULL) { BITMAPINFOHEADER bih; @@ -64,13 +64,13 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : } -PlatformPixelBuffer::~PlatformPixelBuffer() +Win32PixelBuffer::~Win32PixelBuffer() { DeleteObject(bitmap); } -void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) +void Win32PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) { HDC dc; diff --git a/vncviewer/Win32PixelBuffer.h b/vncviewer/Win32PixelBuffer.h index 7d91e09d..728e5948 100644 --- a/vncviewer/Win32PixelBuffer.h +++ b/vncviewer/Win32PixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB +/* Copyright 2011-2014 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 @@ -21,14 +21,14 @@ #include <windows.h> -#include <rfb/PixelBuffer.h> +#include "PlatformPixelBuffer.h" -class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { +class Win32PixelBuffer: public PlatformPixelBuffer { public: - PlatformPixelBuffer(int width, int height); - ~PlatformPixelBuffer(); + Win32PixelBuffer(int width, int height); + ~Win32PixelBuffer(); - void draw(int src_x, int src_y, int x, int y, int w, int h); + virtual void draw(int src_x, int src_y, int x, int y, int w, int h); protected: HBITMAP bitmap; diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx index 548591e1..c709984b 100644 --- a/vncviewer/X11PixelBuffer.cxx +++ b/vncviewer/X11PixelBuffer.cxx @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB + * Copyright 2011-2014 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 @@ -33,7 +33,7 @@ using namespace rfb; -static rfb::LogWriter vlog("PlatformPixelBuffer"); +static rfb::LogWriter vlog("X11PixelBuffer"); static PixelFormat display_pf() { @@ -93,8 +93,8 @@ static PixelFormat display_pf() redShift, greenShift, blueShift); } -PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : - FullFramePixelBuffer(display_pf(), width, height, NULL, NULL), +X11PixelBuffer::X11PixelBuffer(int width, int height) : + PlatformPixelBuffer(display_pf(), width, height, NULL, 0), shminfo(NULL), xim(NULL) { // Might not be open at this point @@ -110,10 +110,11 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : } data = (rdr::U8*)xim->data; + stride = xim->bytes_per_line / (getPF().bpp/8); } -PlatformPixelBuffer::~PlatformPixelBuffer() +X11PixelBuffer::~X11PixelBuffer() { if (shminfo) { vlog.debug("Freeing shared memory XImage"); @@ -130,7 +131,7 @@ PlatformPixelBuffer::~PlatformPixelBuffer() } -void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) +void X11PixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) { if (shminfo) XShmPutImage(fl_display, fl_window, fl_gc, xim, src_x, src_y, x, y, w, h, False); @@ -139,11 +140,6 @@ void PlatformPixelBuffer::draw(int src_x, int src_y, int x, int y, int w, int h) } -int PlatformPixelBuffer::getStride() const -{ - return xim->bytes_per_line / (getPF().bpp/8); -} - static bool caughtError; static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error) @@ -152,7 +148,7 @@ static int XShmAttachErrorHandler(Display *dpy, XErrorEvent *error) return 0; } -int PlatformPixelBuffer::setupShm() +int X11PixelBuffer::setupShm() { int major, minor; Bool pixmaps; diff --git a/vncviewer/X11PixelBuffer.h b/vncviewer/X11PixelBuffer.h index 0b0cee01..c2ffdc28 100644 --- a/vncviewer/X11PixelBuffer.h +++ b/vncviewer/X11PixelBuffer.h @@ -1,4 +1,4 @@ -/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB +/* Copyright 2011-2014 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 @@ -24,16 +24,14 @@ #include <sys/shm.h> #include <X11/extensions/XShm.h> -#include <rfb/PixelBuffer.h> +#include "PlatformPixelBuffer.h" -class PlatformPixelBuffer: public rfb::FullFramePixelBuffer { +class X11PixelBuffer: public PlatformPixelBuffer { public: - PlatformPixelBuffer(int width, int height); - ~PlatformPixelBuffer(); + X11PixelBuffer(int width, int height); + ~X11PixelBuffer(); - void draw(int src_x, int src_y, int x, int y, int w, int h); - - int getStride() const; + virtual void draw(int src_x, int src_y, int x, int y, int w, int h); protected: int setupShm(); diff --git a/win/rfb_win32/DIBSectionBuffer.cxx b/win/rfb_win32/DIBSectionBuffer.cxx index 0c266b00..e2b0d641 100644 --- a/win/rfb_win32/DIBSectionBuffer.cxx +++ b/win/rfb_win32/DIBSectionBuffer.cxx @@ -31,13 +31,11 @@ static LogWriter vlog("DIBSectionBuffer"); DIBSectionBuffer::DIBSectionBuffer(HWND window_) : bitmap(0), window(window_), device(0) { memset(&format, 0, sizeof(format)); - memset(palette, 0, sizeof(palette)); } DIBSectionBuffer::DIBSectionBuffer(HDC device_) : bitmap(0), window(0), device(device_) { memset(&format, 0, sizeof(format)); - memset(palette, 0, sizeof(palette)); } DIBSectionBuffer::~DIBSectionBuffer() { @@ -51,19 +49,10 @@ void DIBSectionBuffer::setPF(const PixelFormat& pf) { vlog.debug("pixel format unchanged by setPF()"); return; } + if (!pf.trueColour) + throw rfb::Exception("palette format not supported"); format = pf; recreateBuffer(); - if ((pf.bpp <= 8) && pf.trueColour) { - vlog.info("creating %d-bit TrueColour palette", pf.depth); - for (int i=0; i < (1<<(pf.depth)); i++) { - rdr::U16 r, g, b; - pf.rgbFromPixel(i, NULL, &r, &g, &b); - palette[i].r = r; - palette[i].g = g; - palette[i].b = b; - } - refreshPalette(); - } } void DIBSectionBuffer::setSize(int w, int h) { @@ -77,20 +66,6 @@ void DIBSectionBuffer::setSize(int w, int h) { } -// * copyPaletteToDIB MUST NEVER be called on a truecolour DIB! * - -void copyPaletteToDIB(Colour palette[256], HDC wndDC, HBITMAP dib) { - BitmapDC dibDC(wndDC, dib); - RGBQUAD rgb[256]; - for (unsigned int i=0;i<256;i++) { - rgb[i].rgbRed = palette[i].r >> 8; - rgb[i].rgbGreen = palette[i].g >> 8; - rgb[i].rgbBlue = palette[i].b >> 8; - } - if (!SetDIBColorTable(dibDC, 0, 256, (RGBQUAD*) rgb)) - throw rdr::SystemException("unable to SetDIBColorTable", GetLastError()); -} - inline void initMaxAndShift(DWORD mask, int* max, int* shift) { for ((*shift) = 0; (mask & 1) == 0; (*shift)++) mask >>= 1; (*max) = (rdr::U16)mask; @@ -103,9 +78,7 @@ void DIBSectionBuffer::recreateBuffer() { if (width_ && height_ && (format.depth != 0)) { BitmapInfo bi; memset(&bi, 0, sizeof(bi)); - // *** wrong? - UINT iUsage = format.trueColour ? DIB_RGB_COLORS : DIB_PAL_COLORS; - // *** + UINT iUsage = DIB_RGB_COLORS; bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biBitCount = format.bpp; bi.bmiHeader.biSizeImage = (format.bpp / 8) * width_ * height_; @@ -140,15 +113,11 @@ void DIBSectionBuffer::recreateBuffer() { // Copy the contents across if (device) { - if (format.bpp <= 8) - copyPaletteToDIB(palette, device, new_bitmap); BitmapDC src_dev(device, bitmap); BitmapDC dest_dev(device, new_bitmap); BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY); } else { WindowDC wndDC(window); - if (format.bpp <= 8) - copyPaletteToDIB(palette, wndDC, new_bitmap); BitmapDC src_dev(wndDC, bitmap); BitmapDC dest_dev(wndDC, new_bitmap); BitBlt(dest_dev, 0, 0, width_, height_, src_dev, 0, 0, SRCCOPY); @@ -164,7 +133,6 @@ void DIBSectionBuffer::recreateBuffer() { if (new_bitmap) { int bpp, depth; - bool trueColour; int redMax, greenMax, blueMax; int redShift, greenShift, blueShift; @@ -189,46 +157,24 @@ void DIBSectionBuffer::recreateBuffer() { // Calculate the PixelFormat for the DIB bpp = depth = ds.dsBm.bmBitsPixel; - trueColour = format.trueColour || format.bpp > 8; - - if (trueColour) { - // Get the truecolour format used by the DIBSection - initMaxAndShift(ds.dsBitfields[0], &redMax, &redShift); - initMaxAndShift(ds.dsBitfields[1], &greenMax, &greenShift); - initMaxAndShift(ds.dsBitfields[2], &blueMax, &blueShift); - - // Calculate the effective depth - depth = 0; - Pixel bits = ds.dsBitfields[0] | ds.dsBitfields[1] | ds.dsBitfields[2]; - while (bits) { - depth++; - bits = bits >> 1; - } - if (depth > bpp) - throw Exception("Bad DIBSection format (depth exceeds bpp)"); + + // Get the truecolour format used by the DIBSection + initMaxAndShift(ds.dsBitfields[0], &redMax, &redShift); + initMaxAndShift(ds.dsBitfields[1], &greenMax, &greenShift); + initMaxAndShift(ds.dsBitfields[2], &blueMax, &blueShift); + + // Calculate the effective depth + depth = 0; + Pixel bits = ds.dsBitfields[0] | ds.dsBitfields[1] | ds.dsBitfields[2]; + while (bits) { + depth++; + bits = bits >> 1; } + if (depth > bpp) + throw Exception("Bad DIBSection format (depth exceeds bpp)"); - format = PixelFormat(bpp, depth, false, trueColour, + format = PixelFormat(bpp, depth, false, true, redMax, greenMax, blueMax, redShift, greenShift, blueShift); - - if (!trueColour) { - // Set the DIBSection's palette - refreshPalette(); - } } } - -void DIBSectionBuffer::refreshPalette() { - if (format.bpp > 8) { - vlog.error("refresh palette called for truecolor DIB"); - return; - } - vlog.debug("refreshing palette"); - if (device) - copyPaletteToDIB(palette, device, bitmap); - else - copyPaletteToDIB(palette, WindowDC(window), bitmap); -} - - diff --git a/win/rfb_win32/DIBSectionBuffer.h b/win/rfb_win32/DIBSectionBuffer.h index ad1a310c..cf9e7bc1 100644 --- a/win/rfb_win32/DIBSectionBuffer.h +++ b/win/rfb_win32/DIBSectionBuffer.h @@ -28,7 +28,6 @@ #include <windows.h> #include <rfb/PixelBuffer.h> #include <rfb/Region.h> -#include <rfb/ColourMap.h> #include <rfb/Exception.h> namespace rfb { @@ -39,7 +38,7 @@ namespace rfb { // -=- DIBSectionBuffer // - class DIBSectionBuffer : public FullFramePixelBuffer, ColourMap { + class DIBSectionBuffer : public FullFramePixelBuffer { public: DIBSectionBuffer(HWND window); DIBSectionBuffer(HDC device); @@ -48,32 +47,11 @@ namespace rfb { virtual void setPF(const PixelFormat &pf); virtual void setSize(int w, int h); - virtual int getStride() const {return stride;} - - virtual ColourMap* getColourMap() const {return (ColourMap*)this;} - - // - ColourMap interface - virtual void lookup(int index, int* r, int *g, int* b) { - *r = palette[index].r; - *g = palette[index].g; - *b = palette[index].b; - } - - // Custom colourmap interface - void setColour(int index, int r, int g, int b) { - palette[index].r = r; - palette[index].g = g; - palette[index].b = b; - } - void refreshPalette(); - // *** virtual void copyRect(const Rect &dest, const Point &move_by_delta); public: HBITMAP bitmap; protected: void recreateBuffer(); - Colour palette[256]; - int stride; HWND window; HDC device; }; diff --git a/win/rfb_win32/DeviceFrameBuffer.cxx b/win/rfb_win32/DeviceFrameBuffer.cxx index cc9bbcad..0ad06e9e 100644 --- a/win/rfb_win32/DeviceFrameBuffer.cxx +++ b/win/rfb_win32/DeviceFrameBuffer.cxx @@ -1,4 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014 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 @@ -79,10 +80,6 @@ DeviceFrameBuffer::DeviceFrameBuffer(HDC deviceContext, const Rect& wRect) // Configure the cursor buffer cursorBm.setPF(format); - - // Set up a palette if required - if (!format.trueColour) - updateColourMap(); } DeviceFrameBuffer::~DeviceFrameBuffer() { @@ -134,37 +131,6 @@ DeviceFrameBuffer::grabRegion(const Region &rgn) { } -void copyDevicePaletteToDIB(HDC dc, DIBSectionBuffer* dib) { - // - Fetch the system palette for the framebuffer - PALETTEENTRY syspalette[256]; - UINT entries = ::GetSystemPaletteEntries(dc, 0, 256, syspalette); - - if (entries == 0) { - vlog.info("resorting to standard 16 color palette"); - for (unsigned int i=0;i<256;i++) { - int v = (i%16) >= 8 ? 127 : 255; - syspalette[i].peRed = i & 1 ? v : 0; - syspalette[i].peGreen = i & 2 ? v : 0; - syspalette[i].peBlue = i & 4 ? v : 0; - } - } else { - vlog.info("framebuffer has %u palette entries", entries); - } - - // - Update the bitmap's stored copy of the palette - for (unsigned int i=0;i<256;i++) { - int r, g, b; - r = (syspalette[i].peRed << 8) + 0x80; - g = (syspalette[i].peGreen << 8) + 0x80; - b = (syspalette[i].peBlue << 8) + 0x80; - dib->setColour(i, r, g, b); - } - - // - Update the DIB section to use the palette - dib->refreshPalette(); -} - - void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) { // - If hCursor is null then there is no cursor - clear the old one @@ -176,6 +142,10 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) try { + const rdr::U8* buffer; + rdr::U8* rwbuffer; + int stride; + // - Get the size and other details about the cursor. IconInfo iconInfo((HICON)hCursor); @@ -211,10 +181,6 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) // Configure the cursor bitmap cursorBm.setSize(cursor.width(), cursor.height()); - // Copy the palette into it if required - if (format.bpp <= 8) - copyDevicePaletteToDIB(device, &cursorBm); - // Draw the cursor into the bitmap BitmapDC dc(device, cursorBm.bitmap); if (!DrawIconEx(dc, 0, 0, hCursor, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT)) @@ -231,7 +197,8 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) bool doOutline = false; if (!iconInfo.hbmColor) { - Pixel xorColour = format.pixelFromRGB((rdr::U16)0, (rdr::U16)0, (rdr::U16)0, cursorBm.getColourMap()); + rwbuffer = cursorBm.getBufferRW(cursorBm.getRect(), &stride); + Pixel xorColour = format.pixelFromRGB((rdr::U16)0, (rdr::U16)0, (rdr::U16)0); for (int y = 0; y < cursor.height(); y++) { for (int x = 0; x < cursor.width(); x++) { int byte = y * maskInfo.bmWidthBytes + x / 8; @@ -242,11 +209,11 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) switch (format.bpp) { case 8: - ((rdr::U8*)cursorBm.data)[y * cursor.width() + x] = xorColour; break; + rwbuffer[y * cursor.width() + x] = xorColour; break; case 16: - ((rdr::U16*)cursorBm.data)[y * cursor.width() + x] = xorColour; break; + rwbuffer[y * cursor.width() + x] = xorColour; break; case 32: - ((rdr::U32*)cursorBm.data)[y * cursor.width() + x] = xorColour; break; + rwbuffer[y * cursor.width() + x] = xorColour; break; } doOutline = true; @@ -268,21 +235,21 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server) if (doOutline) { vlog.debug("drawing cursor outline!"); - memcpy(cursor.data, cursorBm.data, cursor.dataLen()); - cursor.drawOutline(format.pixelFromRGB((rdr::U16)0xffff, (rdr::U16)0xffff, (rdr::U16)0xffff, cursorBm.getColourMap())); - memcpy(cursorBm.data, cursor.data, cursor.dataLen()); + + buffer = cursorBm.getBuffer(cursorBm.getRect(), &stride); + cursor.imageRect(cursorBm.getRect(), buffer, stride); + + cursor.drawOutline(format.pixelFromRGB((rdr::U16)0xffff, (rdr::U16)0xffff, (rdr::U16)0xffff)); + + buffer = cursor.getBuffer(cursor.getRect(), &stride); + cursorBm.imageRect(cursor.getRect(), buffer, stride); } + buffer = cursorBm.getBuffer(cursorBm.getRect(), &stride); server->setCursor(cursor.width(), cursor.height(), cursor.hotspot, - cursorBm.data, cursor.mask.buf); + buffer, cursor.mask.buf); + } catch (rdr::Exception& e) { vlog.error("%s", e.str()); } } - - -void -DeviceFrameBuffer::updateColourMap() { - if (!format.trueColour) - copyDevicePaletteToDIB(device, this); -} diff --git a/win/rfb_win32/DeviceFrameBuffer.h b/win/rfb_win32/DeviceFrameBuffer.h index 7718c339..8e280f8a 100644 --- a/win/rfb_win32/DeviceFrameBuffer.h +++ b/win/rfb_win32/DeviceFrameBuffer.h @@ -79,7 +79,6 @@ namespace rfb { // - DeviceFrameBuffer specific methods void setCursor(HCURSOR c, VNCServer* server); - void updateColourMap(); // Set whether grabRect should ignore errors or throw exceptions // Only set this if you are sure you'll capture the errors some other way! diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx index 6d0c924f..26a7bbce 100644 --- a/win/rfb_win32/SDisplay.cxx +++ b/win/rfb_win32/SDisplay.cxx @@ -350,12 +350,6 @@ SDisplay::notifyDisplayEvent(WMMonitor::Notifier::DisplayEventType evt) { vlog.debug("desktop format changed"); recreatePixelBuffer(); break; - case WMMonitor::Notifier::DisplayColourMapChanged: - vlog.debug("desktop colormap changed"); - pb->updateColourMap(); - if (server) - server->setColourMapEntries(); - break; default: vlog.error("unknown display event received"); } diff --git a/win/rfb_win32/WMNotifier.cxx b/win/rfb_win32/WMNotifier.cxx index 20a5445f..159dacaf 100644 --- a/win/rfb_win32/WMNotifier.cxx +++ b/win/rfb_win32/WMNotifier.cxx @@ -46,12 +46,6 @@ WMMonitor::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { notifier->notifyDisplayEvent(Notifier::DisplayPixelFormatChanged); } break; - case WM_SYSCOLORCHANGE: - case WM_PALETTECHANGED: - if (notifier) { - notifier->notifyDisplayEvent(Notifier::DisplayColourMapChanged); - } - break; }; return MsgWindow::processMessage(msg, wParam, lParam); } diff --git a/win/rfb_win32/WMNotifier.h b/win/rfb_win32/WMNotifier.h index a7609642..ada45d09 100644 --- a/win/rfb_win32/WMNotifier.h +++ b/win/rfb_win32/WMNotifier.h @@ -44,7 +44,7 @@ namespace rfb { class Notifier { public: - typedef enum {DisplaySizeChanged, DisplayColourMapChanged, + typedef enum {DisplaySizeChanged, DisplayPixelFormatChanged} DisplayEventType; virtual void notifyDisplayEvent(DisplayEventType evt) = 0; }; |