Browse Source

Merge branch 'nocolourmap' of https://github.com/CendioOssman/tigervnc

tags/v1.3.90
Pierre Ossman 10 years ago
parent
commit
ff7a923a61
100 changed files with 1921 additions and 3317 deletions
  1. 0
    23
      common/rdr/InStream.h
  2. 0
    25
      common/rdr/OutStream.h
  3. 4
    4
      common/rfb/CConnection.cxx
  4. 1
    5
      common/rfb/CMakeLists.txt
  5. 1
    2
      common/rfb/CMsgHandler.h
  6. 145
    45
      common/rfb/CMsgReader.cxx
  7. 17
    15
      common/rfb/CMsgReader.h
  8. 0
    174
      common/rfb/CMsgReaderV3.cxx
  9. 87
    1
      common/rfb/CMsgWriter.cxx
  10. 17
    20
      common/rfb/CMsgWriter.h
  11. 0
    117
      common/rfb/CMsgWriterV3.cxx
  12. 0
    41
      common/rfb/CMsgWriterV3.h
  13. 0
    96
      common/rfb/ColourCube.h
  14. 0
    51
      common/rfb/ColourMap.h
  15. 20
    18
      common/rfb/CopyRectDecoder.cxx
  16. 9
    8
      common/rfb/CopyRectDecoder.h
  17. 14
    6
      common/rfb/Decoder.cxx
  18. 5
    2
      common/rfb/Decoder.h
  19. 11
    6
      common/rfb/Encoder.cxx
  20. 10
    7
      common/rfb/Encoder.h
  21. 5
    7
      common/rfb/HextileDecoder.cxx
  22. 1
    3
      common/rfb/HextileDecoder.h
  23. 7
    10
      common/rfb/HextileEncoder.cxx
  24. 2
    4
      common/rfb/HextileEncoder.h
  25. 190
    0
      common/rfb/Palette.h
  26. 31
    105
      common/rfb/PixelBuffer.cxx
  27. 17
    34
      common/rfb/PixelBuffer.h
  28. 90
    58
      common/rfb/PixelFormat.cxx
  29. 17
    13
      common/rfb/PixelFormat.h
  30. 59
    109
      common/rfb/PixelFormat.inl
  31. 11
    137
      common/rfb/PixelTransformer.cxx
  32. 2
    31
      common/rfb/PixelTransformer.h
  33. 4
    6
      common/rfb/RREDecoder.cxx
  34. 1
    3
      common/rfb/RREDecoder.h
  35. 10
    9
      common/rfb/RREEncoder.cxx
  36. 4
    5
      common/rfb/RREEncoder.h
  37. 5
    4
      common/rfb/RawDecoder.cxx
  38. 1
    3
      common/rfb/RawDecoder.h
  39. 8
    8
      common/rfb/RawEncoder.cxx
  40. 2
    4
      common/rfb/RawEncoder.h
  41. 18
    9
      common/rfb/SConnection.cxx
  42. 1
    5
      common/rfb/SConnection.h
  43. 2
    2
      common/rfb/SDesktop.h
  44. 112
    0
      common/rfb/SMsgReader.cxx
  45. 15
    9
      common/rfb/SMsgReader.h
  46. 0
    131
      common/rfb/SMsgReaderV3.cxx
  47. 327
    60
      common/rfb/SMsgWriter.cxx
  48. 78
    85
      common/rfb/SMsgWriter.h
  49. 0
    399
      common/rfb/SMsgWriterV3.cxx
  50. 0
    84
      common/rfb/SMsgWriterV3.h
  51. 22
    4
      common/rfb/TightDecoder.cxx
  52. 3
    2
      common/rfb/TightDecoder.h
  53. 36
    17
      common/rfb/TightEncoder.cxx
  54. 7
    31
      common/rfb/TightEncoder.h
  55. 0
    110
      common/rfb/TightPalette.cxx
  56. 0
    127
      common/rfb/TightPalette.h
  57. 2
    23
      common/rfb/TransImageGetter.cxx
  58. 3
    28
      common/rfb/TransImageGetter.h
  59. 53
    60
      common/rfb/VNCSConnectionST.cxx
  60. 3
    4
      common/rfb/VNCSConnectionST.h
  61. 1
    7
      common/rfb/VNCServer.h
  62. 12
    14
      common/rfb/VNCServerST.cxx
  63. 1
    2
      common/rfb/VNCServerST.h
  64. 25
    7
      common/rfb/ZRLEDecoder.cxx
  65. 1
    2
      common/rfb/ZRLEDecoder.h
  66. 30
    19
      common/rfb/ZRLEEncoder.cxx
  67. 2
    3
      common/rfb/ZRLEEncoder.h
  68. 5
    11
      common/rfb/hextileDecode.h
  69. 4
    10
      common/rfb/hextileEncode.h
  70. 11
    17
      common/rfb/hextileEncodeBetter.h
  71. 4
    10
      common/rfb/rreDecode.h
  72. 1
    1
      common/rfb/rreEncode.h
  73. 15
    18
      common/rfb/tightDecode.h
  74. 58
    160
      common/rfb/tightEncode.h
  75. 10
    129
      common/rfb/transInitTempl.h
  76. 0
    33
      common/rfb/transTempl.h
  77. 10
    16
      common/rfb/zrleDecode.h
  78. 28
    92
      common/rfb/zrleEncode.h
  79. 1
    1
      tests/pixelconv.cxx
  80. 3
    5
      unix/x0vncserver/XPixelBuffer.cxx
  81. 1
    8
      unix/x0vncserver/XPixelBuffer.h
  82. 2
    16
      unix/x0vncserver/x0vncserver.cxx
  83. 30
    117
      unix/xserver/hw/vnc/XserverDesktop.cc
  84. 1
    11
      unix/xserver/hw/vnc/XserverDesktop.h
  85. 4
    5
      unix/xserver/hw/vnc/vncExtInit.cc
  86. 0
    38
      unix/xserver/hw/vnc/vncHooks.cc
  87. 27
    12
      vncviewer/CConn.cxx
  88. 7
    3
      vncviewer/CConn.h
  89. 2
    0
      vncviewer/CMakeLists.txt
  90. 0
    6
      vncviewer/DesktopWindow.cxx
  91. 0
    2
      vncviewer/DesktopWindow.h
  92. 52
    0
      vncviewer/FLTKPixelBuffer.cxx
  93. 12
    20
      vncviewer/FLTKPixelBuffer.h
  94. 13
    8
      vncviewer/OSXPixelBuffer.cxx
  95. 6
    6
      vncviewer/OSXPixelBuffer.h
  96. 7
    21
      vncviewer/PlatformPixelBuffer.cxx
  97. 6
    24
      vncviewer/PlatformPixelBuffer.h
  98. 37
    45
      vncviewer/Viewport.cxx
  99. 2
    9
      vncviewer/Viewport.h
  100. 0
    0
      vncviewer/Win32PixelBuffer.cxx

