Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@589 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
new file mode 100644
index 0000000..ce3d68a
--- /dev/null
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -0,0 +1,137 @@
+/* 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.
+ */
+#include <stdio.h>
+#include <vector>
+#include <rdr/types.h>
+#include <rfb/Exception.h>
+#include <rfb/ComparingUpdateTracker.h>
+
+using namespace rfb;
+
+ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
+  : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
+{
+    changed.assign_union(fb->getRect());
+}
+
+ComparingUpdateTracker::~ComparingUpdateTracker()
+{
+}
+
+
+#define BLOCK_SIZE 16
+
+void ComparingUpdateTracker::compare()
+{
+  std::vector<Rect> rects;
+  std::vector<Rect>::iterator i;
+
+  if (firstCompare) {
+    // NB: We leave the change region untouched on this iteration,
+    // since in effect the entire framebuffer has changed.
+    oldFb.setSize(fb->width(), fb->height());
+    for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
+      Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
+      int srcStride;
+      const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
+      oldFb.imageRect(pos, srcData, srcStride);
+    }
+    firstCompare = false;
+  } else {
+    copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
+    for (i = rects.begin(); i != rects.end(); i++)
+      oldFb.copyRect(*i, copy_delta);
+
+    Region to_check = changed.union_(copied);
+    to_check.get_rects(&rects);
+
+    Region newChanged;
+    for (i = rects.begin(); i != rects.end(); i++)
+      compareRect(*i, &newChanged);
+
+    copied.assign_subtract(newChanged);
+    changed = newChanged;
+  }
+}
+
+void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
+{
+  if (!r.enclosed_by(fb->getRect())) {
+    fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
+    return;
+  }
+
+  int bytesPerPixel = fb->getPF().bpp/8;
+  int oldStride;
+  rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
+  int oldStrideBytes = oldStride * bytesPerPixel;
+
+  std::vector<Rect> changedBlocks;
+
+  for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
+  {
+    // Get a strip of the source buffer
+    Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
+    int fbStride;
+    const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
+    int newStrideBytes = fbStride * bytesPerPixel;
+
+    rdr::U8* oldBlockPtr = oldData;
+    int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
+
+    for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
+    {
+      const rdr::U8* newPtr = newBlockPtr;
+      rdr::U8* oldPtr = oldBlockPtr;
+
+      int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
+      int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
+
+      for (int y = blockTop; y < blockBottom; y++)
+      {
+        if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
+        {
+          // A block has changed - copy the remainder to the oldFb
+          changedBlocks.push_back(Rect(blockLeft, blockTop,
+                                       blockRight, blockBottom));
+          for (int y2 = y; y2 < blockBottom; y2++)
+          {
+            memcpy(oldPtr, newPtr, blockWidthInBytes);
+            newPtr += newStrideBytes;
+            oldPtr += oldStrideBytes;
+          }
+          break;
+        }
+
+        newPtr += newStrideBytes;
+        oldPtr += oldStrideBytes;
+      }
+
+      oldBlockPtr += blockWidthInBytes;
+      newBlockPtr += blockWidthInBytes;
+    }
+
+    oldData += oldStrideBytes * BLOCK_SIZE;
+  }
+
+  if (!changedBlocks.empty()) {
+    Region temp;
+    temp.setOrderedRects(changedBlocks);
+    newChanged->assign_union(temp);
+  }
+}