Use PixelBuffer objects as the interface for encoders and decoders

This avoid a lot of unnecessary middle men. This also pushes the
responsibility for pixel format conversion into the encoders and
decoders. The new bufferFromBuffer() is used for direct conversion,
rather than PixelTransformer/TransImageGetter.
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index c78bb89..305eddc 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -263,7 +263,6 @@
   // This initial update request is a bit of a corner case, so we need
   // to help out setting the correct format here.
   assert(pendingPFChange);
-  desktop->setServerPF(pendingPF);
   cp.setPF(pendingPF);
   pendingPFChange = false;
 }
@@ -330,7 +329,6 @@
   // A format change has been scheduled and we are now past the update
   // with the old format. Time to active the new one.
   if (pendingPFChange) {
-    desktop->setServerPF(pendingPF);
     cp.setPF(pendingPF);
     pendingPFChange = false;
   }
@@ -405,26 +403,11 @@
       throw Exception("Unknown rect encoding");
     }
   }
-  decoders[encoding]->readRect(r, this);
+  decoders[encoding]->readRect(r, desktop->getFramebuffer());
 
   sock->inStream().stopTiming();
 }
 
-void CConn::fillRect(const rfb::Rect& r, rfb::Pixel p)
-{
-  desktop->fillRect(r,p);
-}
-
-void CConn::imageRect(const rfb::Rect& r, void* p)
-{
-  desktop->imageRect(r,p);
-}
-
-void CConn::copyRect(const rfb::Rect& r, int sx, int sy)
-{
-  desktop->copyRect(r,sx,sy);
-}
-
 void CConn::setCursor(int width, int height, const Point& hotspot,
                       void* data, void* mask)
 {
@@ -461,18 +444,10 @@
 
     pf.read(&memStream);
 
-    desktop->setServerPF(pf);
     cp.setPF(pf);
   }
 }
 
-rdr::U8* CConn::getRawBufferRW(const rfb::Rect& r, int* stride) {
-  return desktop->getBufferRW(r, stride);
-}
-void CConn::releaseRawBuffer(const rfb::Rect& r) {
-  desktop->commitBufferRW(r);
-}
-
 
 ////////////////////// Internal methods //////////////////////
 
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index f7f560b..709ca2f 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -64,18 +64,8 @@
 
   void framebufferUpdateStart();
   void framebufferUpdateEnd();
-
   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);
-  void copyRect(const rfb::Rect& r, int sx, int sy);
-
-  rdr::U8* getRawBufferRW(const rfb::Rect& r, int* stride);
-  void releaseRawBuffer(const rfb::Rect& r);
-
-  const rfb::PixelFormat &getPreferredPF() { return fullColourPF; }
-
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index a64f02a..d57d57a 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -193,12 +193,6 @@
 }
 
 
-void DesktopWindow::setServerPF(const rfb::PixelFormat& pf)
-{
-  viewport->setServerPF(pf);
-}
-
-
 const rfb::PixelFormat &DesktopWindow::getPreferredPF()
 {
   return viewport->getPreferredPF();
@@ -216,24 +210,9 @@
 }
 
 
-void DesktopWindow::fillRect(const rfb::Rect& r, rfb::Pixel pix) {
-  viewport->fillRect(r, pix);
-}
-
-void DesktopWindow::imageRect(const rfb::Rect& r, void* pixels) {
-  viewport->imageRect(r, pixels);
-}
-
-void DesktopWindow::copyRect(const rfb::Rect& r, int srcX, int srcY) {
-  viewport->copyRect(r, srcX, srcY);
-}
-
-rdr::U8* DesktopWindow::getBufferRW(const rfb::Rect& r, int* stride) {
-  return viewport->getBufferRW(r, stride);
-}
-
-void DesktopWindow::commitBufferRW(const rfb::Rect& r) {
-  viewport->commitBufferRW(r);
+rfb::ModifiablePixelBuffer* DesktopWindow::getFramebuffer(void)
+{
+  return viewport->getFramebuffer();
 }
 
 
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index 83a8c76..8b91450 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -27,6 +27,8 @@
 
 #include <FL/Fl_Window.H>
 
+namespace rfb { class ModifiablePixelBuffer; }
+
 class CConn;
 class Viewport;
 
@@ -39,26 +41,22 @@
                 const rfb::PixelFormat& serverPF, CConn* cc_);
   ~DesktopWindow();
 
-  // PixelFormat of incoming write operations
-  void setServerPF(const rfb::PixelFormat& pf);
   // Most efficient format (from DesktopWindow's point of view)
   const rfb::PixelFormat &getPreferredPF();
 
   // Flush updates to screen
   void updateWindow();
 
-  // Methods forwarded from CConn
+  // Updated session title
   void setName(const char *name);
 
-  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);
+  // Return a pointer to the framebuffer for decoders to write into
+  rfb::ModifiablePixelBuffer* getFramebuffer(void);
 
