]> source.dussan.org Git - tigervnc.git/commitdiff
Split decoders into a read and decode step
authorPierre Ossman <ossman@cendio.se>
Tue, 10 Nov 2015 16:17:34 +0000 (17:17 +0100)
committerPierre Ossman <ossman@cendio.se>
Fri, 27 Nov 2015 10:00:22 +0000 (11:00 +0100)
We need to split these steps up in preparation for multi-core
support. Reading needs to be done in a serial manner, whilst
decoding can be done in parallel.

This also involved a rather large cleanup of the Tight decoder.

17 files changed:
common/rfb/CopyRectDecoder.cxx
common/rfb/CopyRectDecoder.h
common/rfb/DecodeManager.cxx
common/rfb/DecodeManager.h
common/rfb/Decoder.h
common/rfb/HextileDecoder.cxx
common/rfb/HextileDecoder.h
common/rfb/RREDecoder.cxx
common/rfb/RREDecoder.h
common/rfb/RawDecoder.cxx
common/rfb/RawDecoder.h
common/rfb/TightDecoder.cxx
common/rfb/TightDecoder.h
common/rfb/ZRLEDecoder.cxx
common/rfb/ZRLEDecoder.h
common/rfb/hextileDecode.h
common/rfb/tightDecode.h

index 4690b5e3c498623266f715e17efe50c37fdc0a48..52de8790ea2de7be2fdee930ecb4a08e3c2200a6 100644 (file)
@@ -15,7 +15,8 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
-#include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/CopyRectDecoder.h>
 
@@ -30,10 +31,17 @@ CopyRectDecoder::~CopyRectDecoder()
 }
 
 void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is,
-                               const ConnParams& cp,
-                               ModifiablePixelBuffer* pb)
+                               const ConnParams& cp, rdr::OutStream* os)
 {
-  int srcX = is->readU16();
-  int srcY = is->readU16();
+  os->copyBytes(is, 4);
+}
+
+void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer,
+                                 size_t buflen, const ConnParams& cp,
+                                 ModifiablePixelBuffer* pb)
+{
+  rdr::MemInStream is(buffer, buflen);
+  int srcX = is.readU16();
+  int srcY = is.readU16();
   pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
 }
index a7195ce3fb6c4510f1726be79c6cdb16092a0f68..998a50918455743d97168fd42ef15429fa9f0f8d 100644 (file)
@@ -27,7 +27,10 @@ namespace rfb {
     CopyRectDecoder();
     virtual ~CopyRectDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
   };
 }
 #endif
index b82d31d206c832206dc7f53be3ab453c8f63a29b..ffae18b31ccb0892add19107ee13088c8655c427 100644 (file)
@@ -26,6 +26,7 @@
 #include <rfb/LogWriter.h>
 
 #include <rdr/Exception.h>
+#include <rdr/MemOutStream.h>
 
 using namespace rfb;
 
@@ -35,12 +36,14 @@ DecodeManager::DecodeManager(CConnection *conn) :
   conn(conn)
 {
   memset(decoders, 0, sizeof(decoders));
+  bufferStream = new rdr::MemOutStream();
 }
 
 DecodeManager::~DecodeManager()
 {
   for (size_t i = 0; i < sizeof(decoders)/sizeof(decoders[0]); i++)
     delete decoders[i];
+  delete bufferStream;
 }
 
 void DecodeManager::decodeRect(const Rect& r, int encoding,
@@ -60,5 +63,11 @@ void DecodeManager::decodeRect(const Rect& r, int encoding,
       throw rdr::Exception("Unknown encoding");
     }
   }
-  decoders[encoding]->readRect(r, conn->getInStream(), conn->cp, pb);
+
+  bufferStream->clear();
+  decoders[encoding]->readRect(r, conn->getInStream(),
+                               conn->cp, bufferStream);
+  decoders[encoding]->decodeRect(r, bufferStream->data(),
+                                 bufferStream->length(),
+                                 conn->cp, pb);
 }
index 445601d95f90ff796611aacda3d3ef0f48afdbe4..63a41206843c1194c68d2d9295d35f3c40bfb90b 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <rfb/encodings.h>
 
+namespace rdr { class MemOutStream; }
+
 namespace rfb {
   class CConnection;
   class Decoder;
@@ -38,6 +40,7 @@ namespace rfb {
   private:
     CConnection *conn;
     Decoder *decoders[encodingMax+1];
+    rdr::MemOutStream *bufferStream;
   };
 }
 
index 9d929ea498e65d5eb816736412ec65891e19c029..4195a80b612b2499d09598962cca6272a43d6299 100644 (file)
 #ifndef __RFB_DECODER_H__
 #define __RFB_DECODER_H__
 
-namespace rdr { class InStream; }
+namespace rdr {
+  class InStream;
+  class OutStream;
+}
 
 namespace rfb {
   class ConnParams;
@@ -31,12 +34,20 @@ namespace rfb {
     Decoder();
     virtual ~Decoder();
 
-    // readRect() is the main interface that decodes the given rectangle
-    // with data from the given InStream, onto the ModifiablePixelBuffer.
-    // The PixelFormat of the PixelBuffer might not match the ConnParams
-    // and it is up to the decoder to do any necessary conversion.
+    // These functions are the main interface to an individual decoder
+
+    // readRect() transfers data for the given rectangle from the
+    // InStream to the OutStream, possibly changing it along the way to
+    // make it easier to decode.
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb)=0;
+                          const ConnParams& cp, rdr::OutStream* os)=0;
+    // decodeRect() decodes the given rectangle with data from the
+    // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
+    // the PixelBuffer might not match the ConnParams and it is up to
+    // the decoder to do any necessary conversion.
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb)=0;
 
     static bool supported(int encoding);
     static Decoder* createDecoder(int encoding);
