blob: 7965a6c41a78ace6472584e6dca9096de7e9ea84 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// Cross-platform Region class based on the X11 region implementation. Note
20// that for efficiency this code manipulates the Xlib region structure
21// directly. Apart from the layout of the structure, there is one other key
22// assumption made: a Region returned from XCreateRegion must always have its
23// rects member allocated so that there is space for at least one rectangle.
24//
25
26#include <rfb/Region.h>
27#include <Xregion/Xregion.h>
28#include <Xregion/region.h>
29#include <assert.h>
30#include <stdio.h>
31
32// A _RectRegion must never be passed as a return parameter to the Xlib region
33// operations. This is because for efficiency its "rects" member has not been
34// allocated with Xmalloc. It is however safe to pass it as an input
35// parameter.
36
37class _RectRegion {
38public:
39 _RectRegion(const rfb::Rect& r) {
40 region.rects = &region.extents;
41 region.numRects = 1;
42 region.extents.x1 = r.tl.x;
43 region.extents.y1 = r.tl.y;
44 region.extents.x2 = r.br.x;
45 region.extents.y2 = r.br.y;
46 region.size = 1;
47 if (r.is_empty())
48 region.numRects = 0;
49 }
50 REGION region;
51};
52
53
54rfb::Region::Region() {
55 xrgn = XCreateRegion();
56 assert(xrgn);
57}
58
59rfb::Region::Region(const Rect& r) {
60 xrgn = XCreateRegion();
61 assert(xrgn);
62 reset(r);
63}
64
65rfb::Region::Region(const rfb::Region& r) {
66 xrgn = XCreateRegion();
67 assert(xrgn);
68 XUnionRegion(xrgn, r.xrgn, xrgn);
69}
70
71rfb::Region::~Region() {
72 XDestroyRegion(xrgn);
73}
74
75rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
76 clear();
77 XUnionRegion(xrgn, r.xrgn, xrgn);
78 return *this;
79}
80
81void rfb::Region::clear() {
82 xrgn->numRects = 0;
83 xrgn->extents.x1 = 0;
84 xrgn->extents.y1 = 0;
85 xrgn->extents.x2 = 0;
86 xrgn->extents.y2 = 0;
87}
88
89void rfb::Region::reset(const Rect& r) {
90 if (r.is_empty()) {
91 clear();
92 } else {
93 xrgn->numRects = 1;
94 xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
95 xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
96 xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
97 xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
98 }
99}
100
101void rfb::Region::translate(const Point& delta) {
102 XOffsetRegion(xrgn, delta.x, delta.y);
103}
104
105void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
106 clear();
107 std::vector<Rect>::const_iterator i;
108 for (i=rects.begin(); i != rects.end(); i++) {
109 _RectRegion rr(*i);
110 XUnionRegion(xrgn, &rr.region, xrgn);
111 }
112}
113
114void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
115 int nRects, const ShortRect* rects)
116{
117 if (xrgn->size < nRects)
118 {
119 BOX* prevRects = xrgn->rects;
120 xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
121 if (!xrgn->rects) {
122 fprintf(stderr,"Xrealloc failed\n");
123 Xfree(prevRects);
124 return;
125 }
126 xrgn->size = nRects;
127 }
128
129 xrgn->numRects = nRects;
130 xrgn->extents.x1 = extents->x1;
131 xrgn->extents.y1 = extents->y1;
132 xrgn->extents.x2 = extents->x2;
133 xrgn->extents.y2 = extents->y2;
134 for (int i = 0; i < nRects; i++) {
135 xrgn->rects[i].x1 = rects[i].x1;
136 xrgn->rects[i].y1 = rects[i].y1;
137 xrgn->rects[i].x2 = rects[i].x2;
138 xrgn->rects[i].y2 = rects[i].y2;
139 }
140}
141
142void rfb::Region::copyFrom(const rfb::Region& r) {
143 XUnionRegion(r.xrgn, r.xrgn, xrgn);
144}
145
146void rfb::Region::assign_intersect(const rfb::Region& r) {
147 XIntersectRegion(xrgn, r.xrgn, xrgn);
148}
149
150void rfb::Region::assign_union(const rfb::Region& r) {
151 XUnionRegion(xrgn, r.xrgn, xrgn);
152}
153
154void rfb::Region::assign_subtract(const rfb::Region& r) {
155 XSubtractRegion(xrgn, r.xrgn, xrgn);
156}
157
158rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
159 rfb::Region ret;
160 XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
161 return ret;
162}
163
164rfb::Region rfb::Region::union_(const rfb::Region& r) const {
165 rfb::Region ret;
166 XUnionRegion(xrgn, r.xrgn, ret.xrgn);
167 return ret;
168}
169
170rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
171 rfb::Region ret;
172 XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
173 return ret;
174}
175
176bool rfb::Region::equals(const rfb::Region& r) const {
177 return XEqualRegion(xrgn, r.xrgn);
178}
179
180int rfb::Region::numRects() const {
181 return xrgn->numRects;
182}
183
184bool rfb::Region::get_rects(std::vector<Rect>* rects,
185 bool left2right, bool topdown, int maxArea) const
186{
187 int nRects = xrgn->numRects;
188 int xInc = left2right ? 1 : -1;
189 int yInc = topdown ? 1 : -1;
190 int i = topdown ? 0 : nRects-1;
191 rects->clear();
192 rects->reserve(nRects);
193
194 while (nRects > 0) {
195 int firstInNextBand = i;
196 int nRectsInBand = 0;
197
198 while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
199 {
200 firstInNextBand += yInc;
201 nRects--;
202 nRectsInBand++;
203 }
204
205 if (xInc != yInc)
206 i = firstInNextBand - yInc;
207
208 while (nRectsInBand > 0) {
209 int y = xrgn->rects[i].y1;
210 int h = maxArea / (xrgn->rects[i].x2 - xrgn->rects[i].x1);
211 if (!h) h = xrgn->rects[i].y2 - y;
212 do {
213 if (h > xrgn->rects[i].y2 - y)
214 h = xrgn->rects[i].y2 - y;
215 Rect r(xrgn->rects[i].x1, y, xrgn->rects[i].x2, y+h);
216 rects->push_back(r);
217 y += h;
218 } while (y < xrgn->rects[i].y2);
219 i += xInc;
220 nRectsInBand--;
221 }
222
223 i = firstInNextBand;
224 }
225
226 return !rects->empty();
227}
228
229rfb::Rect rfb::Region::get_bounding_rect() const {
230 return Rect(xrgn->extents.x1, xrgn->extents.y1,
231 xrgn->extents.x2, xrgn->extents.y2);
232}
233
234
235void rfb::Region::debug_print(const char* prefix) const
236{
237 fprintf(stderr,"%s num rects %3ld extents %3d,%3d %3dx%3d\n",
238 prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
239 xrgn->extents.x2-xrgn->extents.x1,
240 xrgn->extents.y2-xrgn->extents.y1);
241
242 for (int i = 0; i < xrgn->numRects; i++) {
243 fprintf(stderr," rect %3d,%3d %3dx%3d\n",
244 xrgn->rects[i].x1, xrgn->rects[i].y1,
245 xrgn->rects[i].x2-xrgn->rects[i].x1,
246 xrgn->rects[i].y2-xrgn->rects[i].y1);
247 }
248}