blob: 995f8c5b9da8a1c9e78cdd802e028ade4486baef [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>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#include <assert.h>
28#include <stdio.h>
29
Pierre Ossman88903f22016-05-13 15:53:25 +020030extern "C" {
31#include <Xregion/Xlibint.h>
32#include <Xregion/Xutil.h>
33#include <Xregion/Xregion.h>
34}
35
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000036// A _RectRegion must never be passed as a return parameter to the Xlib region
37// operations. This is because for efficiency its "rects" member has not been
38// allocated with Xmalloc. It is however safe to pass it as an input
39// parameter.
40
41class _RectRegion {
42public:
43 _RectRegion(const rfb::Rect& r) {
44 region.rects = &region.extents;
45 region.numRects = 1;
46 region.extents.x1 = r.tl.x;
47 region.extents.y1 = r.tl.y;
48 region.extents.x2 = r.br.x;
49 region.extents.y2 = r.br.y;
50 region.size = 1;
51 if (r.is_empty())
52 region.numRects = 0;
53 }
54 REGION region;
55};
56
57
58rfb::Region::Region() {
59 xrgn = XCreateRegion();
60 assert(xrgn);
61}
62
63rfb::Region::Region(const Rect& r) {
64 xrgn = XCreateRegion();
65 assert(xrgn);
66 reset(r);
67}
68
69rfb::Region::Region(const rfb::Region& r) {
70 xrgn = XCreateRegion();
71 assert(xrgn);
72 XUnionRegion(xrgn, r.xrgn, xrgn);
73}
74
75rfb::Region::~Region() {
76 XDestroyRegion(xrgn);
77}
78
79rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
80 clear();
81 XUnionRegion(xrgn, r.xrgn, xrgn);
82 return *this;
83}
84
85void rfb::Region::clear() {
86 xrgn->numRects = 0;
87 xrgn->extents.x1 = 0;
88 xrgn->extents.y1 = 0;
89 xrgn->extents.x2 = 0;
90 xrgn->extents.y2 = 0;
91}
92
93void rfb::Region::reset(const Rect& r) {
94 if (r.is_empty()) {
95 clear();
96 } else {
97 xrgn->numRects = 1;
98 xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
99 xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
100 xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
101 xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
102 }
103}
104
105void rfb::Region::translate(const Point& delta) {
106 XOffsetRegion(xrgn, delta.x, delta.y);
107}
108
109void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
110 clear();
111 std::vector<Rect>::const_iterator i;
112 for (i=rects.begin(); i != rects.end(); i++) {
113 _RectRegion rr(*i);
114 XUnionRegion(xrgn, &rr.region, xrgn);
115 }
116}
117
118void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
119 int nRects, const ShortRect* rects)
120{
121 if (xrgn->size < nRects)
122 {
123 BOX* prevRects = xrgn->rects;
124 xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
125 if (!xrgn->rects) {
126 fprintf(stderr,"Xrealloc failed\n");
127 Xfree(prevRects);
128 return;
129 }
130 xrgn->size = nRects;
131 }
132
133 xrgn->numRects = nRects;
134 xrgn->extents.x1 = extents->x1;
135 xrgn->extents.y1 = extents->y1;
136 xrgn->extents.x2 = extents->x2;
137 xrgn->extents.y2 = extents->y2;
138 for (int i = 0; i < nRects; i++) {
139 xrgn->rects[i].x1 = rects[i].x1;
140 xrgn->rects[i].y1 = rects[i].y1;
141 xrgn->rects[i].x2 = rects[i].x2;
142 xrgn->rects[i].y2 = rects[i].y2;
143 }
144}
145
146void rfb::Region::copyFrom(const rfb::Region& r) {
147 XUnionRegion(r.xrgn, r.xrgn, xrgn);
148}
149
150void rfb::Region::assign_intersect(const rfb::Region& r) {
151 XIntersectRegion(xrgn, r.xrgn, xrgn);
152}
153
154void rfb::Region::assign_union(const rfb::Region& r) {
155 XUnionRegion(xrgn, r.xrgn, xrgn);
156}
157
158void rfb::Region::assign_subtract(const rfb::Region& r) {
159 XSubtractRegion(xrgn, r.xrgn, xrgn);
160}
161
162rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
163 rfb::Region ret;
164 XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
165 return ret;
166}
167
168rfb::Region rfb::Region::union_(const rfb::Region& r) const {
169 rfb::Region ret;
170 XUnionRegion(xrgn, r.xrgn, ret.xrgn);
171 return ret;
172}
173
174rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
175 rfb::Region ret;
176 XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
177 return ret;
178}
179
180bool rfb::Region::equals(const rfb::Region& r) const {
181 return XEqualRegion(xrgn, r.xrgn);
182}
183
184int rfb::Region::numRects() const {
185 return xrgn->numRects;
186}
187
188bool rfb::Region::get_rects(std::vector<Rect>* rects,
189 bool left2right, bool topdown, int maxArea) const
190{
191 int nRects = xrgn->numRects;
192 int xInc = left2right ? 1 : -1;
193 int yInc = topdown ? 1 : -1;
194 int i = topdown ? 0 : nRects-1;
195 rects->clear();
196 rects->reserve(nRects);
197
198 while (nRects > 0) {
199 int firstInNextBand = i;
200 int nRectsInBand = 0;
201
202 while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
203 {
204 firstInNextBand += yInc;
205 nRects--;
206 nRectsInBand++;
207 }
208
209 if (xInc != yInc)
210 i = firstInNextBand - yInc;
211
212 while (nRectsInBand > 0) {
213 int y = xrgn->rects[i].y1;
214 int h = maxArea / (xrgn->rects[i].x2 - xrgn->rects[i].x1);
215 if (!h) h = xrgn->rects[i].y2 - y;
216 do {
217 if (h > xrgn->rects[i].y2 - y)
218 h = xrgn->rects[i].y2 - y;
219 Rect r(xrgn->rects[i].x1, y, xrgn->rects[i].x2, y+h);
220 rects->push_back(r);
221 y += h;
222 } while (y < xrgn->rects[i].y2);
223 i += xInc;
224 nRectsInBand--;
225 }
226
227 i = firstInNextBand;
228 }
229
230 return !rects->empty();
231}
232
233rfb::Rect rfb::Region::get_bounding_rect() const {
234 return Rect(xrgn->extents.x1, xrgn->extents.y1,
235 xrgn->extents.x2, xrgn->extents.y2);
236}
237
238
239void rfb::Region::debug_print(const char* prefix) const
240{
241 fprintf(stderr,"%s num rects %3ld extents %3d,%3d %3dx%3d\n",
242 prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
243 xrgn->extents.x2-xrgn->extents.x1,
244 xrgn->extents.y2-xrgn->extents.y1);
245
246 for (int i = 0; i < xrgn->numRects; i++) {
247 fprintf(stderr," rect %3d,%3d %3dx%3d\n",
248 xrgn->rects[i].x1, xrgn->rects[i].y1,
249 xrgn->rects[i].x2-xrgn->rects[i].x1,
250 xrgn->rects[i].y2-xrgn->rects[i].y1);
251 }
252}