index 705ccf511bbe9f784fd9c707817f638ade7846fa..d1412d4a12908e2376b927ec659790beef9c1f26 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+
 #include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
 #include <rfb/ConnParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/HextileDecoder.h>
@@ -41,13 +45,60 @@ HextileDecoder::~HextileDecoder()
 }
 
 void HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
-                              const ConnParams& cp, ModifiablePixelBuffer* pb)
+                              const ConnParams& cp, rdr::OutStream* os)
+{
+  Rect t;
+  size_t bytesPerPixel;
+
+  bytesPerPixel = cp.pf().bpp/8;
+
+  for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+    t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+
+    for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+      rdr::U8 tileType;
+
+      t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+
+      tileType = is->readU8();
+      os->writeU8(tileType);
+
+      if (tileType & hextileRaw) {
+        os->copyBytes(is, t.area() * bytesPerPixel);
+        continue;
+      }
+
+      if (tileType & hextileBgSpecified)
+        os->copyBytes(is, bytesPerPixel);
+
+      if (tileType & hextileFgSpecified)
+        os->copyBytes(is, bytesPerPixel);
+
+      if (tileType & hextileAnySubrects) {
+        rdr::U8 nSubrects;
+
+        nSubrects = is->readU8();
+        os->writeU8(nSubrects);
+
+        if (tileType & hextileSubrectsColoured)
+          os->copyBytes(is, nSubrects * (bytesPerPixel + 2));
+        else
+          os->copyBytes(is, nSubrects * 2);
+      }
+    }
+  }
+}
+
+void HextileDecoder::decodeRect(const Rect& r, const void* buffer,
+                                size_t buflen, const ConnParams& cp,
+                                ModifiablePixelBuffer* pb)
 {
+  rdr::MemInStream is(buffer, buflen);
   const PixelFormat& pf = cp.pf();
-  rdr::U8 buf[16 * 16 * 4 * pf.bpp/8];
   switch (pf.bpp) {
-  case 8:  hextileDecode8 (r, is, (rdr::U8*) buf, pf, pb); break;
-  case 16: hextileDecode16(r, is, (rdr::U16*)buf, pf, pb); break;
-  case 32: hextileDecode32(r, is, (rdr::U32*)buf, pf, pb); break;
+  case 8:  hextileDecode8 (r, &is, pf, pb); break;
+  case 16: hextileDecode16(r, &is, pf, pb); break;
+  case 32: hextileDecode32(r, &is, pf, pb); break;
   }
 }
index 22eefba44ceaac4caa3bd58082651fa57c7696fb..bdc76bcc8e3e5f71761b69b04dcb002086fd30dd 100644 (file)
@@ -27,7 +27,10 @@ namespace rfb {
     HextileDecoder();
     virtual ~HextileDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
   };
 }
 #endif
index b80264443df55acb41dcf6cb092d8f601728626c..2dd47cc07848dc54f8544662ce9722e4462adfd1 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+
 #include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
 #include <rfb/ConnParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/RREDecoder.h>
@@ -41,12 +45,25 @@ RREDecoder::~RREDecoder()
 }
 
 void RREDecoder::readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb)
+                          const ConnParams& cp, rdr::OutStream* os)
+{
+  rdr::U32 numRects;
+
+  numRects = is->readU32();
+  os->writeU32(numRects);
+
+  os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8));
+}
+
+void RREDecoder::decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb)
 {
+  rdr::MemInStream is(buffer, buflen);
   const PixelFormat& pf = cp.pf();
   switch (pf.bpp) {
-  case 8:  rreDecode8 (r, is, pf, pb); break;
-  case 16: rreDecode16(r, is, pf, pb); break;
-  case 32: rreDecode32(r, is, pf, pb); break;
+  case 8:  rreDecode8 (r, &is, pf, pb); break;
+  case 16: rreDecode16(r, &is, pf, pb); break;
+  case 32: rreDecode32(r, &is, pf, pb); break;
   }
 }
index 3bed62bc260f7b506fb9cb5fa513f59089174157..f89fef4a520458ee5104d819d26bb78843c4065a 100644 (file)
@@ -27,7 +27,10 @@ namespace rfb {
     RREDecoder();
     virtual ~RREDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
   };
 }
 #endif
index 292c3436e2220c551c84ef4d776a45aa1a1a29f8..e349bda8bc2d1f526f20bb0839e50e51f773e206 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
-#include <rdr/InStream.h>
+
+#include <assert.h>
+
+#include <rdr/OutStream.h>
 #include <rfb/ConnParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/RawDecoder.h>
@@ -31,36 +34,15 @@ RawDecoder::~RawDecoder()
 }
 
 void RawDecoder::readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb)
