summaryrefslogtreecommitdiffstats
path: root/common/rfb/Region.cxx
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-25 05:01:55 +0000
commita2adc8d4cfdf7336ce9192414c5e775224742a97 (patch)
tree0fc9f229bd40a2de342d91338798033da8ebd7bc /common/rfb/Region.cxx
parent4fc2026b9595e9425f50616d18781995aebe495b (diff)
downloadtigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.tar.gz
tigervnc-a2adc8d4cfdf7336ce9192414c5e775224742a97.zip
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
Diffstat (limited to 'common/rfb/Region.cxx')
-rw-r--r--common/rfb/Region.cxx248
1 files changed, 248 insertions, 0 deletions
diff --git a/common/rfb/Region.cxx b/common/rfb/Region.cxx
new file mode 100644
index 00000000..7965a6c4
--- /dev/null
+++ b/common/rfb/Region.cxx
@@ -0,0 +1,248 @@
+/* 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.
+ */
+
+// Cross-platform Region class based on the X11 region implementation. Note
+// that for efficiency this code manipulates the Xlib region structure
+// directly. Apart from the layout of the structure, there is one other key
+// assumption made: a Region returned from XCreateRegion must always have its
+// rects member allocated so that there is space for at least one rectangle.
+//
+
+#include <rfb/Region.h>
+#include <Xregion/Xregion.h>
+#include <Xregion/region.h>
+#include <assert.h>
+#include <stdio.h>
+
+// A _RectRegion must never be passed as a return parameter to the Xlib region
+// operations. This is because for efficiency its "rects" member has not been
+// allocated with Xmalloc. It is however safe to pass it as an input
+// parameter.
+
+class _RectRegion {
+public:
+ _RectRegion(const rfb::Rect& r) {
+ region.rects = &region.extents;
+ region.numRects = 1;
+ region.extents.x1 = r.tl.x;
+ region.extents.y1 = r.tl.y;
+ region.extents.x2 = r.br.x;
+ region.extents.y2 = r.br.y;
+ region.size = 1;
+ if (r.is_empty())
+ region.numRects = 0;
+ }
+ REGION region;
+};
+
+
+rfb::Region::Region() {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+}
+
+rfb::Region::Region(const Rect& r) {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+ reset(r);
+}
+
+rfb::Region::Region(const rfb::Region& r) {
+ xrgn = XCreateRegion();
+ assert(xrgn);
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region::~Region() {
+ XDestroyRegion(xrgn);
+}
+
+rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
+ clear();
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+ return *this;
+}
+
+void rfb::Region::clear() {
+ xrgn->numRects = 0;
+ xrgn->extents.x1 = 0;
+ xrgn->extents.y1 = 0;
+ xrgn->extents.x2 = 0;
+ xrgn->extents.y2 = 0;
+}
+
+void rfb::Region::reset(const Rect& r) {
+ if (r.is_empty()) {
+ clear();
+ } else {
+ xrgn->numRects = 1;
+ xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
+ xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
+ xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
+ xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
+ }
+}
+
+void rfb::Region::translate(const Point& delta) {
+ XOffsetRegion(xrgn, delta.x, delta.y);
+}
+
+void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
+ clear();
+ std::vector<Rect>::const_iterator i;
+ for (i=rects.begin(); i != rects.end(); i++) {
+ _RectRegion rr(*i);
+ XUnionRegion(xrgn, &rr.region, xrgn);
+ }
+}
+
+void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
+ int nRects, const ShortRect* rects)
+{
+ if (xrgn->size < nRects)
+ {
+ BOX* prevRects = xrgn->rects;
+ xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
+ if (!xrgn->rects) {
+ fprintf(stderr,"Xrealloc failed\n");
+ Xfree(prevRects);
+ return;
+ }
+ xrgn->size = nRects;
+ }
+
+ xrgn->numRects = nRects;
+ xrgn->extents.x1 = extents->x1;
+ xrgn->extents.y1 = extents->y1;
+ xrgn->extents.x2 = extents->x2;
+ xrgn->extents.y2 = extents->y2;
+ for (int i = 0; i < nRects; i++) {
+ xrgn->rects[i].x1 = rects[i].x1;
+ xrgn->rects[i].y1 = rects[i].y1;
+ xrgn->rects[i].x2 = rects[i].x2;
+ xrgn->rects[i].y2 = rects[i].y2;
+ }
+}
+
+void rfb::Region::copyFrom(const rfb::Region& r) {
+ XUnionRegion(r.xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_intersect(const rfb::Region& r) {
+ XIntersectRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_union(const rfb::Region& r) {
+ XUnionRegion(xrgn, r.xrgn, xrgn);
+}
+
+void rfb::Region::assign_subtract(const rfb::Region& r) {
+ XSubtractRegion(xrgn, r.xrgn, xrgn);
+}
+
+rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
+ rfb::Region ret;
+ XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+rfb::Region rfb::Region::union_(const rfb::Region& r) const {
+ rfb::Region ret;
+ XUnionRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
+ rfb::Region ret;
+ XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
+ return ret;
+}
+
+bool rfb::Region::equals(const rfb::Region& r) const {
+ return XEqualRegion(xrgn, r.xrgn);
+}
+
+int rfb::Region::numRects() const {
+ return xrgn->numRects;
+}
+
+bool rfb::Region::get_rects(std::vector<Rect>* rects,
+ bool left2right, bool topdown, int maxArea) const
+{
+ int nRects = xrgn->numRects;
+ int xInc = left2right ? 1 : -1;
+ int yInc = topdown ? 1 : -1;
+ int i = topdown ? 0 : nRects-1;
+ rects->clear();
+ rects->reserve(nRects);
+
+ while (nRects > 0) {
+ int firstInNextBand = i;
+ int nRectsInBand = 0;
+
+ while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
+ {
+ firstInNextBand += yInc;
+ nRects--;
+ nRectsInBand++;
+ }
+
+ if (xInc != yInc)
+ i = firstInNextBand - yInc;
+
+ while (nRectsInBand > 0) {
+ int y = xrgn->rects[i].y1;
+ int h = maxArea / (xrgn->rects[i].x2 - xrgn->rects[i].x1);
+ if (!h) h = xrgn->rects[i].y2 - y;
+ do {
+ if (h > xrgn->rects[i].y2 - y)
+ h = xrgn->rects[i].y2 - y;
+ Rect r(xrgn->rects[i].x1, y, xrgn->rects[i].x2, y+h);
+ rects->push_back(r);
+ y += h;
+ } while (y < xrgn->rects[i].y2);
+ i += xInc;
+ nRectsInBand--;
+ }
+
+ i = firstInNextBand;
+ }
+
+ return !rects->empty();
+}
+
+rfb::Rect rfb::Region::get_bounding_rect() const {
+ return Rect(xrgn->extents.x1, xrgn->extents.y1,
+ xrgn->extents.x2, xrgn->extents.y2);
+}
+
+
+void rfb::Region::debug_print(const char* prefix) const
+{
+ fprintf(stderr,"%s num rects %3ld extents %3d,%3d %3dx%3d\n",
+ prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
+ xrgn->extents.x2-xrgn->extents.x1,
+ xrgn->extents.y2-xrgn->extents.y1);
+
+ for (int i = 0; i < xrgn->numRects; i++) {
+ fprintf(stderr," rect %3d,%3d %3dx%3d\n",
+ xrgn->rects[i].x1, xrgn->rects[i].y1,
+ xrgn->rects[i].x2-xrgn->rects[i].x1,
+ xrgn->rects[i].y2-xrgn->rects[i].y1);
+ }
+}