+ 0
- 23
common/rdr/InStream.h View File

@@ -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.


+ 0
- 25
common/rdr/OutStream.h View File

@@ -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.


+ 4
- 4
common/rfb/CConnection.cxx View File

@@ -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);

+ 1
- 5
common/rfb/CMakeLists.txt View File

@@ -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

+ 1
- 2
common/rfb/CMsgHandler.h View File

@@ -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;

+ 145
- 45
common/rfb/CMsgReader.cxx View File

@@ -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;
}

+ 17
- 15
common/rfb/CMsgReader.h View File

@@ -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

+ 0
- 174
common/rfb/CMsgReaderV3.cxx View File

@@ -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();
}

+ 87
- 1
common/rfb/CMsgWriter.cxx View File

@@ -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();
}

+ 17
- 20
common/rfb/CMsgWriter.h View File

@@ -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;

+ 0
- 117
common/rfb/CMsgWriterV3.cxx View File

@@ -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();
}

+ 0
- 41
common/rfb/CMsgWriterV3.h View File

@@ -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

+ 0
- 96
common/rfb/ColourCube.h View File

@@ -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

+ 0
- 51
common/rfb/ColourMap.h View File

@@ -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

common/rfb/SMsgReaderV3.h → common/rfb/CopyRectDecoder.cxx View File