+                          const ConnParams& cp, rdr::OutStream* os)
 {
-  const PixelFormat& pf = cp.pf();
-
-  rdr::U8 imageBuf[16384];
-  const int maxPixels = sizeof(imageBuf) / (pf.bpp/8);
-
-  int x = r.tl.x;
-  int y = r.tl.y;
-  int w = r.width();
-  int h = r.height();
-
-  while (h > 0) {
-    int dx;
-
-    dx = 0;
-    while (dx < w) {
-      int dw;
-
-      dw = maxPixels;
-      if (dx + dw > w)
-        dw = w - dx;
-
-      is->readBytes(imageBuf, dw * pf.bpp/8);
-      pb->imageRect(pf, Rect(x+dx, y, x+dx+dw, y+1), imageBuf);
-
-      dx += dw;
-    }
+  os->copyBytes(is, r.area() * cp.pf().bpp/8);
+}
 
-    y++;
-    h--;
-  }
+void RawDecoder::decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb)
+{
+  assert(buflen >= (size_t)r.area() * cp.pf().bpp/8);
+  pb->imageRect(cp.pf(), r, buffer);
 }
index 4caf175d753f886b27b0ec5db5e07698938e553d..21ea738bf335ca313752f0cd9f2266e941aa4b94 100644 (file)
@@ -26,7 +26,10 @@ namespace rfb {
     RawDecoder();
     virtual ~RawDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
   };
 }
 #endif
index 96749a9eb64f0c2bb6aa474a9a2fe1746714b0f2..cab49fdf16437217a5bc68a33465d64e00fa8739 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2000-2003 Constantin Kaplinsky.  All Rights Reserved.
  * Copyright 2004-2005 Cendio AB.
+ * Copyright 2009-2015 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
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+
+#include <assert.h>
+
 #include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
 #include <rfb/ConnParams.h>
+#include <rfb/Exception.h>
 #include <rfb/PixelBuffer.h>
+#include <rfb/TightConstants.h>
 #include <rfb/TightDecoder.h>
 
 using namespace rfb;
 
-#define TIGHT_MAX_WIDTH 2048
+static const int TIGHT_MAX_WIDTH = 2048;
+static const int TIGHT_MIN_TO_COMPRESS = 12;
 
 #define BPP 8
 #include <rfb/tightDecode.h>
