@@ -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. | |||
@@ -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. | |||
@@ -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); |
@@ -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 |
@@ -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; |
@@ -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; | |||
} |
@@ -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 |
@@ -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(); | |||
} |
@@ -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(); | |||
} |
@@ -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; |
@@ -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(); | |||
} |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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; | |||
} |
@@ -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; | |||
}; | |||
} | |||
@@ -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; | |||
} |
@@ -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; | |||
}; | |||
} | |||
@@ -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; |
@@ -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 |
@@ -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(); | |||
} |
@@ -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 |
@@ -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 |
@@ -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); |
@@ -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(); | |||
}; | |||
@@ -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; | |||
} |
@@ -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. |
@@ -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; | |||
} | |||
} | |||
@@ -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 | |||
{ |
@@ -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; |
@@ -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; |
@@ -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 |
@@ -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(); | |||
} |
@@ -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; | |||
}; | |||
} |
@@ -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; |
@@ -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 |
@@ -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(); | |||
} |
@@ -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 |
@@ -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); | |||
} |
@@ -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; | |||
@@ -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; |
@@ -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(); |
@@ -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; |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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 |
@@ -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; | |||
} | |||
} | |||
@@ -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 |
@@ -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; | |||
} |
@@ -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]; |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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> | |||
@@ -44,28 +45,6 @@ namespace rfb { | |||
int jpegSubsampling; | |||
}; | |||
// | |||
// 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). | |||
@@ -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[]; |
@@ -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; | |||
} |
@@ -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__ |
@@ -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); | |||
} |
@@ -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 | |||
@@ -89,10 +69,6 @@ namespace rfb { | |||
// the rectangle given to getImage(). | |||
void setOffset(const Point& offset_) { offset = offset_; } | |||
private: | |||
static void cmCallback(int firstColour, int nColours, | |||
ColourMap* cm, void* data); | |||
private: | |||
bool economic; | |||
PixelBuffer* pb; | |||
@@ -100,7 +76,6 @@ namespace rfb { | |||
SMsgWriter* writer; | |||
rdr::U8* table; | |||
transFnType transFn; | |||
ColourCube* cube; | |||
Point offset; | |||
}; | |||
} |
@@ -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 |
@@ -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; | |||
@@ -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; |
@@ -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; | |||
} | |||
@@ -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(); |
@@ -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: |
@@ -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; | |||
}; | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
}; |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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(); |
@@ -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); | |||
} | |||
} | |||
@@ -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 |
@@ -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)); |
@@ -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> | |||
@@ -53,82 +52,6 @@ namespace rfb { | |||
#ifndef TIGHT_ONCE | |||
#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) |
@@ -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 | |||
} |
@@ -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 |
@@ -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); | |||
} | |||
} | |||
@@ -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)); |
@@ -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); |
@@ -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); |
@@ -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) { |
@@ -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) { |
@@ -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) |
@@ -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_; |
@@ -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]); |
@@ -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( |
@@ -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(); | |||
} | |||
@@ -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; |
@@ -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 |
@@ -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); | |||
} |
@@ -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); |
@@ -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); | |||
} |
@@ -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 |
@@ -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; |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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(); | |||
} | |||
@@ -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; |