1 /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2016-2020 Pierre Ossman for Cendio AB
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20 #include <rfb/Region.h>
21 #include <rfb/LogWriter.h>
22
23 extern "C" {
24 #include <pixman.h>
25 }
26
27 static rfb::LogWriter vlog("Region");
28
Region()29 rfb::Region::Region() {
30 rgn = new struct pixman_region16;
31 pixman_region_init(rgn);
32 }
33
Region(const Rect & r)34 rfb::Region::Region(const Rect& r) {
35 rgn = new struct pixman_region16;
36 pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height());
37 }
38
Region(const rfb::Region & r)39 rfb::Region::Region(const rfb::Region& r) {
40 rgn = new struct pixman_region16;
41 pixman_region_init(rgn);
42 pixman_region_copy(rgn, r.rgn);
43 }
44
~Region()45 rfb::Region::~Region() {
46 pixman_region_fini(rgn);
47 delete rgn;
48 }
49
operator =(const rfb::Region & r)50 rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
51 pixman_region_copy(rgn, r.rgn);
52 return *this;
53 }
54
clear()55 void rfb::Region::clear() {
56 // pixman_region_clear() isn't available on some older systems
57 pixman_region_fini(rgn);
58 pixman_region_init(rgn);
59 }
60
reset(const Rect & r)61 void rfb::Region::reset(const Rect& r) {
62 pixman_region_fini(rgn);
63 pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height());
64 }
65
translate(const Point & delta)66 void rfb::Region::translate(const Point& delta) {
67 pixman_region_translate(rgn, delta.x, delta.y);
68 }
69
assign_intersect(const rfb::Region & r)70 void rfb::Region::assign_intersect(const rfb::Region& r) {
71 pixman_region_intersect(rgn, rgn, r.rgn);
72 }
73
assign_union(const rfb::Region & r)74 void rfb::Region::assign_union(const rfb::Region& r) {
75 pixman_region_union(rgn, rgn, r.rgn);
76 }
77
assign_subtract(const rfb::Region & r)78 void rfb::Region::assign_subtract(const rfb::Region& r) {
79 pixman_region_subtract(rgn, rgn, r.rgn);
80 }
81
intersect(const rfb::Region & r) const82 rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
83 rfb::Region ret;
84 pixman_region_intersect(ret.rgn, rgn, r.rgn);
85 return ret;
86 }
87
union_(const rfb::Region & r) const88 rfb::Region rfb::Region::union_(const rfb::Region& r) const {
89 rfb::Region ret;
90 pixman_region_union(ret.rgn, rgn, r.rgn);
91 return ret;
92 }
93
subtract(const rfb::Region & r) const94 rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
95 rfb::Region ret;
96 pixman_region_subtract(ret.rgn, rgn, r.rgn);
97 return ret;
98 }
99
equals(const rfb::Region & r) const100 bool rfb::Region::equals(const rfb::Region& r) const {
101 return pixman_region_equal(rgn, r.rgn);
102 }
103
numRects() const104 int rfb::Region::numRects() const {
105 return pixman_region_n_rects(rgn);
106 }
107
get_rects(std::vector<Rect> * rects,bool left2right,bool topdown) const108 bool rfb::Region::get_rects(std::vector<Rect>* rects,
109 bool left2right, bool topdown) const
110 {
111 int nRects;
112 const pixman_box16_t* boxes;
113 int xInc, yInc, i;
114
115 boxes = pixman_region_rectangles(rgn, &nRects);
116
117 rects->clear();
118 rects->reserve(nRects);
119
120 xInc = left2right ? 1 : -1;
121 yInc = topdown ? 1 : -1;
122 i = topdown ? 0 : nRects-1;
123
124 while (nRects > 0) {
125 int firstInNextBand = i;
126 int nRectsInBand = 0;
127
128 while (nRects > 0 && boxes[firstInNextBand].y1 == boxes[i].y1)
129 {
130 firstInNextBand += yInc;
131 nRects--;
132 nRectsInBand++;
133 }
134
135 if (xInc != yInc)
136 i = firstInNextBand - yInc;
137
138 while (nRectsInBand > 0) {
139 Rect r(boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2);
140 rects->push_back(r);
141 i += xInc;
142 nRectsInBand--;
143 }
144
145 i = firstInNextBand;
146 }
147
148 return !rects->empty();
149 }
150
get_bounding_rect() const151 rfb::Rect rfb::Region::get_bounding_rect() const {
152 const pixman_box16_t* extents;
153 extents = pixman_region_extents(rgn);
154 return Rect(extents->x1, extents->y1, extents->x2, extents->y2);
155 }
156
157
debug_print(const char * prefix) const158 void rfb::Region::debug_print(const char* prefix) const
159 {
160 Rect extents;
161 std::vector<Rect> rects;
162 std::vector<Rect>::const_iterator iter;
163
164 extents = get_bounding_rect();
165 get_rects(&rects);
166
167 vlog.debug("%s num rects %3ld extents %3d,%3d %3dx%3d",
168 prefix, (long)rects.size(), extents.tl.x, extents.tl.y,
169 extents.width(), extents.height());
170
171 for (iter = rects.begin(); iter != rects.end(); ++iter) {
172 vlog.debug(" rect %3d,%3d %3dx%3d",
173 iter->tl.x, iter->tl.y, iter->width(), iter->height());
174 }
175 }
176