@@ -45,29 +55,355 @@ TightDecoder::~TightDecoder()
 }
 
 void TightDecoder::readRect(const Rect& r, rdr::InStream* is,
-                            const ConnParams& cp, ModifiablePixelBuffer* pb)
+                            const ConnParams& cp, rdr::OutStream* os)
+{
+  rdr::U8 comp_ctl;
+
+  comp_ctl = is->readU8();
+  os->writeU8(comp_ctl);
+
+  comp_ctl >>= 4;
+
+  // "Fill" compression type.
+  if (comp_ctl == tightFill) {
+    if (cp.pf().is888())
+      os->copyBytes(is, 3);
+    else
+      os->copyBytes(is, cp.pf().bpp/8);
+    return;
+  }
+
+  // "JPEG" compression type.
+  if (comp_ctl == tightJpeg) {
+    rdr::U32 len;
+
+    len = readCompact(is);
+    os->writeOpaque32(len);
+    os->copyBytes(is, len);
+    return;
+  }
+
+  // Quit on unsupported compression type.
+  if (comp_ctl > tightMaxSubencoding)
+    throw Exception("TightDecoder: bad subencoding value received");
+
+  // "Basic" compression type.
+
+  int palSize = 0;
+
+  if (r.width() > TIGHT_MAX_WIDTH)
+    throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width());
+
+  // Possible palette
+  if ((comp_ctl & tightExplicitFilter) != 0) {
+    rdr::U8 filterId;
+
+    filterId = is->readU8();
+    os->writeU8(filterId);
+
+    switch (filterId) {
+    case tightFilterPalette:
+      palSize = is->readU8() + 1;
+      os->writeU8(palSize - 1);
+
+      if (cp.pf().is888())
+        os->copyBytes(is, palSize * 3);
+      else
+        os->copyBytes(is, palSize * cp.pf().bpp/8);
+      break;
+    case tightFilterGradient:
+      if (cp.pf().bpp == 8)
+        throw Exception("TightDecoder: invalid BPP for gradient filter");
+      break;
+    case tightFilterCopy:
+      break;
+    default:
+      throw Exception("TightDecoder: unknown filter code received");
+    }
+  }
+
+  size_t rowSize, dataSize;
+
+  if (palSize != 0) {
+    if (palSize <= 2)
+      rowSize = (r.width() + 7) / 8;
+    else
+      rowSize = r.width();
+  } else if (cp.pf().is888()) {
+    rowSize = r.width() * 3;
+  } else {
+    rowSize = r.width() * cp.pf().bpp/8;
+  }
+
+  dataSize = r.height() * rowSize;
+
+  if (dataSize < TIGHT_MIN_TO_COMPRESS)
+    os->copyBytes(is, dataSize);
+  else {
+    rdr::U32 len;
+
+    len = readCompact(is);
+    os->writeOpaque32(len);
+    os->copyBytes(is, len);
+  }
+}
+
+void TightDecoder::decodeRect(const Rect& r, const void* buffer,
+                              size_t buflen, const ConnParams& cp,
+                              ModifiablePixelBuffer* pb)
 {
-  this->is = is;
-  this->pb = pb;
-  clientpf = pb->getPF();
-  serverpf = cp.pf();
+  const rdr::U8* bufptr;
+  const PixelFormat& pf = cp.pf();
+
+  rdr::U8 comp_ctl;
+
+  bufptr = (const rdr::U8*)buffer;
+
+  assert(buflen >= 1);
+
+  comp_ctl = *bufptr;
+  bufptr += 1;
+  buflen -= 1;
+
+  // Flush zlib streams if we are told by the server to do so.
+  for (int i = 0; i < 4; i++) {
+    if (comp_ctl & 1) {
+      zis[i].reset();
+    }
+    comp_ctl >>= 1;
+  }
+
+  // "Fill" compression type.
+  if (comp_ctl == tightFill) {
+    if (pf.is888()) {
+      rdr::U8 pix[4];
+
+      assert(buflen >= 3);
+
+      pf.bufferFromRGB(pix, bufptr, 1);
+      pb->fillRect(pf, r, pix);
+    } else {
+      assert(buflen >= (size_t)pf.bpp/8);
+      pb->fillRect(pf, r, bufptr);
+    }
+    return;
+  }
+
+  // "JPEG" compression type.
+  if (comp_ctl == tightJpeg) {
+    rdr::U32 len;
+
+    int stride;
+    rdr::U8 *buf;
+
+    assert(buflen >= 4);
 
-  if (clientpf.equal(serverpf)) {
-    /* Decode directly into the framebuffer (fast path) */
+    memcpy(&len, bufptr, 4);
+    bufptr += 4;
+    buflen -= 4;
+
+    // We always use direct decoding with JPEG images
+    buf = pb->getBufferRW(r, &stride);
+    jd.decompress(bufptr, len, buf, stride, r, pb->getPF());
+    pb->commitBufferRW(r);
+    return;
+  }
+
+  // Quit on unsupported compression type.
+  assert(comp_ctl <= tightMaxSubencoding);
+
+  // "Basic" compression type.
+
+  int palSize = 0;
+  rdr::U8 palette[256 * 4];
+  bool useGradient = false;
+
+  if ((comp_ctl & tightExplicitFilter) != 0) {
+    rdr::U8 filterId;
+
+    assert(buflen >= 1);
+
+    filterId = *bufptr;
+    bufptr += 1;
+    buflen -= 1;
+
+    switch (filterId) {
+    case tightFilterPalette:
+      assert(buflen >= 1);
+
+      palSize = *bufptr + 1;
+      bufptr += 1;
+      buflen -= 1;
+
+      if (pf.is888()) {
+        rdr::U8 tightPalette[palSize * 3];
+
+        assert(buflen >= sizeof(tightPalette));
+
+        memcpy(tightPalette, bufptr, sizeof(tightPalette));
+        bufptr += sizeof(tightPalette);
+        buflen -= sizeof(tightPalette);
+
+        pf.bufferFromRGB(palette, tightPalette, palSize);
+      } else {
+        size_t len;
+
+        len = palSize * pf.bpp/8;
+
+        assert(buflen >= len);
+
+        memcpy(palette, bufptr, len);
+        bufptr += len;
+        buflen -= len;
+      }
+      break;
+    case tightFilterGradient:
+      useGradient = true;
+      break;
+    case tightFilterCopy:
+      break;
+    default:
+      assert(false);
+    }
+  }
+
+  // Determine if the data should be decompressed or just copied.
+  size_t rowSize, dataSize;
+  rdr::U8* netbuf;
+
+  netbuf = NULL;
+
+  if (palSize != 0) {
+    if (palSize <= 2)
+      rowSize = (r.width() + 7) / 8;
+    else
+      rowSize = r.width();
+  } else if (pf.is888()) {
+    rowSize = r.width() * 3;
+  } else {
+    rowSize = r.width() * pf.bpp/8;
+  }
+
+  dataSize = r.height() * rowSize;
+
+  if (dataSize < TIGHT_MIN_TO_COMPRESS)
+    assert(buflen >= dataSize);
+  else {
+    rdr::U32 len;
+    int streamId;
+    rdr::MemInStream* ms;
+
+    assert(buflen >= 4);
+
+    memcpy(&len, bufptr, 4);
+    bufptr += 4;
+    buflen -= 4;
+
+    assert(buflen >= len);
+
+    streamId = comp_ctl & 0x03;
+    ms = new rdr::MemInStream(bufptr, len);
+    zis[streamId].setUnderlying(ms, len);
+
+    // Allocate buffer and decompress the data
+    netbuf = new rdr::U8[dataSize];
+
+    zis[streamId].readBytes(netbuf, dataSize);
+    zis[streamId].reset();
+
+    delete ms;
+
+    bufptr = netbuf;
+    buflen = dataSize;
+  }
+
+  // Time to decode the actual data
+  bool directDecode;
+
+  rdr::U8* outbuf;
+  int stride;
+
+  if (pb->getPF().equal(pf)) {
+    // Decode directly into the framebuffer (fast path)
     directDecode = true;
   } else {
-    /* Decode into an intermediate buffer and use pixel translation */
+    // Decode into an intermediate buffer and use pixel translation
     directDecode = false;
   }
 
-  switch (serverpf.bpp) {
-  case 8:
-    tightDecode8 (r); break;
-  case 16:
-    tightDecode16(r); break;
-  case 32:
-    tightDecode32(r); break;
+  if (directDecode)
+    outbuf = pb->getBufferRW(r, &stride);
+  else {
+    outbuf = new rdr::U8[r.area() * pf.bpp/8];
+    stride = r.width();
   }
+
+  if (palSize == 0) {
+    // Truecolor data
+    if (useGradient) {
+      if (pf.is888())
+        FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
+      else {
+        switch (pf.bpp) {
+        case 8:
+          assert(false);
+          break;
+        case 16:
+          FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
+          break;
+        case 32:
+          FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
+          break;
+        }
+      }
+    } else {
+      // Copy
+      rdr::U8* ptr = outbuf;
+      const rdr::U8* srcPtr = bufptr;
+      int w = r.width();
+      int h = r.height();
+      if (pf.is888()) {
+        while (h > 0) {
+          pf.bufferFromRGB(ptr, srcPtr, w);
+          ptr += stride * pf.bpp/8;
+          srcPtr += w * 3;
+          h--;
+        }
+      } else {
+        while (h > 0) {
+          memcpy(ptr, srcPtr, w * pf.bpp/8);
+          ptr += stride * pf.bpp/8;
+          srcPtr += w * pf.bpp/8;
+          h--;
+        }
+      }
+    }
+  } else {
+    // Indexed color
+    switch (pf.bpp) {
+    case 8:
+      FilterPalette((const rdr::U8*)palette, palSize,
+                    bufptr, (rdr::U8*)outbuf, stride, r);
+      break;
+    case 16:
+      FilterPalette((const rdr::U16*)palette, palSize,
+                    bufptr, (rdr::U16*)outbuf, stride, r);
+      break;
+    case 32:
+      FilterPalette((const rdr::U32*)palette, palSize,
+                    bufptr, (rdr::U32*)outbuf, stride, r);
+      break;
+    }
+  }
+
+  if (directDecode)
+    pb->commitBufferRW(r);
+  else {
+    pb->imageRect(pf, r, outbuf);
+    delete [] outbuf;
+  }
+
+  delete [] netbuf;
 }
 
 rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
index 028514a522cab91dfc665ee781351bf2cc78ef44..18497d41b6f2b3bbc2649a6e91626c8850e41f2c 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2000-2003 Constantin Kaplinsky.  All Rights Reserved.
  * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * Copyright 2009-2015 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
@@ -31,39 +32,35 @@ namespace rfb {
     TightDecoder();
     virtual ~TightDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
 
   private:
     rdr::U32 readCompact(rdr::InStream* is);
 
-    void tightDecode8(const Rect& r);
-    void tightDecode16(const Rect& r);
-    void tightDecode32(const Rect& r);
+    void FilterGradient24(const rdr::U8* inbuf, const PixelFormat& pf,
+                          rdr::U32* outbuf, int stride, const Rect& r);
 
-    void DecompressJpegRect8(const Rect& r);
-    void DecompressJpegRect16(const Rect& r);
-    void DecompressJpegRect32(const Rect& r);
+    void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf,
+                        rdr::U16* outbuf, int stride, const Rect& r);
+    void FilterGradient(const rdr::U8* inbuf, const PixelFormat& pf,
+                        rdr::U32* outbuf, int stride, const Rect& r);
 
-    void FilterGradient8(rdr::U8 *netbuf, rdr::U8* buf, int stride, 
-                         const Rect& r);
-    void FilterGradient16(rdr::U8 *netbuf, rdr::U16* buf, int stride, 
-                          const Rect& r);
-    void FilterGradient24(rdr::U8 *netbuf, rdr::U32* buf, int stride, 
-                          const Rect& r);
-    void FilterGradient32(rdr::U8 *netbuf, rdr::U32* buf, int stride, 
-                          const Rect& r);
+    void FilterPalette(const rdr::U8* palette, int palSize,
+                       const rdr::U8* inbuf, rdr::U8* outbuf,
+                       int stride, const Rect& r);
+    void FilterPalette(const rdr::U16* palette, int palSize,
+                       const rdr::U8* inbuf, rdr::U16* outbuf,
+                       int stride, const Rect& r);
+    void FilterPalette(const rdr::U32* palette, int palSize,
+                       const rdr::U8* inbuf, rdr::U32* outbuf,
+                       int stride, const Rect& r);
 
-    void directFillRect8(const Rect& r, Pixel pix);
-    void directFillRect16(const Rect& r, Pixel pix);
-    void directFillRect32(const Rect& r, Pixel pix);
-
-    ModifiablePixelBuffer* pb;
-    rdr::InStream* is;
+  private:
     rdr::ZlibInStream zis[4];
     JpegDecompressor jd;
-    PixelFormat clientpf;
-    PixelFormat serverpf;
-    bool directDecode;
   };
 }
 
