You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Region.cxx 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* 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. // Cross-platform Region class based on the X11 region implementation. Note
  19. // that for efficiency this code manipulates the Xlib region structure
  20. // directly. Apart from the layout of the structure, there is one other key
  21. // assumption made: a Region returned from XCreateRegion must always have its
  22. // rects member allocated so that there is space for at least one rectangle.
  23. //
  24. #include <rfb/Region.h>
  25. #include <rfb/LogWriter.h>
  26. #include <assert.h>
  27. #include <stdio.h>
  28. extern "C" {
  29. #include <Xregion/Xlibint.h>
  30. #include <Xregion/Xutil.h>
  31. #include <Xregion/Xregion.h>
  32. }
  33. static rfb::LogWriter vlog("Region");
  34. // A _RectRegion must never be passed as a return parameter to the Xlib region
  35. // operations. This is because for efficiency its "rects" member has not been
  36. // allocated with Xmalloc. It is however safe to pass it as an input
  37. // parameter.
  38. class _RectRegion {
  39. public:
  40. _RectRegion(const rfb::Rect& r) {
  41. region.rects = &region.extents;
  42. region.numRects = 1;
  43. region.extents.x1 = r.tl.x;
  44. region.extents.y1 = r.tl.y;
  45. region.extents.x2 = r.br.x;
  46. region.extents.y2 = r.br.y;
  47. region.size = 1;
  48. if (r.is_empty())
  49. region.numRects = 0;
  50. }
  51. REGION region;
  52. };
  53. rfb::Region::Region() {
  54. xrgn = XCreateRegion();
  55. assert(xrgn);
  56. }
  57. rfb::Region::Region(const Rect& r) {
  58. xrgn = XCreateRegion();
  59. assert(xrgn);
  60. reset(r);
  61. }
  62. rfb::Region::Region(const rfb::Region& r) {
  63. xrgn = XCreateRegion();
  64. assert(xrgn);
  65. XUnionRegion(xrgn, r.xrgn, xrgn);
  66. }
  67. rfb::Region::~Region() {
  68. XDestroyRegion(xrgn);
  69. }
  70. rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
  71. clear();
  72. XUnionRegion(xrgn, r.xrgn, xrgn);
  73. return *this;
  74. }
  75. void rfb::Region::clear() {
  76. xrgn->numRects = 0;
  77. xrgn->extents.x1 = 0;
  78. xrgn->extents.y1 = 0;
  79. xrgn->extents.x2 = 0;
  80. xrgn->extents.y2 = 0;
  81. }
  82. void rfb::Region::reset(const Rect& r) {
  83. if (r.is_empty()) {
  84. clear();
  85. } else {
  86. xrgn->numRects = 1;
  87. xrgn->rects[0].x1 = xrgn->extents.x1 = r.tl.x;
  88. xrgn->rects[0].y1 = xrgn->extents.y1 = r.tl.y;
  89. xrgn->rects[0].x2 = xrgn->extents.x2 = r.br.x;
  90. xrgn->rects[0].y2 = xrgn->extents.y2 = r.br.y;
  91. }
  92. }
  93. void rfb::Region::translate(const Point& delta) {
  94. XOffsetRegion(xrgn, delta.x, delta.y);
  95. }
  96. void rfb::Region::setOrderedRects(const std::vector<Rect>& rects) {
  97. clear();
  98. std::vector<Rect>::const_iterator i;
  99. for (i=rects.begin(); i != rects.end(); i++) {
  100. _RectRegion rr(*i);
  101. XUnionRegion(xrgn, &rr.region, xrgn);
  102. }
  103. }
  104. void rfb::Region::setExtentsAndOrderedRects(const ShortRect* extents,
  105. int nRects, const ShortRect* rects)
  106. {
  107. if (xrgn->size < nRects)
  108. {
  109. BOX* prevRects = xrgn->rects;
  110. xrgn->rects = (BOX*)Xrealloc((char*)xrgn->rects, nRects * sizeof(BOX));
  111. if (!xrgn->rects) {
  112. vlog.error("Xrealloc failed");
  113. Xfree(prevRects);
  114. return;
  115. }
  116. xrgn->size = nRects;
  117. }
  118. xrgn->numRects = nRects;
  119. xrgn->extents.x1 = extents->x1;
  120. xrgn->extents.y1 = extents->y1;
  121. xrgn->extents.x2 = extents->x2;
  122. xrgn->extents.y2 = extents->y2;
  123. for (int i = 0; i < nRects; i++) {
  124. xrgn->rects[i].x1 = rects[i].x1;
  125. xrgn->rects[i].y1 = rects[i].y1;
  126. xrgn->rects[i].x2 = rects[i].x2;
  127. xrgn->rects[i].y2 = rects[i].y2;
  128. }
  129. }
  130. void rfb::Region::assign_intersect(const rfb::Region& r) {
  131. XIntersectRegion(xrgn, r.xrgn, xrgn);
  132. }
  133. void rfb::Region::assign_union(const rfb::Region& r) {
  134. XUnionRegion(xrgn, r.xrgn, xrgn);
  135. }
  136. void rfb::Region::assign_subtract(const rfb::Region& r) {
  137. XSubtractRegion(xrgn, r.xrgn, xrgn);
  138. }
  139. rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
  140. rfb::Region ret;
  141. XIntersectRegion(xrgn, r.xrgn, ret.xrgn);
  142. return ret;
  143. }
  144. rfb::Region rfb::Region::union_(const rfb::Region& r) const {
  145. rfb::Region ret;
  146. XUnionRegion(xrgn, r.xrgn, ret.xrgn);
  147. return ret;
  148. }
  149. rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
  150. rfb::Region ret;
  151. XSubtractRegion(xrgn, r.xrgn, ret.xrgn);
  152. return ret;
  153. }
  154. bool rfb::Region::equals(const rfb::Region& r) const {
  155. return XEqualRegion(xrgn, r.xrgn);
  156. }
  157. int rfb::Region::numRects() const {
  158. return xrgn->numRects;
  159. }
  160. bool rfb::Region::get_rects(std::vector<Rect>* rects,
  161. bool left2right, bool topdown) const
  162. {
  163. int nRects = xrgn->numRects;
  164. int xInc = left2right ? 1 : -1;
  165. int yInc = topdown ? 1 : -1;
  166. int i = topdown ? 0 : nRects-1;
  167. rects->clear();
  168. rects->reserve(nRects);
  169. while (nRects > 0) {
  170. int firstInNextBand = i;
  171. int nRectsInBand = 0;
  172. while (nRects > 0 && xrgn->rects[firstInNextBand].y1 == xrgn->rects[i].y1)
  173. {
  174. firstInNextBand += yInc;
  175. nRects--;
  176. nRectsInBand++;
  177. }
  178. if (xInc != yInc)
  179. i = firstInNextBand - yInc;
  180. while (nRectsInBand > 0) {
  181. Rect r(xrgn->rects[i].x1, xrgn->rects[i].y1,
  182. xrgn->rects[i].x2, xrgn->rects[i].y2);
  183. rects->push_back(r);
  184. i += xInc;
  185. nRectsInBand--;
  186. }
  187. i = firstInNextBand;
  188. }
  189. return !rects->empty();
  190. }
  191. rfb::Rect rfb::Region::get_bounding_rect() const {
  192. return Rect(xrgn->extents.x1, xrgn->extents.y1,
  193. xrgn->extents.x2, xrgn->extents.y2);
  194. }
  195. void rfb::Region::debug_print(const char* prefix) const
  196. {
  197. vlog.debug("%s num rects %3ld extents %3d,%3d %3dx%3d",
  198. prefix, xrgn->numRects, xrgn->extents.x1, xrgn->extents.y1,
  199. xrgn->extents.x2-xrgn->extents.x1,
  200. xrgn->extents.y2-xrgn->extents.y1);
  201. for (int i = 0; i < xrgn->numRects; i++) {
  202. vlog.debug(" rect %3d,%3d %3dx%3d",
  203. xrgn->rects[i].x1, xrgn->rects[i].y1,
  204. xrgn->rects[i].x2-xrgn->rects[i].x1,
  205. xrgn->rects[i].y2-xrgn->rects[i].y1);
  206. }
  207. }