@@ -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

common/rfb/ImageGetter.h → common/rfb/CopyRectDecoder.h View File

@@ -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

+ 14
- 6
common/rfb/Decoder.cxx View File

@@ -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;
}

+ 5
- 2
common/rfb/Decoder.h View File

@@ -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;
};
}


+ 11
- 6
common/rfb/Encoder.cxx View File

@@ -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;
}

+ 10
- 7
common/rfb/Encoder.h View File

@@ -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;
};
}


+ 5
- 7
common/rfb/HextileDecoder.cxx View File

@@ -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;

+ 1
- 3
common/rfb/HextileDecoder.h View File

@@ -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

+ 7
- 10
common/rfb/HextileEncoder.cxx View File

@@ -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();
}

+ 2
- 4
common/rfb/HextileEncoder.h View File

@@ -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

+ 190
- 0
common/rfb/Palette.h View File

@@ -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

+ 31
- 105
common/rfb/PixelBuffer.cxx View File

@@ -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);

+ 17
- 34
common/rfb/PixelBuffer.h View File

@@ -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();
};


+ 90
- 58
common/rfb/PixelFormat.cxx View File

@@ -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;
}

+ 17
- 13
common/rfb/PixelFormat.h View File

@@ -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.

+ 59
- 109
common/rfb/PixelFormat.inl View File

@@ -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;
}
}


+ 11
- 137
common/rfb/PixelTransformer.cxx View File

@@ -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
{

+ 2
- 31
common/rfb/PixelTransformer.h View File

@@ -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;

+ 4
- 6
common/rfb/RREDecoder.cxx View File

@@ -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;

+ 1
- 3
common/rfb/RREDecoder.h View File

@@ -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

+ 10
- 9
common/rfb/RREEncoder.cxx View File

@@ -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();
}

+ 4
- 5
common/rfb/RREEncoder.h View File

@@ -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;
};
}

+ 5
- 4
common/rfb/RawDecoder.cxx View File

@@ -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;

+ 1
- 3
common/rfb/RawDecoder.h View File

@@ -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

+ 8
- 8
common/rfb/RawEncoder.cxx View File

@@ -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();
}

+ 2
- 4
common/rfb/RawEncoder.h View File

@@ -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

+ 18
- 9
common/rfb/SConnection.cxx View File

@@ -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);
}

+ 1
- 5
common/rfb/SConnection.h View File

@@ -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;


+ 2
- 2
common/rfb/SDesktop.h View File

@@ -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;

+ 112
- 0
common/rfb/SMsgReader.cxx View File

@@ -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();

+ 15
- 9
common/rfb/SMsgReader.h View File

@@ -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;

+ 0
- 131
common/rfb/SMsgReaderV3.cxx View File

@@ -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);
}

+ 327
- 60
common/rfb/SMsgWriter.cxx View File

@@ -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);
}

+ 78
- 85
common/rfb/SMsgWriter.h View File

@@ -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

+ 0
- 399
common/rfb/SMsgWriterV3.cxx View File

@@ -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;
}
}


+ 0
- 84
common/rfb/SMsgWriterV3.h View File

@@ -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

+ 22
- 4
common/rfb/TightDecoder.cxx View File

@@ -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;
}

+ 3
- 2
common/rfb/TightDecoder.h View File

@@ -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];

+ 36
- 17
common/rfb/TightEncoder.cxx View File

@@ -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);
}
}
}

+ 7
- 31
common/rfb/TightEncoder.h View File

@@ -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[];

+ 0
- 110
common/rfb/TightPalette.cxx View File

@@ -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;
}

+ 0
- 127
common/rfb/TightPalette.h View File

@@ -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__

+ 2
- 23
common/rfb/TransImageGetter.cxx View File