index 1328012d53dad4a25b51d26c6b79c3e33c7845bc..498152cf6cc51d0092b86a3bd803386837cfbf8a 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+
 #include <rdr/InStream.h>
+#include <rdr/MemInStream.h>
+#include <rdr/OutStream.h>
+
 #include <rfb/ConnParams.h>
 #include <rfb/PixelBuffer.h>
 #include <rfb/ZRLEDecoder.h>
@@ -67,13 +71,25 @@ ZRLEDecoder::~ZRLEDecoder()
 }
 
 void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
-                           const ConnParams& cp, ModifiablePixelBuffer* pb)
+                           const ConnParams& cp, rdr::OutStream* os)
+{
+  rdr::U32 len;
+
+  len = is->readU32();
+  os->writeU32(len);
+  os->copyBytes(is, len);
+}
+
+void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer,
+                             size_t buflen, const ConnParams& cp,
+                             ModifiablePixelBuffer* pb)
 {
+  rdr::MemInStream is(buffer, buflen);
   const rfb::PixelFormat& pf = cp.pf();
   rdr::U8* buf[64 * 64 * 4 * pf.bpp/8];
   switch (pf.bpp) {
-  case 8:  zrleDecode8 (r, is, &zis, (rdr::U8*) buf, pf, pb); break;
-  case 16: zrleDecode16(r, is, &zis, (rdr::U16*)buf, pf, pb); break;
+  case 8:  zrleDecode8 (r, &is, &zis, (rdr::U8*) buf, pf, pb); break;
+  case 16: zrleDecode16(r, &is, &zis, (rdr::U16*)buf, pf, pb); break;
   case 32:
     {
       Pixel maxPixel = pf.pixelFromRGB((rdr::U16)-1, (rdr::U16)-1, (rdr::U16)-1);
@@ -83,16 +99,16 @@ void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is,
       if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
           (fitsInMS3Bytes && pf.isBigEndian()))
       {
-        zrleDecode24A(r, is, &zis, (rdr::U32*)buf, pf, pb);
+        zrleDecode24A(r, &is, &zis, (rdr::U32*)buf, pf, pb);
       }
       else if ((fitsInLS3Bytes && pf.isBigEndian()) ||
                (fitsInMS3Bytes && pf.isLittleEndian()))
       {
-        zrleDecode24B(r, is, &zis, (rdr::U32*)buf, pf, pb);
+        zrleDecode24B(r, &is, &zis, (rdr::U32*)buf, pf, pb);
       }
       else
       {
-        zrleDecode32(r, is, &zis, (rdr::U32*)buf, pf, pb);
+        zrleDecode32(r, &is, &zis, (rdr::U32*)buf, pf, pb);
       }
       break;
     }
index 5ab80b48a94987dd95da6649f05309825ac7eb84..1e338510e244db5e834aea83dc46a7b036b8c768 100644 (file)
@@ -28,7 +28,10 @@ namespace rfb {
     ZRLEDecoder();
     virtual ~ZRLEDecoder();
     virtual void readRect(const Rect& r, rdr::InStream* is,
-                          const ConnParams& cp, ModifiablePixelBuffer* pb);
+                          const ConnParams& cp, rdr::OutStream* os);
+    virtual void decodeRect(const Rect& r, const void* buffer,
+                            size_t buflen, const ConnParams& cp,
+                            ModifiablePixelBuffer* pb);
   private:
     rdr::ZlibInStream zis;
   };
