1 #include <lib/gdi/erect.h>
2 #include <lib/gdi/epoint.h>
3 #include <lib/gdi/region.h>
6 #define max(a,b) ((a) > (b) ? (a) : (b))
8 #define min(a,b) ((a) < (b) ? (a) : (b))
15 A region is basically a list of rectangles. In this implementation,
16 rectangles are ordered by their upper-left position, organized in bands.
18 this code stolen from miregion.c out of the X-Window system.
19 for implementation details, look into their source.
20 This code does all the ugly stuff.
22 Thanks go out to ryg, for explaining me this stuff.
26 gRegion::gRegion(const eRect &rect) : extends(rect)
28 rects.push_back(rect);
39 int gRegion::do_coalesce(int prevStart, unsigned int curStart)
41 // Figure out how many rectangles are in the band.
42 unsigned int numRects = curStart - prevStart;
43 assert(numRects == rects.size() - curStart);
46 std::vector<eRect>::iterator prevBox = rects.begin() + prevStart;
47 std::vector<eRect>::const_iterator curBox = rects.begin() + curStart;
49 // The bands may only be coalesced if the bottom of the previous
50 // matches the top scanline of the current.
51 if (prevBox->y2 != curBox->y1)
54 // Make sure the bands have boxes in the same places. This
55 // assumes that boxes have been added in such a way that they
56 // cover the most area possible. I.e. two boxes in a band must
57 // have some horizontal space between them.
62 if ((prevBox->x1 != curBox->x1) || (prevBox->x2 != curBox->x2))
69 // The bands may be merged, so set the bottom y of each box
70 // in the previous band to the bottom y of the current band.
71 numRects = curStart - prevStart;
72 rects.resize(rects.size() - numRects);
81 void gRegion::appendNonO(std::vector<eRect>::const_iterator r,
82 std::vector<eRect>::const_iterator rEnd, int y1, int y2)
84 int newRects = rEnd - r;
86 assert(newRects != 0);
87 rects.reserve(rects.size() + newRects);
89 assert(r->x1 < r->x2);
90 rects.push_back(eRect(r->x1, y1, r->x2, y2));
95 void gRegion::intersectO(
96 std::vector<eRect>::const_iterator r1,
97 std::vector<eRect>::const_iterator r1End,
98 std::vector<eRect>::const_iterator r2,
99 std::vector<eRect>::const_iterator r2End,
106 assert(r1 != r1End && r2 != r2End);
109 x1 = max(r1->x1, r2->x1);
110 x2 = min(r1->x2, r2->x2);
113 rects.push_back(eRect(x1, y1, x2, y2));
118 } while ( (r1 != r1End) && (r2 != r2End));
121 void gRegion::subtractO(
122 std::vector<eRect>::const_iterator r1,
123 std::vector<eRect>::const_iterator r1End,
124 std::vector<eRect>::const_iterator r2,
125 std::vector<eRect>::const_iterator r2End,
133 assert(r1 != r1End && r2 != r2End);
138 else if (r2->x1 <= x1) {
146 } else if (r2->x1 < r1->x2) {
148 rects.push_back(eRect(x1, y1, r2->x1, y2));
159 rects.push_back(eRect(x1, y1, r1->x2, y2));
164 } while ((r1 != r1End) && (r2 != r2End));
168 rects.push_back(eRect(x1, y1, r1->x2, y2));
175 #define MERGERECT(r) \
178 /* Merge with current rectangle */ \
179 if (r->x1 < x2) overlap = 1; \
180 if (x2 < r->x2) x2 = r->x2; \
182 /* Add current rectangle, start new one */ \
183 rects.push_back(eRect(x1, y1, x2, y2)); \
190 void gRegion::mergeO(
191 std::vector<eRect>::const_iterator r1,
192 std::vector<eRect>::const_iterator r1End,
193 std::vector<eRect>::const_iterator r2,
194 std::vector<eRect>::const_iterator r2End,
201 assert(r1 != r1End && r2 != r2End);
214 while (r1 != r1End && r2 != r2End)
215 if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
221 } while (r1 != r1End);
222 } else if (r2 != r2End)
226 } while (r2 != r2End);
228 rects.push_back(eRect(x1, y1, x2, y2));
231 void gRegion::regionOp(const gRegion ®1, const gRegion ®2, int opcode, int &overlap)
233 std::vector<eRect>::const_iterator r1, r1End, r2, r2End, r1BandEnd, r2BandEnd;
236 int curBand, ytop, top, bot;
238 r1 = reg1.rects.begin();
239 r1End = reg1.rects.end();
240 r2 = reg2.rects.begin();
241 r2End = reg2.rects.end();
243 int newSize = reg1.rects.size();
244 int numRects = reg2.rects.size();
248 if (numRects > newSize)
252 rects.reserve(newSize);
254 int ybot = min(r1->y1, r2->y1);
259 FindBand(r1, r1BandEnd, r1End, r1y1);
260 FindBand(r2, r2BandEnd, r2End, r2y1);
263 top = max(r1y1, ybot);
264 bot = min(r1->y2, r2y1);
266 curBand = rects.size();
267 appendNonO(r1, r1BandEnd, top, bot);
268 coalesce(prevBand, curBand);
272 } else if (r2y1 < r1y1) {
274 top = max(r2y1, ybot);
275 bot = min(r2->y2, r1y1);
277 curBand = rects.size();
278 appendNonO(r2, r2BandEnd, top, bot);
279 coalesce(prevBand, curBand);
285 ybot = min(r1->y2, r2->y2);
287 curBand = rects.size();
291 intersectO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
294 subtractO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
297 mergeO(r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, overlap);
303 coalesce(prevBand, curBand);
305 if (r1->y2 == ybot) r1 = r1BandEnd;
306 if (r2->y2 == ybot) r2 = r2BandEnd;
307 } while (r1 != r1End && r2 != r2End);
308 if ((r1 != r1End) && (opcode & 1)) {
309 FindBand(r1, r1BandEnd, r1End, r1y1);
310 curBand = rects.size();
311 appendNonO(r1, r1BandEnd, max(r1y1, ybot), r1->y2);
312 coalesce(prevBand, curBand);
313 AppendRegions(r1BandEnd, r1End);
314 } else if ((r2 != r2End) && (opcode & 2)) {
315 FindBand(r2, r2BandEnd, r2End, r2y1);
316 curBand = rects.size();
317 appendNonO(r2, r2BandEnd, max(r2y1, ybot), r2->y2);
318 coalesce(prevBand, curBand);
319 AppendRegions(r2BandEnd, r2End);
323 void gRegion::intersect(const gRegion &r1, const gRegion &r2)
326 // TODO: handle trivial reject
327 regionOp(r1, r2, OP_INTERSECT, overlap);
330 void gRegion::subtract(const gRegion &r1, const gRegion &r2)
333 // TODO: handle trivial reject
334 regionOp(r1, r2, OP_SUBTRACT, overlap);
337 void gRegion::merge(const gRegion &r1, const gRegion &r2)
340 // TODO: handle trivial reject
341 regionOp(r1, r2, OP_UNION, overlap);