1 #include <lib/gdi/erect.h>
2 #include <lib/gdi/epoint.h>
3 #include <lib/gdi/region.h>
4 #include <lib/base/eerror.h>
7 #define max(a,b) ((a) > (b) ? (a) : (b))
9 #define min(a,b) ((a) < (b) ? (a) : (b))
16 A region is basically a list of rectangles. In this implementation,
17 rectangles are ordered by their upper-left position, organized in bands.
19 this code stolen from miregion.c out of the X-Window system.
20 for implementation details, look into their source.
21 This code does all the ugly stuff.
23 Thanks go out to ryg, for explaining me this stuff.
27 gRegion::gRegion(const eRect &rect) : extends(rect)
29 rects.push_back(rect);
40 int gRegion::do_coalesce(int prevStart, unsigned int curStart)
42 // Figure out how many rectangles are in the band.
43 unsigned int numRects = curStart - prevStart;
44 assert(numRects == rects.size() - curStart);
47 std::vector<eRect>::iterator prevBox = rects.begin() + prevStart;
48 std::vector<eRect>::const_iterator curBox = rects.begin() + curStart;
50 // The bands may only be coalesced if the bottom of the previous
51 // matches the top scanline of the current.
52 if (prevBox->y2 != curBox->y1)
55 // Make sure the bands have boxes in the same places. This
56 // assumes that boxes have been added in such a way that they
57 // cover the most area possible. I.e. two boxes in a band must
58 // have some horizontal space between them.
63 if ((prevBox->x1 != curBox->x1) || (prevBox->x2 != curBox->x2))
70 // The bands may be merged, so set the bottom y of each box
71 // in the previous band to the bottom y of the current band.
72 numRects = curStart - prevStart;
73 rects.resize(rects.size() - numRects);
82 void gRegion::appendNonO(std::vector<eRect>::const_iterator r,
83 std::vector<eRect>::const_iterator rEnd, int y1, int y2)
85 int newRects = rEnd - r;
87 assert(newRects != 0);
88 rects.reserve(rects.size() + newRects);
90 assert(r->x1 < r->x2);
91 rects.push_back(eRect(r->x1, y1, r->x2 - r->x1, y2 - y1));
96 void gRegion::intersectO(
97 std::vector<eRect>::const_iterator r1,
98 std::vector<eRect>::const_iterator r1End,
99 std::vector<eRect>::const_iterator r2,
100 std::vector<eRect>::const_iterator r2End,
107 assert(r1 != r1End && r2 != r2End);
110 x1 = max(r1->x1, r2->x1);
111 x2 = min(r1->x2, r2->x2);
114 rects.push_back(eRect(x1, y1, x2 - x1, y2 - y1));
119 } while ( (r1 != r1End) && (r2 != r2End));
122 void gRegion::subtractO(
123 std::vector<eRect>::const_iterator r1,
124 std::vector<eRect>::const_iterator r1End,
125 std::vector<eRect>::const_iterator r2,
126 std::vector<eRect>::const_iterator r2End,
134 assert(r1 != r1End && r2 != r2End);
139 else if (r2->x1 <= x1) {
147 } else if (r2->x1 < r1->x2) {
149 rects.push_back(eRect(x1, y1, r2->x1 - x1, y2 - y1));
160 rects.push_back(eRect(x1, y1, r1->x2 - x1, y2 - y1));
165 } while ((r1 != r1End) && (r2 != r2End));
169 rects.push_back(eRect(x1, y1, r1->x2 - x1, y2 - y1));
176 #define MERGERECT(r) \
179 /* Merge with current rectangle */ \
180 if (r->x1 < x2) overlap = 1; \
181 if (x2 < r->x2) x2 = r->x2; \
183 /* Add current rectangle, start new one */ \
184 rects.push_back(eRect(x1, y1, x2 - x1, y2 - y1)); \
191 void gRegion::mergeO(
192 std::vector<eRect>::const_iterator r1,
193 std::vector<eRect>::const_iterator r1End,
194 std::vector<eRect>::const_iterator r2,
195 std::vector<eRect>::const_iterator r2End,
202 assert(r1 != r1End && r2 != r2End);
215 while (r1 != r1End && r2 != r2End)
216 if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
222 } while (r1 != r1End);
223 } else if (r2 != r2End)
227 } while (r2 != r2End);
229 rects.push_back(eRect(x1, y1, x2 - x1, y2 - y1));
232 void gRegion::regionOp(const gRegion ®1, const gRegion ®2, int opcode, int &overlap)
234 std::vector<eRect>::const_iterator r1, r1End, r2, r2End, r1BandEnd, r2BandEnd;
237 int curBand, ytop, top, bot;
239 r1 = reg1.rects.begin();
240 r1End = reg1.rects.end();
241 r2 = reg2.rects.begin();
242 r2End = reg2.rects.end();
244 int newSize = reg1.rects.size();
245 int numRects = reg2.rects.size();
249 if (numRects > newSize)
253 rects.reserve(newSize);
255 int ybot = min(r1->y1, r2->y1);
260 FindBand(r1, r1BandEnd, r1End, r1y1);
261 FindBand(r2, r2BandEnd, r2End, r2y1);
264 top = max(r1y1, ybot);
265 bot = min(r1->y2, r2y1);
267 curBand = rects.size();
268 appendNonO(r1, r1BandEnd, top, bot);
269 coalesce(prevBand, curBand);
273 } else if (r2y1 < r1y1) {
275 top = max(r2y1, ybot);
276 bot = min(r2->y2, r1y1);
278 curBand = rects.size();
279 appendNonO(r2, r2BandEnd, top, bot);
280 coalesce(prevBand, curBand);
286 ybot = min(r1->y2, r2->y2);
288 curBand = rects.size();
292 intersectO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
295 subtractO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
298 mergeO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
304 coalesce(prevBand, curBand);
306 if (r1->y2 == ybot) r1 = r1BandEnd;
307 if (r2->y2 == ybot) r2 = r2BandEnd;
308 } while (r1 != r1End && r2 != r2End);
309 if ((r1 != r1End) && (opcode & 1)) {
310 FindBand(r1, r1BandEnd, r1End, r1y1);
311 curBand = rects.size();
312 appendNonO(r1, r1BandEnd, max(r1y1, ybot), r1->y2);
313 coalesce(prevBand, curBand);
314 AppendRegions(r1BandEnd, r1End);
315 } else if ((r2 != r2End) && (opcode & 2)) {
316 FindBand(r2, r2BandEnd, r2End, r2y1);
317 curBand = rects.size();
318 appendNonO(r2, r2BandEnd, max(r2y1, ybot), r2->y2);
319 coalesce(prevBand, curBand);
320 AppendRegions(r2BandEnd, r2End);
324 for (int a=0; a<rects.size(); ++a)
325 extends = extends | eRect(rects[0].topLeft(), rects[rects.size()-1].bottomRight());
328 void gRegion::intersect(const gRegion &r1, const gRegion &r2)
330 if (r1.rects.empty())
335 if (r2.rects.empty())
341 // TODO: handle trivial reject
342 regionOp(r1, r2, OP_INTERSECT, overlap);
345 void gRegion::subtract(const gRegion &r1, const gRegion &r2)
347 if (r1.rects.empty() || r2.rects.empty())
353 // TODO: handle trivial reject
354 regionOp(r1, r2, OP_SUBTRACT, overlap);
357 void gRegion::merge(const gRegion &r1, const gRegion &r2)
359 if (r1.rects.empty())
364 if (r2.rects.empty())
370 // TODO: handle trivial reject
371 regionOp(r1, r2, OP_UNION, overlap);
374 gRegion gRegion::operator&(const gRegion &r2) const
377 res.intersect(*this, r2);
381 gRegion gRegion::operator-(const gRegion &r2) const
384 res.subtract(*this, r2);
388 gRegion gRegion::operator|(const gRegion &r2) const
391 res.merge(*this, r2);
395 gRegion &gRegion::operator&=(const gRegion &r2)
398 res.intersect(*this, r2);
402 gRegion &gRegion::operator-=(const gRegion &r2)
405 res.subtract(*this, r2);
409 gRegion &gRegion::operator|=(const gRegion &r2)
412 res.merge(*this, r2);
416 void gRegion::moveBy(ePoint offset)
418 extends.moveBy(offset);
420 for (i=0; i<rects.size(); ++i)
421 rects[i].moveBy(offset);