Move image encoding logic into a central EncodeManager class

This allows us to apply a lot more server logic
independently of which encoder is in use.

Most of this class are things moved over from the
Tight encoder.
diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx
index 6e23ad3..60a0663 100644
--- a/common/rfb/RREEncoder.cxx
+++ b/common/rfb/RREEncoder.cxx
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2014 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,10 +18,10 @@
  */
 #include <rdr/OutStream.h>
 #include <rfb/encodings.h>
-#include <rfb/SMsgWriter.h>
 #include <rfb/SConnection.h>
 #include <rfb/PixelFormat.h>
 #include <rfb/PixelBuffer.h>
+#include <rfb/Palette.h>
 #include <rfb/RREEncoder.h>
 
 using namespace rfb;
@@ -35,7 +36,8 @@
 #include <rfb/rreEncode.h>
 #undef BPP
 
-RREEncoder::RREEncoder(SConnection* conn) : RawEncoder(conn)
+RREEncoder::RREEncoder(SConnection* conn) :
+  Encoder(conn, encodingRRE, EncoderPlain, -1)
 {
 }
 
@@ -43,30 +45,71 @@
 {
 }
 
-void RREEncoder::writeRect(const Rect& r, PixelBuffer* pb)
+bool RREEncoder::isSupported()
 {
-  int w = r.width();
-  int h = r.height();
-  rdr::U8* imageBuf = conn->writer()->getImageBuf(w*h);
-  pb->getImage(conn->cp.pf(), imageBuf, r);
+  return conn->cp.supportsEncoding(encodingRRE);
+}
 
-  mos.clear();
+void RREEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
+{
+  rdr::U8* imageBuf;
+  int stride;
+  rdr::U32 bg;
 
-  int nSubrects = -1;
-  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) {
-    RawEncoder::writeRect(r, pb);
+  int w = pb->width();
+  int h = pb->height();
+
+  if (palette.size() == 1) {
+    Encoder::writeSolidRect(pb, palette);
     return;
   }
 
-  conn->writer()->startRect(r, encodingRRE);
+  // We have to have our own copy of the data as we modify it as
+  // we find subrects.
+  bufferCopy.setPF(pb->getPF());
+  bufferCopy.setSize(w, h);
+
+  imageBuf = bufferCopy.getBufferRW(pb->getRect(), &stride);
+  pb->getImage(imageBuf, pb->getRect());
+
+  if (palette.size() > 0)
+    bg = palette.getColour(0);
+  else {
+    // Some crazy person is using this encoder for high colour
+    // data. Just pick the first pixel as the background colour.
+    bg = 0;
+    memcpy(&bg, imageBuf, pb->getPF().bpp/8);
+  }
+
+  int nSubrects = -1;
+  switch (pb->getPF().bpp) {
+  case 8:
+    nSubrects = rreEncode8((rdr::U8*)imageBuf, w, h, &mos, bg);
+    break;
+  case 16:
+    nSubrects = rreEncode16((rdr::U16*)imageBuf, w, h, &mos, bg);
+    break;
+  case 32:
+    nSubrects = rreEncode32((rdr::U32*)imageBuf, w, h, &mos, bg);
+    break;
+  }
+
+  bufferCopy.commitBufferRW(pb->getRect());
+
   rdr::OutStream* os = conn->getOutStream();
   os->writeU32(nSubrects);
   os->writeBytes(mos.data(), mos.length());
-  conn->writer()->endRect();
+  mos.clear();
+}
+
+void RREEncoder::writeSolidRect(int width, int height,
+                                const PixelFormat& pf,
+                                const rdr::U8* colour)
+{
+  rdr::OutStream* os;
+
+  os = conn->getOutStream();
+
+  os->writeU32(0);
+  os->writeBytes(colour, pf.bpp/8);
 }