index 56ba11812a59c617dcc1a1064a32e632fdf7ec98..7affa157fe6c4d9400498c3bc5dfcbfd85ac71be 100644 (file)
@@ -37,12 +37,14 @@ 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,
-                     const PixelFormat& pf, ModifiablePixelBuffer* pb)
+static void HEXTILE_DECODE (const Rect& r, rdr::InStream* is,
+                            const PixelFormat& pf,
+                            ModifiablePixelBuffer* pb)
 {
   Rect t;
   PIXEL_T bg = 0;
   PIXEL_T fg = 0;
+  PIXEL_T buf[16 * 16 * 4];
 
   for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
@@ -55,20 +57,20 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf,
       int tileType = is->readU8();
 
       if (tileType & hextileRaw) {
-       is->readBytes(buf, t.area() * (BPP/8));
-       pb->imageRect(pf, t, buf);
-       continue;
+        is->readBytes(buf, t.area() * (BPP/8));
+        pb->imageRect(pf, t, buf);
+        continue;
       }
 
       if (tileType & hextileBgSpecified)
-       bg = is->READ_PIXEL();
+        bg = is->READ_PIXEL();
 
       int len = t.area();
-      PIXEL_T* ptr = (PIXEL_T*)buf;
+      PIXEL_T* ptr = buf;
       while (len-- > 0) *ptr++ = bg;
 
       if (tileType & hextileFgSpecified)
-       fg = is->READ_PIXEL();
+        fg = is->READ_PIXEL();
 
       if (tileType & hextileAnySubrects) {
         int nSubrects = is->readU8();
@@ -85,7 +87,7 @@ void HEXTILE_DECODE (const Rect& r, rdr::InStream* is, PIXEL_T* buf,
           int y = (xy & 15);
           int w = ((wh >> 4) & 15) + 1;
           int h = (wh & 15) + 1;
-          PIXEL_T* ptr = (PIXEL_T*)buf + y * t.width() + x;
+          PIXEL_T* ptr = buf + y * t.width() + x;
           int rowAdd = t.width() - w;
           while (h-- > 0) {
             int len = w;
index 88fda73b81657dcc4c8a39fba2a5372ce0c21123..b6e86ed5ea0bf3b3ea92e8f807d29ba8b21a920f 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2000-2003 Constantin Kaplinsky.  All Rights Reserved.
  * Copyright 2004-2005 Cendio AB.
+ * Copyright 2009-2015 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
 // This file is #included after having set the following macro:
 // BPP                - 8, 16 or 32
 
-#include <rdr/InStream.h>
-#include <rdr/ZlibInStream.h>
-#include <rfb/Exception.h>
-#include <rfb/TightConstants.h>
-
 namespace rfb {
 
 // CONCAT2E concatenates its arguments, expanding them if they are macros
@@ -39,242 +35,17 @@ namespace rfb {
 #endif
 
 #define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define READ_PIXEL CONCAT2E(readOpaque,BPP)
-#define TIGHT_DECODE TightDecoder::CONCAT2E(tightDecode,BPP)
-#define DECOMPRESS_JPEG_RECT TightDecoder::CONCAT2E(DecompressJpegRect,BPP)
-#define FILTER_GRADIENT TightDecoder::CONCAT2E(FilterGradient,BPP)
-
-#define TIGHT_MIN_TO_COMPRESS 12
-
-// Main function implementing Tight decoder
-
-void TIGHT_DECODE (const Rect& r)
-{
-  bool cutZeros = false;
-#if BPP == 32
-  if (serverpf.is888()) {
-    cutZeros = true;
-  } 
-#endif
-
-  rdr::U8 comp_ctl = is->readU8();
-
-  // Flush zlib streams if we are told by the server to do so.
-  for (int i = 0; i < 4; i++) {
-    if (comp_ctl & 1) {
-      zis[i].reset();
-    }
-    comp_ctl >>= 1;
-  }
-
-  // "Fill" compression type.
-  if (comp_ctl == tightFill) {
-    PIXEL_T pix;
-    if (cutZeros) {
-      rdr::U8 bytebuf[3];
-      is->readBytes(bytebuf, 3);
-      serverpf.bufferFromRGB((rdr::U8*)&pix, bytebuf, 1);
-    } else {
-      pix = is->READ_PIXEL();
-    }
-    pb->fillRect(serverpf, r, &pix);
-    return;
-  }
-
-  // "JPEG" compression type.
-  if (comp_ctl == tightJpeg) {
-    DECOMPRESS_JPEG_RECT(r);
-    return;
-  }
-
-  // Quit on unsupported compression type.
-  if (comp_ctl > tightMaxSubencoding) {
-    throw Exception("TightDecoder: bad subencoding value received");
-    return;
-  }
-
-  // "Basic" compression type.
-  int palSize = 0;
-  static PIXEL_T palette[256];
-  bool useGradient = false;
-
-  if ((comp_ctl & tightExplicitFilter) != 0) {
-    rdr::U8 filterId = is->readU8();
-
-    switch (filterId) {
-    case tightFilterPalette:
-      palSize = is->readU8() + 1;
-      if (cutZeros) {
-        rdr::U8 tightPalette[256 * 3];
-        is->readBytes(tightPalette, palSize * 3);
-        serverpf.bufferFromRGB((rdr::U8*)palette, tightPalette, palSize);
-      } else {
-        is->readBytes(palette, palSize * sizeof(PIXEL_T));
-      }
-      break;
-    case tightFilterGradient:
-      useGradient = true;
-      break;
-    case tightFilterCopy:
-      break;
-    default:
-      throw Exception("TightDecoder: unknown filter code received");
-      return;
-    }
-  }
-
-  int bppp = BPP;
-  if (palSize != 0) {
-    bppp = (palSize <= 2) ? 1 : 8;
-  } else if (cutZeros) {
-    bppp = 24;
-  }
-
-  // Determine if the data should be decompressed or just copied.
-  int rowSize = (r.width() * bppp + 7) / 8;
-  int dataSize = r.height() * rowSize;
-  int streamId = -1;
-  rdr::InStream *input;
-  if (dataSize < TIGHT_MIN_TO_COMPRESS) {
-    input = is;
-  } else {
-    int length = readCompact(is);
-    streamId = comp_ctl & 0x03;
-    zis[streamId].setUnderlying(is, length);
-    input = &zis[streamId];
-  }
-
-  // Allocate netbuf and read in data
-  rdr::U8 *netbuf = new rdr::U8[dataSize];
-  if (!netbuf) {
-    throw Exception("rfb::TightDecoder::tightDecode unable to allocate buffer");
-  }
-  input->readBytes(netbuf, dataSize);
-
-  PIXEL_T *buf;
-  int stride = r.width();
-  if (directDecode)
-    buf = (PIXEL_T *)pb->getBufferRW(r, &stride);
-  else
-    buf = new PIXEL_T[r.area()];
-
-  if (palSize == 0) {
-    // Truecolor data
-    if (useGradient) {
-#if BPP == 32
-      if (cutZeros) {
-        FilterGradient24(netbuf, buf, stride, r);
-      } else 
-#endif
-      {
-        FILTER_GRADIENT(netbuf, buf, stride, r);
-      }
-    } else {
-      // Copy
-      int h = r.height();
-      PIXEL_T *ptr = buf;
-      rdr::U8 *srcPtr = netbuf;
-      int w = r.width();
-      if (cutZeros) {
-        while (h > 0) {
-          serverpf.bufferFromRGB((rdr::U8*)ptr, srcPtr, w);
-          ptr += stride;
-          srcPtr += w * 3;
-          h--;
-        }
-      } else {
-        while (h > 0) {
-          memcpy(ptr, srcPtr, w * sizeof(PIXEL_T));
-          ptr += stride;
-          srcPtr += w * sizeof(PIXEL_T);
-          h--;
-        }
-      }
-    }
-  } else {
-    // Indexed color
-    int x, h = r.height(), w = r.width(), b, pad = stride - w;
-    PIXEL_T *ptr = buf;
-    rdr::U8 bits, *srcPtr = netbuf;
-    if (palSize <= 2) {
-      // 2-color palette
-      while (h > 0) {
-        for (x = 0; x < w / 8; x++) {
-          bits = *srcPtr++;
-          for (b = 7; b >= 0; b--) {
-            *ptr++ = palette[bits >> b & 1];
-          }
-        }
-        if (w % 8 != 0) {
-          bits = *srcPtr++;
-          for (b = 7; b >= 8 - w % 8; b--) {
-            *ptr++ = palette[bits >> b & 1];
-          }
-        }
-        ptr += pad;
-        h--;
-      }
-    } else {
-      // 256-color palette
-      while (h > 0) {
-        PIXEL_T *endOfRow = ptr + w;
-        while (ptr < endOfRow) {
-          *ptr++ = palette[*srcPtr++];
-        }
-        ptr += pad;
-        h--;
-      }
-    }
-  }
-
-  if (directDecode)
-    pb->commitBufferRW(r);
-  else {
-    pb->imageRect(serverpf, r, buf);
-    delete [] buf;
-  }
-
-  delete [] netbuf;
-
-  if (streamId != -1) {
-    zis[streamId].reset();
-  }
-}
-
-void
-DECOMPRESS_JPEG_RECT(const Rect& r)
-{
-  // Read length
-  int compressedLen = readCompact(is);
-  if (compressedLen <= 0) {
-      throw Exception("Incorrect data received from the server.\n");
-  }
-
-  // Allocate netbuf and read in data
-  rdr::U8* netbuf = new rdr::U8[compressedLen];
-  if (!netbuf) {
-    throw Exception("rfb::TightDecoder::DecompressJpegRect unable to allocate buffer");
-  }
-  is->readBytes(netbuf, compressedLen);
-
-  // We always use direct decoding with JPEG images
-  int stride;
-  rdr::U8 *buf = pb->getBufferRW(r, &stride);
-  jd.decompress(netbuf, compressedLen, buf, stride, r, clientpf);
-  pb->commitBufferRW(r);
-
-  delete [] netbuf;
-}
 
 #if BPP == 32
 
 void
-TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
-                               const Rect& r)
+TightDecoder::FilterGradient24(const rdr::U8 *inbuf,
+                               const PixelFormat& pf, PIXEL_T* outbuf,
+                               int stride, const Rect& r)
 {
   int x, y, c;
-  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
-  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
+  rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+  rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
   rdr::U8 pix[3]; 
   int est[3]; 
 
@@ -287,10 +58,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
   for (y = 0; y < rectHeight; y++) {
     /* First pixel in a row */
     for (c = 0; c < 3; c++) {
-      pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+      pix[c] = inbuf[y*rectWidth*3+c] + prevRow[c];
       thisRow[c] = pix[c];
     }
-    serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride], pix, 1);
+    pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
 
     /* Remaining pixels of a row */
     for (x = 1; x < rectWidth; x++) {
@@ -301,10 +72,10 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
         } else if (est[c] < 0) {
           est[c] = 0;
         }
-        pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+        pix[c] = inbuf[(y*rectWidth+x)*3+c] + est[c];
         thisRow[x*3+c] = pix[c];
       }
-      serverpf.bufferFromRGB((rdr::U8*)&buf[y*stride+x], pix, 1);
+      pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
     }
 
     memcpy(prevRow, thisRow, sizeof(prevRow));
@@ -313,12 +84,15 @@ TightDecoder::FilterGradient24(rdr::U8 *netbuf, PIXEL_T* buf, int stride,
 
 #endif
 
-void
-FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r)
+#if BPP != 8
+
+void TightDecoder::FilterGradient(const rdr::U8* inbuf,
+                                  const PixelFormat& pf, PIXEL_T* outbuf,
+                                  int stride, const Rect& r)
 {
   int x, y, c;
-  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
-  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*sizeof(PIXEL_T)];
+  static rdr::U8 prevRow[TIGHT_MAX_WIDTH*3];
+  static rdr::U8 thisRow[TIGHT_MAX_WIDTH*3];
   rdr::U8 pix[3]; 
   int est[3]; 
 
@@ -330,13 +104,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);
+    pf.rgbFromBuffer(pix, &inbuf[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);
+    pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride], pix, 1);
 
     /* Remaining pixels of a row */
     for (x = 1; x < rectWidth; x++) {
@@ -349,23 +123,60 @@ FILTER_GRADIENT(rdr::U8 *netbuf, PIXEL_T* buf, int stride, const Rect& r)
         }
       }
 