-  rdr::U8* getBufferRW(const rfb::Rect& r, int* stride);
-  void commitBufferRW(const rfb::Rect& r);
-
+  // Resize the current framebuffer, but retain the contents
   void resizeFramebuffer(int new_w, int new_h);
 
+  // New image for the locally rendered cursor
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index ced0446..5bd50d2 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -24,3 +24,19 @@
   FullFramePixelBuffer(pf, width, height, data, stride)
 {
 }
+
+void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r)
+{
+  FullFramePixelBuffer::commitBufferRW(r);
+  damage.assign_union(rfb::Region(r));
+}
+
+rfb::Rect PlatformPixelBuffer::getDamage(void)
+{
+  rfb::Rect r;
+
+  r = damage.get_bounding_rect();
+  damage.clear();
+
+  return r;
+}
diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h
index 03842ac..21b93be 100644
--- a/vncviewer/PlatformPixelBuffer.h
+++ b/vncviewer/PlatformPixelBuffer.h
@@ -20,14 +20,20 @@
 #define __PLATFORMPIXELBUFFER_H__
 
 #include <rfb/PixelBuffer.h>
+#include <rfb/Region.h>
 
 class PlatformPixelBuffer: public rfb::FullFramePixelBuffer {
 public:
   PlatformPixelBuffer(const rfb::PixelFormat& pf, int width, int height,
                       rdr::U8* data, int stride);
 
-  virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0;
+  virtual void commitBufferRW(const rfb::Rect& r);
 
+  virtual void draw(int src_x, int src_y, int x, int y, int w, int h) = 0;
+  rfb::Rect getDamage(void);
+
+protected:
+  rfb::Region damage;
 };
 
 #endif
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 70964b7..cd8b1bc 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -27,7 +27,6 @@
 
 #include <rfb/CMsgWriter.h>
 #include <rfb/LogWriter.h>
-#include <rfb/PixelTransformer.h>
 
 // FLTK can pull in the X11 headers on some systems
 #ifndef XK_VoidSymbol
@@ -84,7 +83,7 @@
        ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS };
 
 Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_)
