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