-      serverpf.rgbFromBuffer(pix, (rdr::U8*)&netbuf[y*rectWidth+x], 1);
+      pf.rgbFromBuffer(pix, &inbuf[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);
+      pf.bufferFromRGB((rdr::U8*)&outbuf[y*stride+x], pix, 1);
     }
 
     memcpy(prevRow, thisRow, sizeof(prevRow));
   }
 }
 
-#undef TIGHT_MIN_TO_COMPRESS
-#undef FILTER_GRADIENT
-#undef DECOMPRESS_JPEG_RECT
-#undef TIGHT_DECODE
-#undef READ_PIXEL
+#endif
+
+void TightDecoder::FilterPalette(const PIXEL_T* palette, int palSize,
+                                 const rdr::U8* inbuf, PIXEL_T* outbuf,
+                                 int stride, const Rect& r)
+{
+  // Indexed color
+  int x, h = r.height(), w = r.width(), b, pad = stride - w;
+  PIXEL_T* ptr = outbuf;
+  rdr::U8 bits;
+  const rdr::U8* srcPtr = inbuf;
+  if (palSize <= 2) {
+    // 2-color palette
+    while (h > 0) {
+      for (x = 0; x < w / 8; x++) {
+        bits = *srcPtr++;
+        for (b = 7; b >= 0; b--) {
+          *ptr++ = palette[bits >> b & 1];
+        }
+      }
+      if (w % 8 != 0) {
+        bits = *srcPtr++;
+        for (b = 7; b >= 8 - w % 8; b--) {
+          *ptr++ = palette[bits >> b & 1];
+        }
+      }
+      ptr += pad;
+      h--;
+    }
+  } else {
+    // 256-color palette
+    while (h > 0) {
+      PIXEL_T *endOfRow = ptr + w;
+      while (ptr < endOfRow) {
+        *ptr++ = palette[*srcPtr++];
+      }
+      ptr += pad;
+      h--;
+    }
+  }
+}
+
 #undef PIXEL_T
 }