-  : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL), pixelTrans(NULL),
+  : Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL),
     lastPointerPos(0, 0), lastButtonMask(0),
     cursor(NULL), menuCtrlKey(false), menuAltKey(false)
 {
@@ -101,8 +100,6 @@
   frameBuffer = createFramebuffer(w, h);
   assert(frameBuffer);
 
-  setServerPF(serverPF);
-
   contextMenu = new Fl_Menu_Button(0, 0, 0, 0);
   // Setting box type to FL_NO_BOX prevents it from trying to draw the
   // button component (which we don't want)
@@ -130,7 +127,6 @@
 {
   // Unregister all timeouts in case they get a change tro trigger
   // again later when this object is already gone.
-  Fl::remove_timeout(handleUpdateTimeout, this);
   Fl::remove_timeout(handlePointerTimeout, this);
 
 #ifdef HAVE_FLTK_CLIPBOARD
@@ -141,9 +137,6 @@
 
   delete frameBuffer;
 
-  if (pixelTrans)
-    delete pixelTrans;
-
   if (cursor) {
     if (!cursor->alloc_array)
       delete [] cursor->array;
@@ -155,40 +148,6 @@
 }
 
 
-void Viewport::setServerPF(const rfb::PixelFormat& pf)
-{
-  if (pixelTrans)
-    delete pixelTrans;
-  pixelTrans = NULL;
-
-  if (pf.equal(getPreferredPF()))
-    return;
-
-  pixelTrans = new PixelTransformer();
-
-  // FIXME: This is an ugly (temporary) hack to get around a corner
-  //        case during startup. The conversion routines cannot handle
-  //        non-native source formats, and we can sometimes get that
-  //        as the initial format. We will switch to a better format
-  //        before getting any updates, but we need something for now.
-  //        Our old client used something completely bogus and just
-  //        hoped nothing would ever go wrong. We try to at least match
-  //        the pixel size so that we don't get any memory access issues
-  //        should a stray update appear.
-  static rdr::U32 endianTest = 1;
-  static bool nativeBigEndian = *(rdr::U8*)(&endianTest) != 1;
-  if ((pf.bpp > 8) && (pf.bigEndian != nativeBigEndian)) {
-    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, getPreferredPF());
-    return;
-  }
-
-  pixelTrans->init(pf, getPreferredPF());
-}
-
-
 const rfb::PixelFormat &Viewport::getPreferredPF()
 {
   return frameBuffer->getPF();
@@ -197,65 +156,21 @@
 
 // Copy the areas of the framebuffer that have been changed (damaged)
 // to the displayed window.
+// FIXME: Make sure this gets called on slow updates
 
 void Viewport::updateWindow()
 {
   Rect r;
 
-  Fl::remove_timeout(handleUpdateTimeout, this);
-
-  r = damage.get_bounding_rect();
-  Fl_Widget::damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
-
-  damage.clear();
+  r = frameBuffer->getDamage();
+  damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
 }
 
-void Viewport::fillRect(const rfb::Rect& r, rfb::Pixel pix) {
-  if (pixelTrans) {
-    rfb::Pixel pix2;
-    pixelTrans->translatePixels(&pix, &pix2, 1);
-    pix = pix2;
-  }
-
-  frameBuffer->fillRect(r, pix);
-  damageRect(r);
+rfb::ModifiablePixelBuffer* Viewport::getFramebuffer(void)
+{
+  return frameBuffer;
 }
 
-void Viewport::imageRect(const rfb::Rect& r, void* pixels) {
-  if (pixelTrans) {
-    rdr::U8* buffer;
-    int stride;
-    buffer = frameBuffer->getBufferRW(r, &stride);
-    pixelTrans->translateRect(pixels, r.width(),
-                              rfb::Rect(0, 0, r.width(), r.height()),
-                              buffer, stride, rfb::Point(0, 0));
-    frameBuffer->commitBufferRW(r);
-  } else {
-    frameBuffer->imageRect(r, pixels);
-  }
-  damageRect(r);
-}
-
-void Viewport::copyRect(const rfb::Rect& r, int srcX, int srcY) {
-  frameBuffer->copyRect(r, rfb::Point(r.tl.x-srcX, r.tl.y-srcY));
-  damageRect(r);
-}
-
-rdr::U8* Viewport::getBufferRW(const rfb::Rect& r, int* stride) {
-  return frameBuffer->getBufferRW(r, stride);
-}
-
-void Viewport::commitBufferRW(const rfb::Rect& r) {
-  frameBuffer->commitBufferRW(r);
-  damageRect(r);
-}
-
-void Viewport::damageRect(const rfb::Rect& r) {
-  damage.assign_union(rfb::Region(r));
-  if (!Fl::has_timeout(handleUpdateTimeout, this))
-    Fl::add_timeout(0.500, handleUpdateTimeout, this);
-};
-
 #ifdef HAVE_FLTK_CURSOR
 static const char * dotcursor_xpm[] = {
   "5 5 2 1",
@@ -303,10 +218,7 @@
 
       const PixelFormat *pf;
       
-      if (pixelTrans)
-        pf = &pixelTrans->getInPF();
-      else
-        pf = &frameBuffer->getPF();
+      pf = &cc->cp.pf();
 
       i = (U8*)data;
       o = buffer;
@@ -530,16 +442,6 @@
 }
 
 
-void Viewport::handleUpdateTimeout(void *data)
-{
-  Viewport *self = (Viewport *)data;
-
-  assert(self);
-
-  self->updateWindow();
-}
-
-
 void Viewport::handleClipboardChange(int source, void *data)
 {
   Viewport *self = (Viewport *)data;
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index e112efd..0523cd1 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -22,10 +22,9 @@
 
 #include <map>
 
-#include <FL/Fl_Widget.H>
+namespace rfb { class ModifiablePixelBuffer; }
 
-#include <rfb/Region.h>
-#include <rfb/Pixel.h>
+#include <FL/Fl_Widget.H>
 
 class Fl_Menu_Button;
 class Fl_RGB_Image;
@@ -41,23 +40,16 @@
   Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_);
   ~Viewport();
 
-  // PixelFormat of incoming write operations
-  void setServerPF(const rfb::PixelFormat& pf);
   // Most efficient format (from Viewport's point of view)
   const rfb::PixelFormat &getPreferredPF();
 
   // Flush updates to screen
   void updateWindow();
 
-  // Methods forwarded from CConn
+  // Return a pointer to the framebuffer for decoders to write into
+  rfb::ModifiablePixelBuffer* getFramebuffer(void);
 
-  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);
-
-  rdr::U8* getBufferRW(const rfb::Rect& r, int* stride);
-  void commitBufferRW(const rfb::Rect& r);
-
+  // New image for the locally rendered cursor
   void setCursor(int width, int height, const rfb::Point& hotspot,
                  void* data, void* mask);
 
@@ -71,12 +63,8 @@
 
 private:
 
-  void damageRect(const rfb::Rect& r);
-
   PlatformPixelBuffer* createFramebuffer(int w, int h);
 
-  static void handleUpdateTimeout(void *data);
-
   static void handleClipboardChange(int source, void *data);
 
   void handlePointerEvent(const rfb::Point& pos, int buttonMask);
@@ -96,8 +84,6 @@
   CConn* cc;
 
   PlatformPixelBuffer* frameBuffer;
-  rfb::PixelTransformer *pixelTrans;
-  rfb::Region damage;
 
   rfb::Point lastPointerPos;
   int lastButtonMask;