@@ -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);
}

+ 3
- 28
common/rfb/TransImageGetter.h View File

@@ -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;
};
}

+ 53
- 60
common/rfb/VNCSConnectionST.cxx View File

@@ -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

+ 3
- 4
common/rfb/VNCSConnectionST.h View File

@@ -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;


+ 1
- 7
common/rfb/VNCServer.h View File

@@ -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;

+ 12
- 14
common/rfb/VNCServerST.cxx View File

@@ -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;
}


+ 1
- 2
common/rfb/VNCServerST.h View File

@@ -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 &region);
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();

+ 25
- 7
common/rfb/ZRLEDecoder.cxx View File

@@ -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:

+ 1
- 2
common/rfb/ZRLEDecoder.h View File

@@ -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;
};
}

+ 30
- 19
common/rfb/ZRLEEncoder.cxx View File

@@ -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();
}

+ 2
- 3
common/rfb/ZRLEEncoder.h View File

@@ -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;
};

+ 5
- 11
common/rfb/hextileDecode.h View File

@@ -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);
}
}
}

+ 4
- 10
common/rfb/hextileEncode.h View File

@@ -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;

+ 11
- 17
common/rfb/hextileEncodeBetter.h View File

@@ -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();

+ 4
- 10
common/rfb/rreDecode.h View File

@@ -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);
}
}


+ 1
- 1
common/rfb/rreEncode.h View File

@@ -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

+ 15
- 18
common/rfb/tightDecode.h View File

@@ -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));

+ 58
- 160
common/rfb/tightEncode.h View File

@@ -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)

+ 10
- 129
common/rfb/transInitTempl.h View File

@@ -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
}

+ 0
- 33
common/rfb/transTempl.h View File

@@ -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

+ 10
- 16
common/rfb/zrleDecode.h View File

@@ -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);
}
}


+ 28
- 92
common/rfb/zrleEncode.h View File

@@ -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));

+ 1
- 1
tests/pixelconv.cxx View File

@@ -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);

+ 3
- 5
unix/x0vncserver/XPixelBuffer.cxx View File

@@ -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);

+ 1
- 8
unix/x0vncserver/XPixelBuffer.h View File

@@ -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) {

+ 2
- 16
unix/x0vncserver/x0vncserver.cxx View File

@@ -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) {

+ 30
- 117
unix/xserver/hw/vnc/XserverDesktop.cc View File

@@ -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)

+ 1
- 11
unix/xserver/hw/vnc/XserverDesktop.h View File

@@ -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_;

+ 4
- 5
unix/xserver/hw/vnc/vncExtInit.cc View File

@@ -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]);

+ 0
- 38
unix/xserver/hw/vnc/vncHooks.cc View File

@@ -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(

+ 27
- 12
vncviewer/CConn.cxx View File

@@ -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();
}


+ 7
- 3
vncviewer/CConn.h View File

@@ -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;

+ 2
- 0
vncviewer/CMakeLists.txt View File

@@ -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

+ 0
- 6
vncviewer/DesktopWindow.cxx View File

@@ -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);
}

+ 0
- 2
vncviewer/DesktopWindow.h View File

@@ -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);

+ 52
- 0
vncviewer/FLTKPixelBuffer.cxx View File

@@ -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);
}

common/rfb/TrueColourMap.h → vncviewer/FLTKPixelBuffer.h View File

@@ -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

+ 13
- 8
vncviewer/OSXPixelBuffer.cxx View File

@@ -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;

+ 6
- 6
vncviewer/OSXPixelBuffer.h View File

@@ -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

common/rfb/CMsgReaderV3.h → vncviewer/PlatformPixelBuffer.cxx View File

@@ -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

+ 6
- 24
vncviewer/PlatformPixelBuffer.h View File

@@ -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

+ 37
- 45
vncviewer/Viewport.cxx View File

@@ -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();
}



+ 2
- 9
vncviewer/Viewport.h View File

@@ -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;

+ 0
- 0
vncviewer/Win32PixelBuffer.cxx View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save