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