|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qregion.h" |
|
43 #include "qpainterpath.h" |
|
44 #include "qpolygon.h" |
|
45 #include "qbuffer.h" |
|
46 #include "qdatastream.h" |
|
47 #include "qvariant.h" |
|
48 #include "qvarlengtharray.h" |
|
49 |
|
50 #include <qdebug.h> |
|
51 |
|
52 #if defined(Q_OS_UNIX) || defined(Q_WS_WIN) |
|
53 #include "qimage.h" |
|
54 #include "qbitmap.h" |
|
55 #include <stdlib.h> |
|
56 #endif |
|
57 |
|
58 QT_BEGIN_NAMESPACE |
|
59 |
|
60 /*! |
|
61 \class QRegion |
|
62 \brief The QRegion class specifies a clip region for a painter. |
|
63 |
|
64 \ingroup painting |
|
65 \ingroup shared |
|
66 |
|
67 QRegion is used with QPainter::setClipRegion() to limit the paint |
|
68 area to what needs to be painted. There is also a QWidget::repaint() |
|
69 function that takes a QRegion parameter. QRegion is the best tool for |
|
70 minimizing the amount of screen area to be updated by a repaint. |
|
71 |
|
72 This class is not suitable for constructing shapes for rendering, especially |
|
73 as outlines. Use QPainterPath to create paths and shapes for use with |
|
74 QPainter. |
|
75 |
|
76 QRegion is an \l{implicitly shared} class. |
|
77 |
|
78 \section1 Creating and Using Regions |
|
79 |
|
80 A region can be created from a rectangle, an ellipse, a polygon or |
|
81 a bitmap. Complex regions may be created by combining simple |
|
82 regions using united(), intersected(), subtracted(), or xored() (exclusive |
|
83 or). You can move a region using translate(). |
|
84 |
|
85 You can test whether a region isEmpty() or if it |
|
86 contains() a QPoint or QRect. The bounding rectangle can be found |
|
87 with boundingRect(). |
|
88 |
|
89 The function rects() gives a decomposition of the region into |
|
90 rectangles. |
|
91 |
|
92 Example of using complex regions: |
|
93 \snippet doc/src/snippets/code/src_gui_painting_qregion.cpp 0 |
|
94 |
|
95 \section1 Additional License Information |
|
96 |
|
97 On Embedded Linux, Windows CE and X11 platforms, parts of this class rely on |
|
98 code obtained under the following licenses: |
|
99 |
|
100 \legalese |
|
101 Copyright (c) 1987 X Consortium |
|
102 |
|
103 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
104 of this software and associated documentation files (the "Software"), to deal |
|
105 in the Software without restriction, including without limitation the rights |
|
106 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
107 copies of the Software, and to permit persons to whom the Software is |
|
108 furnished to do so, subject to the following conditions: |
|
109 |
|
110 The above copyright notice and this permission notice shall be included in |
|
111 all copies or substantial portions of the Software. |
|
112 |
|
113 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
114 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
115 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
116 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
117 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
118 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
119 |
|
120 Except as contained in this notice, the name of the X Consortium shall not be |
|
121 used in advertising or otherwise to promote the sale, use or other dealings |
|
122 in this Software without prior written authorization from the X Consortium. |
|
123 \endlegalese |
|
124 |
|
125 \br |
|
126 |
|
127 \legalese |
|
128 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. |
|
129 |
|
130 All Rights Reserved |
|
131 |
|
132 Permission to use, copy, modify, and distribute this software and its |
|
133 documentation for any purpose and without fee is hereby granted, |
|
134 provided that the above copyright notice appear in all copies and that |
|
135 both that copyright notice and this permission notice appear in |
|
136 supporting documentation, and that the name of Digital not be |
|
137 used in advertising or publicity pertaining to distribution of the |
|
138 software without specific, written prior permission. |
|
139 |
|
140 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
141 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
142 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
143 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
144 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
145 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
146 SOFTWARE. |
|
147 \endlegalese |
|
148 |
|
149 \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath |
|
150 */ |
|
151 |
|
152 |
|
153 /*! |
|
154 \enum QRegion::RegionType |
|
155 |
|
156 Specifies the shape of the region to be created. |
|
157 |
|
158 \value Rectangle the region covers the entire rectangle. |
|
159 \value Ellipse the region is an ellipse inside the rectangle. |
|
160 */ |
|
161 |
|
162 /*! |
|
163 \fn void QRegion::translate(const QPoint &point) |
|
164 |
|
165 \overload |
|
166 |
|
167 Translates the region \a{point}\e{.x()} along the x axis and |
|
168 \a{point}\e{.y()} along the y axis, relative to the current |
|
169 position. Positive values move the region to the right and down. |
|
170 |
|
171 Translates to the given \a point. |
|
172 */ |
|
173 |
|
174 /*! |
|
175 \fn Handle QRegion::handle() const |
|
176 |
|
177 Returns a platform-specific region handle. The \c Handle type is |
|
178 \c HRGN on Windows, \c Region on X11, and \c RgnHandle on Mac OS |
|
179 X. On \l{Qt for Embedded Linux} it is \c {void *}. |
|
180 |
|
181 \warning This function is not portable. |
|
182 */ |
|
183 |
|
184 /***************************************************************************** |
|
185 QRegion member functions |
|
186 *****************************************************************************/ |
|
187 |
|
188 /*! |
|
189 \fn QRegion::QRegion() |
|
190 |
|
191 Constructs an empty region. |
|
192 |
|
193 \sa isEmpty() |
|
194 */ |
|
195 |
|
196 /*! |
|
197 \fn QRegion::QRegion(const QRect &r, RegionType t) |
|
198 \overload |
|
199 |
|
200 Create a region based on the rectange \a r with region type \a t. |
|
201 |
|
202 If the rectangle is invalid a null region will be created. |
|
203 |
|
204 \sa QRegion::RegionType |
|
205 */ |
|
206 |
|
207 /*! |
|
208 \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) |
|
209 |
|
210 Constructs a polygon region from the point array \a a with the fill rule |
|
211 specified by \a fillRule. |
|
212 |
|
213 If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined |
|
214 using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill |
|
215 algorithm is used. |
|
216 |
|
217 \warning This constructor can be used to create complex regions that will |
|
218 slow down painting when used. |
|
219 */ |
|
220 |
|
221 /*! |
|
222 \fn QRegion::QRegion(const QRegion &r) |
|
223 |
|
224 Constructs a new region which is equal to region \a r. |
|
225 */ |
|
226 |
|
227 /*! |
|
228 \fn QRegion::QRegion(const QBitmap &bm) |
|
229 |
|
230 Constructs a region from the bitmap \a bm. |
|
231 |
|
232 The resulting region consists of the pixels in bitmap \a bm that |
|
233 are Qt::color1, as if each pixel was a 1 by 1 rectangle. |
|
234 |
|
235 This constructor may create complex regions that will slow down |
|
236 painting when used. Note that drawing masked pixmaps can be done |
|
237 much faster using QPixmap::setMask(). |
|
238 */ |
|
239 |
|
240 /*! |
|
241 Constructs a rectangular or elliptic region. |
|
242 |
|
243 If \a t is \c Rectangle, the region is the filled rectangle (\a x, |
|
244 \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled |
|
245 ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size |
|
246 (\a w ,\a h). |
|
247 */ |
|
248 QRegion::QRegion(int x, int y, int w, int h, RegionType t) |
|
249 { |
|
250 QRegion tmp(QRect(x, y, w, h), t); |
|
251 tmp.d->ref.ref(); |
|
252 d = tmp.d; |
|
253 } |
|
254 |
|
255 #ifdef QT3_SUPPORT |
|
256 /*! |
|
257 Use the constructor tha takes a Qt::FillRule as the second |
|
258 argument instead. |
|
259 */ |
|
260 QRegion::QRegion(const QPolygon &pa, bool winding) |
|
261 { |
|
262 new (this) QRegion(pa, winding ? Qt::WindingFill : Qt::OddEvenFill); |
|
263 } |
|
264 #endif |
|
265 |
|
266 /*! |
|
267 \fn QRegion::~QRegion() |
|
268 \internal |
|
269 |
|
270 Destroys the region. |
|
271 */ |
|
272 |
|
273 void QRegion::detach() |
|
274 { |
|
275 if (d->ref != 1) |
|
276 *this = copy(); |
|
277 #if defined(Q_WS_X11) |
|
278 else if (d->xrectangles) { |
|
279 free(d->xrectangles); |
|
280 d->xrectangles = 0; |
|
281 } |
|
282 #endif |
|
283 } |
|
284 |
|
285 // duplicates in qregion_win.cpp and qregion_wce.cpp |
|
286 #define QRGN_SETRECT 1 // region stream commands |
|
287 #define QRGN_SETELLIPSE 2 // (these are internal) |
|
288 #define QRGN_SETPTARRAY_ALT 3 |
|
289 #define QRGN_SETPTARRAY_WIND 4 |
|
290 #define QRGN_TRANSLATE 5 |
|
291 #define QRGN_OR 6 |
|
292 #define QRGN_AND 7 |
|
293 #define QRGN_SUB 8 |
|
294 #define QRGN_XOR 9 |
|
295 #define QRGN_RECTS 10 |
|
296 |
|
297 |
|
298 #ifndef QT_NO_DATASTREAM |
|
299 |
|
300 /* |
|
301 Executes region commands in the internal buffer and rebuilds the |
|
302 original region. |
|
303 |
|
304 We do this when we read a region from the data stream. |
|
305 |
|
306 If \a ver is non-0, uses the format version \a ver on reading the |
|
307 byte array. |
|
308 */ |
|
309 void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder) |
|
310 { |
|
311 QByteArray copy = buffer; |
|
312 QDataStream s(©, QIODevice::ReadOnly); |
|
313 if (ver) |
|
314 s.setVersion(ver); |
|
315 s.setByteOrder(byteOrder); |
|
316 QRegion rgn; |
|
317 #ifndef QT_NO_DEBUG |
|
318 int test_cnt = 0; |
|
319 #endif |
|
320 while (!s.atEnd()) { |
|
321 qint32 id; |
|
322 if (s.version() == 1) { |
|
323 int id_int; |
|
324 s >> id_int; |
|
325 id = id_int; |
|
326 } else { |
|
327 s >> id; |
|
328 } |
|
329 #ifndef QT_NO_DEBUG |
|
330 if (test_cnt > 0 && id != QRGN_TRANSLATE) |
|
331 qWarning("QRegion::exec: Internal error"); |
|
332 test_cnt++; |
|
333 #endif |
|
334 if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) { |
|
335 QRect r; |
|
336 s >> r; |
|
337 rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse); |
|
338 } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) { |
|
339 QPolygon a; |
|
340 s >> a; |
|
341 rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill); |
|
342 } else if (id == QRGN_TRANSLATE) { |
|
343 QPoint p; |
|
344 s >> p; |
|
345 rgn.translate(p.x(), p.y()); |
|
346 } else if (id >= QRGN_OR && id <= QRGN_XOR) { |
|
347 QByteArray bop1, bop2; |
|
348 QRegion r1, r2; |
|
349 s >> bop1; |
|
350 r1.exec(bop1); |
|
351 s >> bop2; |
|
352 r2.exec(bop2); |
|
353 |
|
354 switch (id) { |
|
355 case QRGN_OR: |
|
356 rgn = r1.united(r2); |
|
357 break; |
|
358 case QRGN_AND: |
|
359 rgn = r1.intersected(r2); |
|
360 break; |
|
361 case QRGN_SUB: |
|
362 rgn = r1.subtracted(r2); |
|
363 break; |
|
364 case QRGN_XOR: |
|
365 rgn = r1.xored(r2); |
|
366 break; |
|
367 } |
|
368 } else if (id == QRGN_RECTS) { |
|
369 // (This is the only form used in Qt 2.0) |
|
370 quint32 n; |
|
371 s >> n; |
|
372 QRect r; |
|
373 for (int i=0; i<(int)n; i++) { |
|
374 s >> r; |
|
375 rgn = rgn.united(QRegion(r)); |
|
376 } |
|
377 } |
|
378 } |
|
379 *this = rgn; |
|
380 } |
|
381 |
|
382 |
|
383 /***************************************************************************** |
|
384 QRegion stream functions |
|
385 *****************************************************************************/ |
|
386 |
|
387 /*! |
|
388 \fn QRegion &QRegion::operator=(const QRegion &r) |
|
389 |
|
390 Assigns \a r to this region and returns a reference to the region. |
|
391 */ |
|
392 |
|
393 /*! |
|
394 \relates QRegion |
|
395 |
|
396 Writes the region \a r to the stream \a s and returns a reference |
|
397 to the stream. |
|
398 |
|
399 \sa \link datastreamformat.html Format of the QDataStream operators \endlink |
|
400 */ |
|
401 |
|
402 QDataStream &operator<<(QDataStream &s, const QRegion &r) |
|
403 { |
|
404 QVector<QRect> a = r.rects(); |
|
405 if (a.isEmpty()) { |
|
406 s << (quint32)0; |
|
407 } else { |
|
408 if (s.version() == 1) { |
|
409 int i; |
|
410 for (i = a.size() - 1; i > 0; --i) { |
|
411 s << (quint32)(12 + i * 24); |
|
412 s << (int)QRGN_OR; |
|
413 } |
|
414 for (i = 0; i < a.size(); ++i) { |
|
415 s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i]; |
|
416 } |
|
417 } else { |
|
418 s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect |
|
419 s << (qint32)QRGN_RECTS; |
|
420 s << a; |
|
421 } |
|
422 } |
|
423 return s; |
|
424 } |
|
425 |
|
426 /*! |
|
427 \relates QRegion |
|
428 |
|
429 Reads a region from the stream \a s into \a r and returns a |
|
430 reference to the stream. |
|
431 |
|
432 \sa \link datastreamformat.html Format of the QDataStream operators \endlink |
|
433 */ |
|
434 |
|
435 QDataStream &operator>>(QDataStream &s, QRegion &r) |
|
436 { |
|
437 QByteArray b; |
|
438 s >> b; |
|
439 r.exec(b, s.version(), s.byteOrder()); |
|
440 return s; |
|
441 } |
|
442 #endif //QT_NO_DATASTREAM |
|
443 |
|
444 #ifndef QT_NO_DEBUG_STREAM |
|
445 QDebug operator<<(QDebug s, const QRegion &r) |
|
446 { |
|
447 QVector<QRect> rects = r.rects(); |
|
448 s.nospace() << "QRegion(size=" << rects.size() << "), " |
|
449 << "bounds = " << r.boundingRect() << '\n'; |
|
450 for (int i=0; i<rects.size(); ++i) |
|
451 s << "- " << i << rects.at(i) << '\n'; |
|
452 return s; |
|
453 } |
|
454 #endif |
|
455 |
|
456 |
|
457 // These are not inline - they can be implemented better on some platforms |
|
458 // (eg. Windows at least provides 3-variable operations). For now, simple. |
|
459 |
|
460 |
|
461 /*! |
|
462 Applies the united() function to this region and \a r. \c r1|r2 is |
|
463 equivalent to \c r1.united(r2). |
|
464 |
|
465 \sa united(), operator+() |
|
466 */ |
|
467 const QRegion QRegion::operator|(const QRegion &r) const |
|
468 { return united(r); } |
|
469 |
|
470 /*! |
|
471 Applies the united() function to this region and \a r. \c r1+r2 is |
|
472 equivalent to \c r1.united(r2). |
|
473 |
|
474 \sa united(), operator|() |
|
475 */ |
|
476 const QRegion QRegion::operator+(const QRegion &r) const |
|
477 { return united(r); } |
|
478 |
|
479 /*! |
|
480 \overload |
|
481 \since 4.4 |
|
482 */ |
|
483 const QRegion QRegion::operator+(const QRect &r) const |
|
484 { return united(r); } |
|
485 |
|
486 /*! |
|
487 Applies the intersected() function to this region and \a r. \c r1&r2 |
|
488 is equivalent to \c r1.intersected(r2). |
|
489 |
|
490 \sa intersected() |
|
491 */ |
|
492 const QRegion QRegion::operator&(const QRegion &r) const |
|
493 { return intersected(r); } |
|
494 |
|
495 /*! |
|
496 \overload |
|
497 \since 4.4 |
|
498 */ |
|
499 const QRegion QRegion::operator&(const QRect &r) const |
|
500 { |
|
501 return intersected(r); |
|
502 } |
|
503 |
|
504 /*! |
|
505 Applies the subtracted() function to this region and \a r. \c r1-r2 |
|
506 is equivalent to \c r1.subtracted(r2). |
|
507 |
|
508 \sa subtracted() |
|
509 */ |
|
510 const QRegion QRegion::operator-(const QRegion &r) const |
|
511 { return subtracted(r); } |
|
512 |
|
513 /*! |
|
514 Applies the xored() function to this region and \a r. \c r1^r2 is |
|
515 equivalent to \c r1.xored(r2). |
|
516 |
|
517 \sa xored() |
|
518 */ |
|
519 const QRegion QRegion::operator^(const QRegion &r) const |
|
520 { return xored(r); } |
|
521 |
|
522 /*! |
|
523 Applies the united() function to this region and \a r and assigns |
|
524 the result to this region. \c r1|=r2 is equivalent to \c |
|
525 {r1 = r1.united(r2)}. |
|
526 |
|
527 \sa united() |
|
528 */ |
|
529 QRegion& QRegion::operator|=(const QRegion &r) |
|
530 { return *this = *this | r; } |
|
531 |
|
532 /*! |
|
533 \fn QRegion& QRegion::operator+=(const QRect &rect) |
|
534 |
|
535 Returns a region that is the union of this region with the specified \a rect. |
|
536 |
|
537 \sa united() |
|
538 */ |
|
539 /*! |
|
540 \fn QRegion& QRegion::operator+=(const QRegion &r) |
|
541 |
|
542 Applies the united() function to this region and \a r and assigns |
|
543 the result to this region. \c r1+=r2 is equivalent to \c |
|
544 {r1 = r1.united(r2)}. |
|
545 |
|
546 \sa intersected() |
|
547 */ |
|
548 #if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) |
|
549 QRegion& QRegion::operator+=(const QRect &r) |
|
550 { |
|
551 return operator+=(QRegion(r)); |
|
552 } |
|
553 #endif |
|
554 |
|
555 /*! |
|
556 \fn QRegion& QRegion::operator&=(const QRegion &r) |
|
557 |
|
558 Applies the intersected() function to this region and \a r and |
|
559 assigns the result to this region. \c r1&=r2 is equivalent to \c |
|
560 r1 = r1.intersected(r2). |
|
561 |
|
562 \sa intersected() |
|
563 */ |
|
564 QRegion& QRegion::operator&=(const QRegion &r) |
|
565 { return *this = *this & r; } |
|
566 |
|
567 /*! |
|
568 \overload |
|
569 \since 4.4 |
|
570 */ |
|
571 #if defined (Q_OS_UNIX) || defined (Q_WS_WIN) |
|
572 QRegion& QRegion::operator&=(const QRect &r) |
|
573 { |
|
574 return *this = *this & r; |
|
575 } |
|
576 #else |
|
577 QRegion& QRegion::operator&=(const QRect &r) |
|
578 { |
|
579 return *this &= (QRegion(r)); |
|
580 } |
|
581 #endif |
|
582 |
|
583 /*! |
|
584 \fn QRegion& QRegion::operator-=(const QRegion &r) |
|
585 |
|
586 Applies the subtracted() function to this region and \a r and |
|
587 assigns the result to this region. \c r1-=r2 is equivalent to \c |
|
588 {r1 = r1.subtracted(r2)}. |
|
589 |
|
590 \sa subtracted() |
|
591 */ |
|
592 QRegion& QRegion::operator-=(const QRegion &r) |
|
593 { return *this = *this - r; } |
|
594 |
|
595 /*! |
|
596 Applies the xored() function to this region and \a r and |
|
597 assigns the result to this region. \c r1^=r2 is equivalent to \c |
|
598 {r1 = r1.xored(r2)}. |
|
599 |
|
600 \sa xored() |
|
601 */ |
|
602 QRegion& QRegion::operator^=(const QRegion &r) |
|
603 { return *this = *this ^ r; } |
|
604 |
|
605 /*! |
|
606 \fn bool QRegion::operator!=(const QRegion &other) const |
|
607 |
|
608 Returns true if this region is different from the \a other region; |
|
609 otherwise returns false. |
|
610 */ |
|
611 |
|
612 /*! |
|
613 Returns the region as a QVariant |
|
614 */ |
|
615 QRegion::operator QVariant() const |
|
616 { |
|
617 return QVariant(QVariant::Region, this); |
|
618 } |
|
619 |
|
620 /*! |
|
621 \fn bool QRegion::operator==(const QRegion &r) const |
|
622 |
|
623 Returns true if the region is equal to \a r; otherwise returns |
|
624 false. |
|
625 */ |
|
626 |
|
627 /*! |
|
628 \fn bool QRegion::isNull() const |
|
629 |
|
630 Use isEmpty() instead. |
|
631 */ |
|
632 |
|
633 |
|
634 /*! |
|
635 \fn void QRegion::translate(int dx, int dy) |
|
636 |
|
637 Translates (moves) the region \a dx along the X axis and \a dy |
|
638 along the Y axis. |
|
639 */ |
|
640 |
|
641 /*! |
|
642 \fn QRegion QRegion::translated(const QPoint &p) const |
|
643 \overload |
|
644 \since 4.1 |
|
645 |
|
646 Returns a copy of the regtion that is translated \a{p}\e{.x()} |
|
647 along the x axis and \a{p}\e{.y()} along the y axis, relative to |
|
648 the current position. Positive values move the rectangle to the |
|
649 right and down. |
|
650 |
|
651 \sa translate() |
|
652 */ |
|
653 |
|
654 /*! |
|
655 \since 4.1 |
|
656 |
|
657 Returns a copy of the region that is translated \a dx along the |
|
658 x axis and \a dy along the y axis, relative to the current |
|
659 position. Positive values move the region to the right and |
|
660 down. |
|
661 |
|
662 \sa translate() |
|
663 */ |
|
664 |
|
665 QRegion |
|
666 QRegion::translated(int dx, int dy) const |
|
667 { |
|
668 QRegion ret(*this); |
|
669 ret.translate(dx, dy); |
|
670 return ret; |
|
671 } |
|
672 |
|
673 |
|
674 inline bool rect_intersects(const QRect &r1, const QRect &r2) |
|
675 { |
|
676 return (r1.right() >= r2.left() && r1.left() <= r2.right() && |
|
677 r1.bottom() >= r2.top() && r1.top() <= r2.bottom()); |
|
678 } |
|
679 |
|
680 /*! |
|
681 \since 4.2 |
|
682 |
|
683 Returns true if this region intersects with \a region, otherwise |
|
684 returns false. |
|
685 */ |
|
686 bool QRegion::intersects(const QRegion ®ion) const |
|
687 { |
|
688 if (isEmpty() || region.isEmpty()) |
|
689 return false; |
|
690 |
|
691 if (!rect_intersects(boundingRect(), region.boundingRect())) |
|
692 return false; |
|
693 if (numRects() == 1 && region.numRects() == 1) |
|
694 return true; |
|
695 |
|
696 const QVector<QRect> myRects = rects(); |
|
697 const QVector<QRect> otherRects = region.rects(); |
|
698 |
|
699 for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1) |
|
700 for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2) |
|
701 if (rect_intersects(*i1, *i2)) |
|
702 return true; |
|
703 return false; |
|
704 } |
|
705 |
|
706 /*! |
|
707 \since 4.2 |
|
708 |
|
709 Returns true if this region intersects with \a rect, otherwise |
|
710 returns false. |
|
711 */ |
|
712 bool QRegion::intersects(const QRect &rect) const |
|
713 { |
|
714 if (isEmpty() || rect.isNull()) |
|
715 return false; |
|
716 |
|
717 const QRect r = rect.normalized(); |
|
718 if (!rect_intersects(boundingRect(), r)) |
|
719 return false; |
|
720 if (numRects() == 1) |
|
721 return true; |
|
722 |
|
723 const QVector<QRect> myRects = rects(); |
|
724 for (QVector<QRect>::const_iterator it = myRects.constBegin(); it < myRects.constEnd(); ++it) |
|
725 if (rect_intersects(r, *it)) |
|
726 return true; |
|
727 return false; |
|
728 } |
|
729 |
|
730 #if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) |
|
731 /*! |
|
732 \overload |
|
733 \since 4.4 |
|
734 */ |
|
735 QRegion QRegion::intersect(const QRect &r) const |
|
736 { |
|
737 return intersect(QRegion(r)); |
|
738 } |
|
739 #endif |
|
740 |
|
741 /*! |
|
742 \fn int QRegion::numRects() const |
|
743 \since 4.4 |
|
744 |
|
745 Returns the number of rectangles that will be returned in rects(). |
|
746 */ |
|
747 |
|
748 /*! |
|
749 \fn bool QRegion::isEmpty() const |
|
750 |
|
751 Returns true if the region is empty; otherwise returns false. An |
|
752 empty region is a region that contains no points. |
|
753 |
|
754 Example: |
|
755 \snippet doc/src/snippets/code/src_gui_painting_qregion_unix.cpp 0 |
|
756 */ |
|
757 |
|
758 /*! |
|
759 \fn bool QRegion::contains(const QPoint &p) const |
|
760 |
|
761 Returns true if the region contains the point \a p; otherwise |
|
762 returns false. |
|
763 */ |
|
764 |
|
765 /*! |
|
766 \fn bool QRegion::contains(const QRect &r) const |
|
767 \overload |
|
768 |
|
769 Returns true if the region overlaps the rectangle \a r; otherwise |
|
770 returns false. |
|
771 */ |
|
772 |
|
773 /*! |
|
774 \fn QRegion QRegion::unite(const QRegion &r) const |
|
775 \obsolete |
|
776 |
|
777 Use united(\a r) instead. |
|
778 */ |
|
779 |
|
780 /*! |
|
781 \fn QRegion QRegion::unite(const QRect &rect) const |
|
782 \since 4.4 |
|
783 \obsolete |
|
784 |
|
785 Use united(\a rect) instead. |
|
786 */ |
|
787 |
|
788 /*! |
|
789 \fn QRegion QRegion::united(const QRect &rect) const |
|
790 \since 4.4 |
|
791 |
|
792 Returns a region which is the union of this region and the given \a rect. |
|
793 |
|
794 \sa intersected(), subtracted(), xored() |
|
795 */ |
|
796 |
|
797 /*! |
|
798 \fn QRegion QRegion::united(const QRegion &r) const |
|
799 \since 4.2 |
|
800 |
|
801 Returns a region which is the union of this region and \a r. |
|
802 |
|
803 \img runion.png Region Union |
|
804 |
|
805 The figure shows the union of two elliptical regions. |
|
806 |
|
807 \sa intersected(), subtracted(), xored() |
|
808 */ |
|
809 |
|
810 /*! |
|
811 \fn QRegion QRegion::intersect(const QRegion &r) const |
|
812 \obsolete |
|
813 |
|
814 Use intersected(\a r) instead. |
|
815 */ |
|
816 |
|
817 /*! |
|
818 \fn QRegion QRegion::intersect(const QRect &rect) const |
|
819 \since 4.4 |
|
820 \obsolete |
|
821 |
|
822 Use intersected(\a rect) instead. |
|
823 */ |
|
824 |
|
825 /*! |
|
826 \fn QRegion QRegion::intersected(const QRect &rect) const |
|
827 \since 4.4 |
|
828 |
|
829 Returns a region which is the intersection of this region and the given \a rect. |
|
830 |
|
831 \sa subtracted(), united(), xored() |
|
832 */ |
|
833 |
|
834 /*! |
|
835 \fn QRegion QRegion::intersected(const QRegion &r) const |
|
836 \since 4.2 |
|
837 |
|
838 Returns a region which is the intersection of this region and \a r. |
|
839 |
|
840 \img rintersect.png Region Intersection |
|
841 |
|
842 The figure shows the intersection of two elliptical regions. |
|
843 |
|
844 \sa subtracted(), united(), xored() |
|
845 */ |
|
846 |
|
847 /*! |
|
848 \fn QRegion QRegion::subtract(const QRegion &r) const |
|
849 \obsolete |
|
850 |
|
851 Use subtracted(\a r) instead. |
|
852 */ |
|
853 |
|
854 /*! |
|
855 \fn QRegion QRegion::subtracted(const QRegion &r) const |
|
856 \since 4.2 |
|
857 |
|
858 Returns a region which is \a r subtracted from this region. |
|
859 |
|
860 \img rsubtract.png Region Subtraction |
|
861 |
|
862 The figure shows the result when the ellipse on the right is |
|
863 subtracted from the ellipse on the left (\c {left - right}). |
|
864 |
|
865 \sa intersected(), united(), xored() |
|
866 */ |
|
867 |
|
868 /*! |
|
869 \fn QRegion QRegion::eor(const QRegion &r) const |
|
870 \obsolete |
|
871 |
|
872 Use xored(\a r) instead. |
|
873 */ |
|
874 |
|
875 /*! |
|
876 \fn QRegion QRegion::xored(const QRegion &r) const |
|
877 \since 4.2 |
|
878 |
|
879 Returns a region which is the exclusive or (XOR) of this region |
|
880 and \a r. |
|
881 |
|
882 \img rxor.png Region XORed |
|
883 |
|
884 The figure shows the exclusive or of two elliptical regions. |
|
885 |
|
886 \sa intersected(), united(), subtracted() |
|
887 */ |
|
888 |
|
889 /*! |
|
890 \fn QRect QRegion::boundingRect() const |
|
891 |
|
892 Returns the bounding rectangle of this region. An empty region |
|
893 gives a rectangle that is QRect::isNull(). |
|
894 */ |
|
895 |
|
896 /*! |
|
897 \fn QVector<QRect> QRegion::rects() const |
|
898 |
|
899 Returns an array of non-overlapping rectangles that make up the |
|
900 region. |
|
901 |
|
902 The union of all the rectangles is equal to the original region. |
|
903 */ |
|
904 |
|
905 /*! |
|
906 \fn void QRegion::setRects(const QRect *rects, int number) |
|
907 |
|
908 Sets the region using the array of rectangles specified by \a rects and |
|
909 \a number. |
|
910 The rectangles \e must be optimally Y-X sorted and follow these restrictions: |
|
911 |
|
912 \list |
|
913 \o The rectangles must not intersect. |
|
914 \o All rectangles with a given top coordinate must have the same height. |
|
915 \o No two rectangles may abut horizontally (they should be combined |
|
916 into a single wider rectangle in that case). |
|
917 \o The rectangles must be sorted in ascending order, with Y as the major |
|
918 sort key and X as the minor sort key. |
|
919 \endlist |
|
920 \omit |
|
921 Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X). |
|
922 \endomit |
|
923 */ |
|
924 |
|
925 namespace { |
|
926 |
|
927 struct Segment |
|
928 { |
|
929 Segment() {} |
|
930 Segment(const QPoint &p) |
|
931 : added(false) |
|
932 , point(p) |
|
933 { |
|
934 } |
|
935 |
|
936 int left() const |
|
937 { |
|
938 return qMin(point.x(), next->point.x()); |
|
939 } |
|
940 |
|
941 int right() const |
|
942 { |
|
943 return qMax(point.x(), next->point.x()); |
|
944 } |
|
945 |
|
946 bool overlaps(const Segment &other) const |
|
947 { |
|
948 return left() < other.right() && other.left() < right(); |
|
949 } |
|
950 |
|
951 void connect(Segment &other) |
|
952 { |
|
953 next = &other; |
|
954 other.prev = this; |
|
955 |
|
956 horizontal = (point.y() == other.point.y()); |
|
957 } |
|
958 |
|
959 void merge(Segment &other) |
|
960 { |
|
961 if (right() <= other.right()) { |
|
962 QPoint p = other.point; |
|
963 Segment *oprev = other.prev; |
|
964 |
|
965 other.point = point; |
|
966 other.prev = prev; |
|
967 prev->next = &other; |
|
968 |
|
969 point = p; |
|
970 prev = oprev; |
|
971 oprev->next = this; |
|
972 } else { |
|
973 Segment *onext = other.next; |
|
974 other.next = next; |
|
975 next->prev = &other; |
|
976 |
|
977 next = onext; |
|
978 next->prev = this; |
|
979 } |
|
980 } |
|
981 |
|
982 int horizontal : 1; |
|
983 int added : 1; |
|
984 |
|
985 QPoint point; |
|
986 Segment *prev; |
|
987 Segment *next; |
|
988 }; |
|
989 |
|
990 void mergeSegments(Segment *a, int na, Segment *b, int nb) |
|
991 { |
|
992 int i = 0; |
|
993 int j = 0; |
|
994 |
|
995 while (i != na && j != nb) { |
|
996 Segment &sa = a[i]; |
|
997 Segment &sb = b[j]; |
|
998 const int ra = sa.right(); |
|
999 const int rb = sb.right(); |
|
1000 if (sa.overlaps(sb)) |
|
1001 sa.merge(sb); |
|
1002 i += (rb >= ra); |
|
1003 j += (ra >= rb); |
|
1004 } |
|
1005 } |
|
1006 |
|
1007 void addSegmentsToPath(Segment *segment, QPainterPath &path) |
|
1008 { |
|
1009 Segment *current = segment; |
|
1010 path.moveTo(current->point); |
|
1011 |
|
1012 current->added = true; |
|
1013 |
|
1014 Segment *last = current; |
|
1015 current = current->next; |
|
1016 while (current != segment) { |
|
1017 if (current->horizontal != last->horizontal) |
|
1018 path.lineTo(current->point); |
|
1019 current->added = true; |
|
1020 last = current; |
|
1021 current = current->next; |
|
1022 } |
|
1023 } |
|
1024 |
|
1025 } |
|
1026 |
|
1027 Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion ®ion) |
|
1028 { |
|
1029 QPainterPath result; |
|
1030 if (region.numRects() == 1) { |
|
1031 result.addRect(region.boundingRect()); |
|
1032 return result; |
|
1033 } |
|
1034 |
|
1035 const QVector<QRect> rects = region.rects(); |
|
1036 |
|
1037 QVarLengthArray<Segment> segments; |
|
1038 segments.resize(4 * rects.size()); |
|
1039 |
|
1040 const QRect *rect = rects.constData(); |
|
1041 const QRect *end = rect + rects.size(); |
|
1042 |
|
1043 int lastRowSegmentCount = 0; |
|
1044 Segment *lastRowSegments = 0; |
|
1045 |
|
1046 int lastSegment = 0; |
|
1047 int lastY = 0; |
|
1048 while (rect != end) { |
|
1049 const int y = rect[0].y(); |
|
1050 int count = 0; |
|
1051 while (&rect[count] != end && rect[count].y() == y) |
|
1052 ++count; |
|
1053 |
|
1054 for (int i = 0; i < count; ++i) { |
|
1055 int offset = lastSegment + i; |
|
1056 segments[offset] = Segment(rect[i].topLeft()); |
|
1057 segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0)); |
|
1058 segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1)); |
|
1059 segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1)); |
|
1060 |
|
1061 offset = lastSegment + i; |
|
1062 for (int j = 0; j < 4; ++j) |
|
1063 segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]); |
|
1064 } |
|
1065 |
|
1066 if (lastRowSegments && lastY == y) |
|
1067 mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count); |
|
1068 |
|
1069 lastRowSegments = &segments[lastSegment + 2 * count]; |
|
1070 lastRowSegmentCount = count; |
|
1071 lastSegment += 4 * count; |
|
1072 lastY = y + rect[0].height(); |
|
1073 rect += count; |
|
1074 } |
|
1075 |
|
1076 for (int i = 0; i < lastSegment; ++i) { |
|
1077 Segment *segment = &segments[i]; |
|
1078 if (!segment->added) |
|
1079 addSegmentsToPath(segment, result); |
|
1080 } |
|
1081 |
|
1082 return result; |
|
1083 } |
|
1084 |
|
1085 #if defined(Q_OS_UNIX) || defined(Q_WS_WIN) |
|
1086 |
|
1087 //#define QT_REGION_DEBUG |
|
1088 /* |
|
1089 * clip region |
|
1090 */ |
|
1091 |
|
1092 struct QRegionPrivate { |
|
1093 int numRects; |
|
1094 QVector<QRect> rects; |
|
1095 QRect extents; |
|
1096 QRect innerRect; |
|
1097 int innerArea; |
|
1098 |
|
1099 inline QRegionPrivate() : numRects(0), innerArea(-1) {} |
|
1100 inline QRegionPrivate(const QRect &r) { |
|
1101 numRects = 1; |
|
1102 extents = r; |
|
1103 innerRect = r; |
|
1104 innerArea = r.width() * r.height(); |
|
1105 } |
|
1106 |
|
1107 inline QRegionPrivate(const QRegionPrivate &r) { |
|
1108 rects = r.rects; |
|
1109 numRects = r.numRects; |
|
1110 extents = r.extents; |
|
1111 innerRect = r.innerRect; |
|
1112 innerArea = r.innerArea; |
|
1113 } |
|
1114 |
|
1115 inline QRegionPrivate &operator=(const QRegionPrivate &r) { |
|
1116 rects = r.rects; |
|
1117 numRects = r.numRects; |
|
1118 extents = r.extents; |
|
1119 innerRect = r.innerRect; |
|
1120 innerArea = r.innerArea; |
|
1121 return *this; |
|
1122 } |
|
1123 |
|
1124 void intersect(const QRect &r); |
|
1125 |
|
1126 /* |
|
1127 * Returns true if r is guaranteed to be fully contained in this region. |
|
1128 * A false return value does not guarantee the opposite. |
|
1129 */ |
|
1130 inline bool contains(const QRegionPrivate &r) const { |
|
1131 return contains(r.extents); |
|
1132 } |
|
1133 |
|
1134 inline bool contains(const QRect &r2) const { |
|
1135 const QRect &r1 = innerRect; |
|
1136 return r2.left() >= r1.left() && r2.right() <= r1.right() |
|
1137 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom(); |
|
1138 } |
|
1139 |
|
1140 /* |
|
1141 * Returns true if this region is guaranteed to be fully contained in r. |
|
1142 */ |
|
1143 inline bool within(const QRect &r1) const { |
|
1144 const QRect &r2 = extents; |
|
1145 return r2.left() >= r1.left() && r2.right() <= r1.right() |
|
1146 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom(); |
|
1147 } |
|
1148 |
|
1149 inline void updateInnerRect(const QRect &rect) { |
|
1150 const int area = rect.width() * rect.height(); |
|
1151 if (area > innerArea) { |
|
1152 innerArea = area; |
|
1153 innerRect = rect; |
|
1154 } |
|
1155 } |
|
1156 |
|
1157 inline void vectorize() { |
|
1158 if (numRects == 1) { |
|
1159 if (!rects.size()) |
|
1160 rects.resize(1); |
|
1161 rects[0] = extents; |
|
1162 } |
|
1163 } |
|
1164 |
|
1165 inline void append(const QRect *r); |
|
1166 void append(const QRegionPrivate *r); |
|
1167 void prepend(const QRect *r); |
|
1168 void prepend(const QRegionPrivate *r); |
|
1169 inline bool canAppend(const QRect *r) const; |
|
1170 inline bool canAppend(const QRegionPrivate *r) const; |
|
1171 inline bool canPrepend(const QRect *r) const; |
|
1172 inline bool canPrepend(const QRegionPrivate *r) const; |
|
1173 |
|
1174 inline bool mergeFromRight(QRect *left, const QRect *right); |
|
1175 inline bool mergeFromLeft(QRect *left, const QRect *right); |
|
1176 inline bool mergeFromBelow(QRect *top, const QRect *bottom, |
|
1177 const QRect *nextToTop, |
|
1178 const QRect *nextToBottom); |
|
1179 inline bool mergeFromAbove(QRect *bottom, const QRect *top, |
|
1180 const QRect *nextToBottom, |
|
1181 const QRect *nextToTop); |
|
1182 |
|
1183 #ifdef QT_REGION_DEBUG |
|
1184 void selfTest() const; |
|
1185 #endif |
|
1186 }; |
|
1187 |
|
1188 static inline bool isEmptyHelper(const QRegionPrivate *preg) |
|
1189 { |
|
1190 return !preg || preg->numRects == 0; |
|
1191 } |
|
1192 |
|
1193 static inline bool canMergeFromRight(const QRect *left, const QRect *right) |
|
1194 { |
|
1195 return (right->top() == left->top() |
|
1196 && right->bottom() == left->bottom() |
|
1197 && right->left() <= (left->right() + 1)); |
|
1198 } |
|
1199 |
|
1200 static inline bool canMergeFromLeft(const QRect *right, const QRect *left) |
|
1201 { |
|
1202 return canMergeFromRight(left, right); |
|
1203 } |
|
1204 |
|
1205 bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right) |
|
1206 { |
|
1207 if (canMergeFromRight(left, right)) { |
|
1208 left->setRight(right->right()); |
|
1209 updateInnerRect(*left); |
|
1210 return true; |
|
1211 } |
|
1212 return false; |
|
1213 } |
|
1214 |
|
1215 bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left) |
|
1216 { |
|
1217 if (canMergeFromLeft(right, left)) { |
|
1218 right->setLeft(left->left()); |
|
1219 updateInnerRect(*right); |
|
1220 return true; |
|
1221 } |
|
1222 return false; |
|
1223 } |
|
1224 |
|
1225 static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom, |
|
1226 const QRect *nextToTop, |
|
1227 const QRect *nextToBottom) |
|
1228 { |
|
1229 if (nextToTop && nextToTop->y() == top->y()) |
|
1230 return false; |
|
1231 if (nextToBottom && nextToBottom->y() == bottom->y()) |
|
1232 return false; |
|
1233 |
|
1234 return ((top->bottom() >= (bottom->top() - 1)) |
|
1235 && top->left() == bottom->left() |
|
1236 && top->right() == bottom->right()); |
|
1237 } |
|
1238 |
|
1239 bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom, |
|
1240 const QRect *nextToTop, |
|
1241 const QRect *nextToBottom) |
|
1242 { |
|
1243 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) { |
|
1244 top->setBottom(bottom->bottom()); |
|
1245 updateInnerRect(*top); |
|
1246 return true; |
|
1247 } |
|
1248 return false; |
|
1249 } |
|
1250 |
|
1251 bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top, |
|
1252 const QRect *nextToBottom, |
|
1253 const QRect *nextToTop) |
|
1254 { |
|
1255 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) { |
|
1256 bottom->setTop(top->top()); |
|
1257 updateInnerRect(*bottom); |
|
1258 return true; |
|
1259 } |
|
1260 return false; |
|
1261 } |
|
1262 |
|
1263 static inline QRect qt_rect_intersect_normalized(const QRect &r1, |
|
1264 const QRect &r2) |
|
1265 { |
|
1266 QRect r; |
|
1267 r.setLeft(qMax(r1.left(), r2.left())); |
|
1268 r.setRight(qMin(r1.right(), r2.right())); |
|
1269 r.setTop(qMax(r1.top(), r2.top())); |
|
1270 r.setBottom(qMin(r1.bottom(), r2.bottom())); |
|
1271 return r; |
|
1272 } |
|
1273 |
|
1274 void QRegionPrivate::intersect(const QRect &rect) |
|
1275 { |
|
1276 Q_ASSERT(extents.intersects(rect)); |
|
1277 Q_ASSERT(numRects > 1); |
|
1278 |
|
1279 #ifdef QT_REGION_DEBUG |
|
1280 selfTest(); |
|
1281 #endif |
|
1282 |
|
1283 const QRect r = rect.normalized(); |
|
1284 extents = QRect(); |
|
1285 innerRect = QRect(); |
|
1286 innerArea = -1; |
|
1287 |
|
1288 QRect *dest = rects.data(); |
|
1289 const QRect *src = dest; |
|
1290 int n = numRects; |
|
1291 numRects = 0; |
|
1292 while (n--) { |
|
1293 *dest = qt_rect_intersect_normalized(*src++, r); |
|
1294 if (dest->isEmpty()) |
|
1295 continue; |
|
1296 |
|
1297 if (numRects == 0) { |
|
1298 extents = *dest; |
|
1299 } else { |
|
1300 extents.setLeft(qMin(extents.left(), dest->left())); |
|
1301 // hw: extents.top() will never change after initialization |
|
1302 //extents.setTop(qMin(extents.top(), dest->top())); |
|
1303 extents.setRight(qMax(extents.right(), dest->right())); |
|
1304 extents.setBottom(qMax(extents.bottom(), dest->bottom())); |
|
1305 |
|
1306 const QRect *nextToLast = (numRects > 1 ? dest - 2 : 0); |
|
1307 |
|
1308 // mergeFromBelow inlined and optimized |
|
1309 if (canMergeFromBelow(dest - 1, dest, nextToLast, 0)) { |
|
1310 if (!n || src->y() != dest->y() || src->left() > r.right()) { |
|
1311 QRect *prev = dest - 1; |
|
1312 prev->setBottom(dest->bottom()); |
|
1313 updateInnerRect(*prev); |
|
1314 continue; |
|
1315 } |
|
1316 } |
|
1317 } |
|
1318 updateInnerRect(*dest); |
|
1319 ++dest; |
|
1320 ++numRects; |
|
1321 } |
|
1322 #ifdef QT_REGION_DEBUG |
|
1323 selfTest(); |
|
1324 #endif |
|
1325 } |
|
1326 |
|
1327 void QRegionPrivate::append(const QRect *r) |
|
1328 { |
|
1329 Q_ASSERT(!r->isEmpty()); |
|
1330 |
|
1331 QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1)); |
|
1332 if (mergeFromRight(myLast, r)) { |
|
1333 if (numRects > 1) { |
|
1334 const QRect *nextToTop = (numRects > 2 ? myLast - 2 : 0); |
|
1335 if (mergeFromBelow(myLast - 1, myLast, nextToTop, 0)) |
|
1336 --numRects; |
|
1337 } |
|
1338 } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : 0), 0)) { |
|
1339 // nothing |
|
1340 } else { |
|
1341 vectorize(); |
|
1342 ++numRects; |
|
1343 updateInnerRect(*r); |
|
1344 if (rects.size() < numRects) |
|
1345 rects.resize(numRects); |
|
1346 rects[numRects - 1] = *r; |
|
1347 } |
|
1348 extents.setCoords(qMin(extents.left(), r->left()), |
|
1349 qMin(extents.top(), r->top()), |
|
1350 qMax(extents.right(), r->right()), |
|
1351 qMax(extents.bottom(), r->bottom())); |
|
1352 |
|
1353 #ifdef QT_REGION_DEBUG |
|
1354 selfTest(); |
|
1355 #endif |
|
1356 } |
|
1357 |
|
1358 void QRegionPrivate::append(const QRegionPrivate *r) |
|
1359 { |
|
1360 Q_ASSERT(!isEmptyHelper(r)); |
|
1361 |
|
1362 if (r->numRects == 1) { |
|
1363 append(&r->extents); |
|
1364 return; |
|
1365 } |
|
1366 |
|
1367 vectorize(); |
|
1368 |
|
1369 QRect *destRect = rects.data() + numRects; |
|
1370 const QRect *srcRect = r->rects.constData(); |
|
1371 int numAppend = r->numRects; |
|
1372 |
|
1373 // try merging |
|
1374 { |
|
1375 const QRect *rFirst = srcRect; |
|
1376 QRect *myLast = destRect - 1; |
|
1377 const QRect *nextToLast = (numRects > 1 ? myLast - 1 : 0); |
|
1378 if (mergeFromRight(myLast, rFirst)) { |
|
1379 ++srcRect; |
|
1380 --numAppend; |
|
1381 const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : 0); |
|
1382 if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) { |
|
1383 ++srcRect; |
|
1384 --numAppend; |
|
1385 } |
|
1386 if (numRects > 1) { |
|
1387 nextToLast = (numRects > 2 ? myLast - 2 : 0); |
|
1388 rNextToFirst = (numAppend > 0 ? srcRect : 0); |
|
1389 if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) { |
|
1390 --destRect; |
|
1391 --numRects; |
|
1392 } |
|
1393 } |
|
1394 } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) { |
|
1395 ++srcRect; |
|
1396 --numAppend; |
|
1397 } |
|
1398 } |
|
1399 |
|
1400 // append rectangles |
|
1401 if (numAppend > 0) { |
|
1402 const int newNumRects = numRects + numAppend; |
|
1403 if (newNumRects > rects.size()) { |
|
1404 rects.resize(newNumRects); |
|
1405 destRect = rects.data() + numRects; |
|
1406 } |
|
1407 memcpy(destRect, srcRect, numAppend * sizeof(QRect)); |
|
1408 |
|
1409 numRects = newNumRects; |
|
1410 } |
|
1411 |
|
1412 // update inner rectangle |
|
1413 if (innerArea < r->innerArea) { |
|
1414 innerArea = r->innerArea; |
|
1415 innerRect = r->innerRect; |
|
1416 } |
|
1417 |
|
1418 // update extents |
|
1419 destRect = &extents; |
|
1420 srcRect = &r->extents; |
|
1421 extents.setCoords(qMin(destRect->left(), srcRect->left()), |
|
1422 qMin(destRect->top(), srcRect->top()), |
|
1423 qMax(destRect->right(), srcRect->right()), |
|
1424 qMax(destRect->bottom(), srcRect->bottom())); |
|
1425 |
|
1426 #ifdef QT_REGION_DEBUG |
|
1427 selfTest(); |
|
1428 #endif |
|
1429 } |
|
1430 |
|
1431 void QRegionPrivate::prepend(const QRegionPrivate *r) |
|
1432 { |
|
1433 Q_ASSERT(!isEmptyHelper(r)); |
|
1434 |
|
1435 if (r->numRects == 1) { |
|
1436 prepend(&r->extents); |
|
1437 return; |
|
1438 } |
|
1439 |
|
1440 vectorize(); |
|
1441 |
|
1442 int numPrepend = r->numRects; |
|
1443 int numSkip = 0; |
|
1444 |
|
1445 // try merging |
|
1446 { |
|
1447 QRect *myFirst = rects.data(); |
|
1448 const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : 0); |
|
1449 const QRect *rLast = r->rects.constData() + r->numRects - 1; |
|
1450 const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : 0); |
|
1451 if (mergeFromLeft(myFirst, rLast)) { |
|
1452 --numPrepend; |
|
1453 --rLast; |
|
1454 rNextToLast = (numPrepend > 1 ? rLast - 1 : 0); |
|
1455 if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) { |
|
1456 --numPrepend; |
|
1457 --rLast; |
|
1458 } |
|
1459 if (numRects > 1) { |
|
1460 nextToFirst = (numRects > 2? myFirst + 2 : 0); |
|
1461 rNextToLast = (numPrepend > 0 ? rLast : 0); |
|
1462 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) { |
|
1463 --numRects; |
|
1464 ++numSkip; |
|
1465 } |
|
1466 } |
|
1467 } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) { |
|
1468 --numPrepend; |
|
1469 } |
|
1470 } |
|
1471 |
|
1472 if (numPrepend > 0) { |
|
1473 const int newNumRects = numRects + numPrepend; |
|
1474 if (newNumRects > rects.size()) |
|
1475 rects.resize(newNumRects); |
|
1476 |
|
1477 // move existing rectangles |
|
1478 memmove(rects.data() + numPrepend, rects.constData() + numSkip, |
|
1479 numRects * sizeof(QRect)); |
|
1480 |
|
1481 // prepend new rectangles |
|
1482 memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect)); |
|
1483 |
|
1484 numRects = newNumRects; |
|
1485 } |
|
1486 |
|
1487 // update inner rectangle |
|
1488 if (innerArea < r->innerArea) { |
|
1489 innerArea = r->innerArea; |
|
1490 innerRect = r->innerRect; |
|
1491 } |
|
1492 |
|
1493 // update extents |
|
1494 extents.setCoords(qMin(extents.left(), r->extents.left()), |
|
1495 qMin(extents.top(), r->extents.top()), |
|
1496 qMax(extents.right(), r->extents.right()), |
|
1497 qMax(extents.bottom(), r->extents.bottom())); |
|
1498 |
|
1499 #ifdef QT_REGION_DEBUG |
|
1500 selfTest(); |
|
1501 #endif |
|
1502 } |
|
1503 |
|
1504 void QRegionPrivate::prepend(const QRect *r) |
|
1505 { |
|
1506 Q_ASSERT(!r->isEmpty()); |
|
1507 |
|
1508 QRect *myFirst = (numRects == 1 ? &extents : rects.data()); |
|
1509 if (mergeFromLeft(myFirst, r)) { |
|
1510 if (numRects > 1) { |
|
1511 const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : 0); |
|
1512 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, 0)) { |
|
1513 --numRects; |
|
1514 memmove(rects.data(), rects.constData() + 1, |
|
1515 numRects * sizeof(QRect)); |
|
1516 } |
|
1517 } |
|
1518 } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : 0), 0)) { |
|
1519 // nothing |
|
1520 } else { |
|
1521 vectorize(); |
|
1522 ++numRects; |
|
1523 updateInnerRect(*r); |
|
1524 rects.prepend(*r); |
|
1525 } |
|
1526 extents.setCoords(qMin(extents.left(), r->left()), |
|
1527 qMin(extents.top(), r->top()), |
|
1528 qMax(extents.right(), r->right()), |
|
1529 qMax(extents.bottom(), r->bottom())); |
|
1530 |
|
1531 #ifdef QT_REGION_DEBUG |
|
1532 selfTest(); |
|
1533 #endif |
|
1534 } |
|
1535 |
|
1536 bool QRegionPrivate::canAppend(const QRect *r) const |
|
1537 { |
|
1538 Q_ASSERT(!r->isEmpty()); |
|
1539 |
|
1540 const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1)); |
|
1541 if (r->top() > myLast->bottom()) |
|
1542 return true; |
|
1543 if (r->top() == myLast->top() |
|
1544 && r->height() == myLast->height() |
|
1545 && r->left() > myLast->right()) |
|
1546 { |
|
1547 return true; |
|
1548 } |
|
1549 |
|
1550 return false; |
|
1551 } |
|
1552 |
|
1553 bool QRegionPrivate::canAppend(const QRegionPrivate *r) const |
|
1554 { |
|
1555 return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData()); |
|
1556 } |
|
1557 |
|
1558 bool QRegionPrivate::canPrepend(const QRect *r) const |
|
1559 { |
|
1560 Q_ASSERT(!r->isEmpty()); |
|
1561 |
|
1562 const QRect *myFirst = (numRects == 1) ? &extents : rects.constData(); |
|
1563 if (r->bottom() < myFirst->top()) // not overlapping |
|
1564 return true; |
|
1565 if (r->top() == myFirst->top() |
|
1566 && r->height() == myFirst->height() |
|
1567 && r->right() < myFirst->left()) |
|
1568 { |
|
1569 return true; |
|
1570 } |
|
1571 |
|
1572 return false; |
|
1573 } |
|
1574 |
|
1575 bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const |
|
1576 { |
|
1577 return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1); |
|
1578 } |
|
1579 |
|
1580 #ifdef QT_REGION_DEBUG |
|
1581 void QRegionPrivate::selfTest() const |
|
1582 { |
|
1583 if (numRects == 0) { |
|
1584 Q_ASSERT(extents.isEmpty()); |
|
1585 Q_ASSERT(innerRect.isEmpty()); |
|
1586 return; |
|
1587 } |
|
1588 |
|
1589 Q_ASSERT(innerArea == (innerRect.width() * innerRect.height())); |
|
1590 |
|
1591 if (numRects == 1) { |
|
1592 Q_ASSERT(innerRect == extents); |
|
1593 Q_ASSERT(!innerRect.isEmpty()); |
|
1594 return; |
|
1595 } |
|
1596 |
|
1597 for (int i = 0; i < numRects; ++i) { |
|
1598 const QRect r = rects.at(i); |
|
1599 if ((r.width() * r.height()) > innerArea) |
|
1600 qDebug() << "selfTest(): innerRect" << innerRect << '<' << r; |
|
1601 } |
|
1602 |
|
1603 QRect r = rects.first(); |
|
1604 for (int i = 1; i < numRects; ++i) { |
|
1605 const QRect r2 = rects.at(i); |
|
1606 Q_ASSERT(!r2.isEmpty()); |
|
1607 if (r2.y() == r.y()) { |
|
1608 Q_ASSERT(r.bottom() == r2.bottom()); |
|
1609 Q_ASSERT(r.right() < (r2.left() + 1)); |
|
1610 } else { |
|
1611 Q_ASSERT(r2.y() >= r.bottom()); |
|
1612 } |
|
1613 r = r2; |
|
1614 } |
|
1615 } |
|
1616 #endif // QT_REGION_DEBUG |
|
1617 |
|
1618 #if defined(Q_WS_X11) |
|
1619 QT_BEGIN_INCLUDE_NAMESPACE |
|
1620 # include "qregion_x11.cpp" |
|
1621 QT_END_INCLUDE_NAMESPACE |
|
1622 #elif defined(Q_WS_MAC) |
|
1623 QT_BEGIN_INCLUDE_NAMESPACE |
|
1624 # include "qregion_mac.cpp" |
|
1625 QT_END_INCLUDE_NAMESPACE |
|
1626 #elif defined(Q_WS_WIN) |
|
1627 QT_BEGIN_INCLUDE_NAMESPACE |
|
1628 # include "qregion_win.cpp" |
|
1629 QT_END_INCLUDE_NAMESPACE |
|
1630 #elif defined(Q_WS_QWS) |
|
1631 static QRegionPrivate qrp; |
|
1632 QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp}; |
|
1633 #endif |
|
1634 |
|
1635 typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, |
|
1636 register const QRect *r2, const QRect *r2End, register int y1, register int y2); |
|
1637 typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd, |
|
1638 register int y1, register int y2); |
|
1639 |
|
1640 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2); |
|
1641 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest); |
|
1642 static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2, |
|
1643 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func, |
|
1644 NonOverlapFunc nonOverlap2Func); |
|
1645 |
|
1646 #define RectangleOut 0 |
|
1647 #define RectangleIn 1 |
|
1648 #define RectanglePart 2 |
|
1649 #define EvenOddRule 0 |
|
1650 #define WindingRule 1 |
|
1651 |
|
1652 // START OF region.h extract |
|
1653 /* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */ |
|
1654 /************************************************************************ |
|
1655 |
|
1656 Copyright (c) 1987 X Consortium |
|
1657 |
|
1658 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
1659 of this software and associated documentation files (the "Software"), to deal |
|
1660 in the Software without restriction, including without limitation the rights |
|
1661 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
1662 copies of the Software, and to permit persons to whom the Software is |
|
1663 furnished to do so, subject to the following conditions: |
|
1664 |
|
1665 The above copyright notice and this permission notice shall be included in |
|
1666 all copies or substantial portions of the Software. |
|
1667 |
|
1668 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
1669 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
1670 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
1671 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
1672 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
1673 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
1674 |
|
1675 Except as contained in this notice, the name of the X Consortium shall not be |
|
1676 used in advertising or otherwise to promote the sale, use or other dealings |
|
1677 in this Software without prior written authorization from the X Consortium. |
|
1678 |
|
1679 |
|
1680 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. |
|
1681 |
|
1682 All Rights Reserved |
|
1683 |
|
1684 Permission to use, copy, modify, and distribute this software and its |
|
1685 documentation for any purpose and without fee is hereby granted, |
|
1686 provided that the above copyright notice appear in all copies and that |
|
1687 both that copyright notice and this permission notice appear in |
|
1688 supporting documentation, and that the name of Digital not be |
|
1689 used in advertising or publicity pertaining to distribution of the |
|
1690 software without specific, written prior permission. |
|
1691 |
|
1692 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
1693 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
1694 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
1695 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
1696 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
1697 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
1698 SOFTWARE. |
|
1699 |
|
1700 ************************************************************************/ |
|
1701 |
|
1702 #ifndef _XREGION_H |
|
1703 #define _XREGION_H |
|
1704 |
|
1705 QT_BEGIN_INCLUDE_NAMESPACE |
|
1706 #include <limits.h> |
|
1707 QT_END_INCLUDE_NAMESPACE |
|
1708 |
|
1709 /* 1 if two BOXs overlap. |
|
1710 * 0 if two BOXs do not overlap. |
|
1711 * Remember, x2 and y2 are not in the region |
|
1712 */ |
|
1713 #define EXTENTCHECK(r1, r2) \ |
|
1714 ((r1)->right() >= (r2)->left() && \ |
|
1715 (r1)->left() <= (r2)->right() && \ |
|
1716 (r1)->bottom() >= (r2)->top() && \ |
|
1717 (r1)->top() <= (r2)->bottom()) |
|
1718 |
|
1719 /* |
|
1720 * update region extents |
|
1721 */ |
|
1722 #define EXTENTS(r,idRect){\ |
|
1723 if((r)->left() < (idRect)->extents.left())\ |
|
1724 (idRect)->extents.setLeft((r)->left());\ |
|
1725 if((r)->top() < (idRect)->extents.top())\ |
|
1726 (idRect)->extents.setTop((r)->top());\ |
|
1727 if((r)->right() > (idRect)->extents.right())\ |
|
1728 (idRect)->extents.setRight((r)->right());\ |
|
1729 if((r)->bottom() > (idRect)->extents.bottom())\ |
|
1730 (idRect)->extents.setBottom((r)->bottom());\ |
|
1731 } |
|
1732 |
|
1733 /* |
|
1734 * Check to see if there is enough memory in the present region. |
|
1735 */ |
|
1736 #define MEMCHECK(dest, rect, firstrect){\ |
|
1737 if ((dest).numRects >= ((dest).rects.size()-1)){\ |
|
1738 firstrect.resize(firstrect.size() * 2); \ |
|
1739 (rect) = (firstrect).data() + (dest).numRects;\ |
|
1740 }\ |
|
1741 } |
|
1742 |
|
1743 |
|
1744 /* |
|
1745 * number of points to buffer before sending them off |
|
1746 * to scanlines(): Must be an even number |
|
1747 */ |
|
1748 #define NUMPTSTOBUFFER 200 |
|
1749 |
|
1750 /* |
|
1751 * used to allocate buffers for points and link |
|
1752 * the buffers together |
|
1753 */ |
|
1754 typedef struct _POINTBLOCK { |
|
1755 int data[NUMPTSTOBUFFER * sizeof(QPoint)]; |
|
1756 QPoint *pts; |
|
1757 struct _POINTBLOCK *next; |
|
1758 } POINTBLOCK; |
|
1759 |
|
1760 #endif |
|
1761 // END OF region.h extract |
|
1762 |
|
1763 // START OF Region.c extract |
|
1764 /* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */ |
|
1765 /************************************************************************ |
|
1766 |
|
1767 Copyright (c) 1987, 1988 X Consortium |
|
1768 |
|
1769 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
1770 of this software and associated documentation files (the "Software"), to deal |
|
1771 in the Software without restriction, including without limitation the rights |
|
1772 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
1773 copies of the Software, and to permit persons to whom the Software is |
|
1774 furnished to do so, subject to the following conditions: |
|
1775 |
|
1776 The above copyright notice and this permission notice shall be included in |
|
1777 all copies or substantial portions of the Software. |
|
1778 |
|
1779 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
1780 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
1781 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
1782 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
1783 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
1784 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
1785 |
|
1786 Except as contained in this notice, the name of the X Consortium shall not be |
|
1787 used in advertising or otherwise to promote the sale, use or other dealings |
|
1788 in this Software without prior written authorization from the X Consortium. |
|
1789 |
|
1790 |
|
1791 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. |
|
1792 |
|
1793 All Rights Reserved |
|
1794 |
|
1795 Permission to use, copy, modify, and distribute this software and its |
|
1796 documentation for any purpose and without fee is hereby granted, |
|
1797 provided that the above copyright notice appear in all copies and that |
|
1798 both that copyright notice and this permission notice appear in |
|
1799 supporting documentation, and that the name of Digital not be |
|
1800 used in advertising or publicity pertaining to distribution of the |
|
1801 software without specific, written prior permission. |
|
1802 |
|
1803 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
1804 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
1805 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
1806 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
1807 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
1808 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
1809 SOFTWARE. |
|
1810 |
|
1811 ************************************************************************/ |
|
1812 /* |
|
1813 * The functions in this file implement the Region abstraction, similar to one |
|
1814 * used in the X11 sample server. A Region is simply an area, as the name |
|
1815 * implies, and is implemented as a "y-x-banded" array of rectangles. To |
|
1816 * explain: Each Region is made up of a certain number of rectangles sorted |
|
1817 * by y coordinate first, and then by x coordinate. |
|
1818 * |
|
1819 * Furthermore, the rectangles are banded such that every rectangle with a |
|
1820 * given upper-left y coordinate (y1) will have the same lower-right y |
|
1821 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it |
|
1822 * will span the entire vertical distance of the band. This means that some |
|
1823 * areas that could be merged into a taller rectangle will be represented as |
|
1824 * several shorter rectangles to account for shorter rectangles to its left |
|
1825 * or right but within its "vertical scope". |
|
1826 * |
|
1827 * An added constraint on the rectangles is that they must cover as much |
|
1828 * horizontal area as possible. E.g. no two rectangles in a band are allowed |
|
1829 * to touch. |
|
1830 * |
|
1831 * Whenever possible, bands will be merged together to cover a greater vertical |
|
1832 * distance (and thus reduce the number of rectangles). Two bands can be merged |
|
1833 * only if the bottom of one touches the top of the other and they have |
|
1834 * rectangles in the same places (of the same width, of course). This maintains |
|
1835 * the y-x-banding that's so nice to have... |
|
1836 */ |
|
1837 /* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */ |
|
1838 |
|
1839 static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source, |
|
1840 QRegionPrivate &dest) |
|
1841 { |
|
1842 if (rect->isEmpty()) |
|
1843 return; |
|
1844 |
|
1845 Q_ASSERT(EqualRegion(source, &dest)); |
|
1846 |
|
1847 if (dest.numRects == 0) { |
|
1848 dest = QRegionPrivate(*rect); |
|
1849 } else if (dest.canAppend(rect)) { |
|
1850 dest.append(rect); |
|
1851 } else { |
|
1852 QRegionPrivate p(*rect); |
|
1853 UnionRegion(&p, source, dest); |
|
1854 } |
|
1855 } |
|
1856 |
|
1857 /*- |
|
1858 *----------------------------------------------------------------------- |
|
1859 * miSetExtents -- |
|
1860 * Reset the extents and innerRect of a region to what they should be. |
|
1861 * Called by miSubtract and miIntersect b/c they can't figure it out |
|
1862 * along the way or do so easily, as miUnion can. |
|
1863 * |
|
1864 * Results: |
|
1865 * None. |
|
1866 * |
|
1867 * Side Effects: |
|
1868 * The region's 'extents' and 'innerRect' structure is overwritten. |
|
1869 * |
|
1870 *----------------------------------------------------------------------- |
|
1871 */ |
|
1872 static void miSetExtents(QRegionPrivate &dest) |
|
1873 { |
|
1874 register const QRect *pBox, |
|
1875 *pBoxEnd; |
|
1876 register QRect *pExtents; |
|
1877 |
|
1878 dest.innerRect.setCoords(0, 0, -1, -1); |
|
1879 dest.innerArea = -1; |
|
1880 if (dest.numRects == 0) { |
|
1881 dest.extents.setCoords(0, 0, -1, -1); |
|
1882 return; |
|
1883 } |
|
1884 |
|
1885 pExtents = &dest.extents; |
|
1886 if (dest.rects.isEmpty()) |
|
1887 pBox = &dest.extents; |
|
1888 else |
|
1889 pBox = dest.rects.constData(); |
|
1890 pBoxEnd = pBox + dest.numRects - 1; |
|
1891 |
|
1892 /* |
|
1893 * Since pBox is the first rectangle in the region, it must have the |
|
1894 * smallest y1 and since pBoxEnd is the last rectangle in the region, |
|
1895 * it must have the largest y2, because of banding. Initialize x1 and |
|
1896 * x2 from pBox and pBoxEnd, resp., as good things to initialize them |
|
1897 * to... |
|
1898 */ |
|
1899 pExtents->setLeft(pBox->left()); |
|
1900 pExtents->setTop(pBox->top()); |
|
1901 pExtents->setRight(pBoxEnd->right()); |
|
1902 pExtents->setBottom(pBoxEnd->bottom()); |
|
1903 |
|
1904 Q_ASSERT(pExtents->top() <= pExtents->bottom()); |
|
1905 while (pBox <= pBoxEnd) { |
|
1906 if (pBox->left() < pExtents->left()) |
|
1907 pExtents->setLeft(pBox->left()); |
|
1908 if (pBox->right() > pExtents->right()) |
|
1909 pExtents->setRight(pBox->right()); |
|
1910 dest.updateInnerRect(*pBox); |
|
1911 ++pBox; |
|
1912 } |
|
1913 Q_ASSERT(pExtents->left() <= pExtents->right()); |
|
1914 } |
|
1915 |
|
1916 /* TranslateRegion(pRegion, x, y) |
|
1917 translates in place |
|
1918 added by raymond |
|
1919 */ |
|
1920 |
|
1921 static void OffsetRegion(register QRegionPrivate ®ion, register int x, register int y) |
|
1922 { |
|
1923 if (region.rects.size()) { |
|
1924 register QRect *pbox = region.rects.data(); |
|
1925 register int nbox = region.numRects; |
|
1926 |
|
1927 while (nbox--) { |
|
1928 pbox->translate(x, y); |
|
1929 ++pbox; |
|
1930 } |
|
1931 } |
|
1932 region.extents.translate(x, y); |
|
1933 region.innerRect.translate(x, y); |
|
1934 } |
|
1935 |
|
1936 /*====================================================================== |
|
1937 * Region Intersection |
|
1938 *====================================================================*/ |
|
1939 /*- |
|
1940 *----------------------------------------------------------------------- |
|
1941 * miIntersectO -- |
|
1942 * Handle an overlapping band for miIntersect. |
|
1943 * |
|
1944 * Results: |
|
1945 * None. |
|
1946 * |
|
1947 * Side Effects: |
|
1948 * Rectangles may be added to the region. |
|
1949 * |
|
1950 *----------------------------------------------------------------------- |
|
1951 */ |
|
1952 static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, |
|
1953 register const QRect *r2, const QRect *r2End, int y1, int y2) |
|
1954 { |
|
1955 register int x1; |
|
1956 register int x2; |
|
1957 register QRect *pNextRect; |
|
1958 |
|
1959 pNextRect = dest.rects.data() + dest.numRects; |
|
1960 |
|
1961 while (r1 != r1End && r2 != r2End) { |
|
1962 x1 = qMax(r1->left(), r2->left()); |
|
1963 x2 = qMin(r1->right(), r2->right()); |
|
1964 |
|
1965 /* |
|
1966 * If there's any overlap between the two rectangles, add that |
|
1967 * overlap to the new region. |
|
1968 * There's no need to check for subsumption because the only way |
|
1969 * such a need could arise is if some region has two rectangles |
|
1970 * right next to each other. Since that should never happen... |
|
1971 */ |
|
1972 if (x1 <= x2) { |
|
1973 Q_ASSERT(y1 <= y2); |
|
1974 MEMCHECK(dest, pNextRect, dest.rects) |
|
1975 pNextRect->setCoords(x1, y1, x2, y2); |
|
1976 ++dest.numRects; |
|
1977 ++pNextRect; |
|
1978 } |
|
1979 |
|
1980 /* |
|
1981 * Need to advance the pointers. Shift the one that extends |
|
1982 * to the right the least, since the other still has a chance to |
|
1983 * overlap with that region's next rectangle, if you see what I mean. |
|
1984 */ |
|
1985 if (r1->right() < r2->right()) { |
|
1986 ++r1; |
|
1987 } else if (r2->right() < r1->right()) { |
|
1988 ++r2; |
|
1989 } else { |
|
1990 ++r1; |
|
1991 ++r2; |
|
1992 } |
|
1993 } |
|
1994 } |
|
1995 |
|
1996 /*====================================================================== |
|
1997 * Generic Region Operator |
|
1998 *====================================================================*/ |
|
1999 |
|
2000 /*- |
|
2001 *----------------------------------------------------------------------- |
|
2002 * miCoalesce -- |
|
2003 * Attempt to merge the boxes in the current band with those in the |
|
2004 * previous one. Used only by miRegionOp. |
|
2005 * |
|
2006 * Results: |
|
2007 * The new index for the previous band. |
|
2008 * |
|
2009 * Side Effects: |
|
2010 * If coalescing takes place: |
|
2011 * - rectangles in the previous band will have their y2 fields |
|
2012 * altered. |
|
2013 * - dest.numRects will be decreased. |
|
2014 * |
|
2015 *----------------------------------------------------------------------- |
|
2016 */ |
|
2017 static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart) |
|
2018 { |
|
2019 register QRect *pPrevBox; /* Current box in previous band */ |
|
2020 register QRect *pCurBox; /* Current box in current band */ |
|
2021 register QRect *pRegEnd; /* End of region */ |
|
2022 int curNumRects; /* Number of rectangles in current band */ |
|
2023 int prevNumRects; /* Number of rectangles in previous band */ |
|
2024 int bandY1; /* Y1 coordinate for current band */ |
|
2025 QRect *rData = dest.rects.data(); |
|
2026 |
|
2027 pRegEnd = rData + dest.numRects; |
|
2028 |
|
2029 pPrevBox = rData + prevStart; |
|
2030 prevNumRects = curStart - prevStart; |
|
2031 |
|
2032 /* |
|
2033 * Figure out how many rectangles are in the current band. Have to do |
|
2034 * this because multiple bands could have been added in miRegionOp |
|
2035 * at the end when one region has been exhausted. |
|
2036 */ |
|
2037 pCurBox = rData + curStart; |
|
2038 bandY1 = pCurBox->top(); |
|
2039 for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) { |
|
2040 ++pCurBox; |
|
2041 } |
|
2042 |
|
2043 if (pCurBox != pRegEnd) { |
|
2044 /* |
|
2045 * If more than one band was added, we have to find the start |
|
2046 * of the last band added so the next coalescing job can start |
|
2047 * at the right place... (given when multiple bands are added, |
|
2048 * this may be pointless -- see above). |
|
2049 */ |
|
2050 --pRegEnd; |
|
2051 while ((pRegEnd - 1)->top() == pRegEnd->top()) |
|
2052 --pRegEnd; |
|
2053 curStart = pRegEnd - rData; |
|
2054 pRegEnd = rData + dest.numRects; |
|
2055 } |
|
2056 |
|
2057 if (curNumRects == prevNumRects && curNumRects != 0) { |
|
2058 pCurBox -= curNumRects; |
|
2059 /* |
|
2060 * The bands may only be coalesced if the bottom of the previous |
|
2061 * matches the top scanline of the current. |
|
2062 */ |
|
2063 if (pPrevBox->bottom() == pCurBox->top() - 1) { |
|
2064 /* |
|
2065 * Make sure the bands have boxes in the same places. This |
|
2066 * assumes that boxes have been added in such a way that they |
|
2067 * cover the most area possible. I.e. two boxes in a band must |
|
2068 * have some horizontal space between them. |
|
2069 */ |
|
2070 do { |
|
2071 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) { |
|
2072 // The bands don't line up so they can't be coalesced. |
|
2073 return curStart; |
|
2074 } |
|
2075 ++pPrevBox; |
|
2076 ++pCurBox; |
|
2077 --prevNumRects; |
|
2078 } while (prevNumRects != 0); |
|
2079 |
|
2080 dest.numRects -= curNumRects; |
|
2081 pCurBox -= curNumRects; |
|
2082 pPrevBox -= curNumRects; |
|
2083 |
|
2084 /* |
|
2085 * The bands may be merged, so set the bottom y of each box |
|
2086 * in the previous band to that of the corresponding box in |
|
2087 * the current band. |
|
2088 */ |
|
2089 do { |
|
2090 pPrevBox->setBottom(pCurBox->bottom()); |
|
2091 dest.updateInnerRect(*pPrevBox); |
|
2092 ++pPrevBox; |
|
2093 ++pCurBox; |
|
2094 curNumRects -= 1; |
|
2095 } while (curNumRects != 0); |
|
2096 |
|
2097 /* |
|
2098 * If only one band was added to the region, we have to backup |
|
2099 * curStart to the start of the previous band. |
|
2100 * |
|
2101 * If more than one band was added to the region, copy the |
|
2102 * other bands down. The assumption here is that the other bands |
|
2103 * came from the same region as the current one and no further |
|
2104 * coalescing can be done on them since it's all been done |
|
2105 * already... curStart is already in the right place. |
|
2106 */ |
|
2107 if (pCurBox == pRegEnd) { |
|
2108 curStart = prevStart; |
|
2109 } else { |
|
2110 do { |
|
2111 *pPrevBox++ = *pCurBox++; |
|
2112 dest.updateInnerRect(*pPrevBox); |
|
2113 } while (pCurBox != pRegEnd); |
|
2114 } |
|
2115 } |
|
2116 } |
|
2117 return curStart; |
|
2118 } |
|
2119 |
|
2120 /*- |
|
2121 *----------------------------------------------------------------------- |
|
2122 * miRegionOp -- |
|
2123 * Apply an operation to two regions. Called by miUnion, miInverse, |
|
2124 * miSubtract, miIntersect... |
|
2125 * |
|
2126 * Results: |
|
2127 * None. |
|
2128 * |
|
2129 * Side Effects: |
|
2130 * The new region is overwritten. |
|
2131 * |
|
2132 * Notes: |
|
2133 * The idea behind this function is to view the two regions as sets. |
|
2134 * Together they cover a rectangle of area that this function divides |
|
2135 * into horizontal bands where points are covered only by one region |
|
2136 * or by both. For the first case, the nonOverlapFunc is called with |
|
2137 * each the band and the band's upper and lower extents. For the |
|
2138 * second, the overlapFunc is called to process the entire band. It |
|
2139 * is responsible for clipping the rectangles in the band, though |
|
2140 * this function provides the boundaries. |
|
2141 * At the end of each band, the new region is coalesced, if possible, |
|
2142 * to reduce the number of rectangles in the region. |
|
2143 * |
|
2144 *----------------------------------------------------------------------- |
|
2145 */ |
|
2146 static void miRegionOp(register QRegionPrivate &dest, |
|
2147 const QRegionPrivate *reg1, const QRegionPrivate *reg2, |
|
2148 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func, |
|
2149 NonOverlapFunc nonOverlap2Func) |
|
2150 { |
|
2151 register const QRect *r1; // Pointer into first region |
|
2152 register const QRect *r2; // Pointer into 2d region |
|
2153 const QRect *r1End; // End of 1st region |
|
2154 const QRect *r2End; // End of 2d region |
|
2155 register int ybot; // Bottom of intersection |
|
2156 register int ytop; // Top of intersection |
|
2157 int prevBand; // Index of start of previous band in dest |
|
2158 int curBand; // Index of start of current band in dest |
|
2159 register const QRect *r1BandEnd; // End of current band in r1 |
|
2160 register const QRect *r2BandEnd; // End of current band in r2 |
|
2161 int top; // Top of non-overlapping band |
|
2162 int bot; // Bottom of non-overlapping band |
|
2163 |
|
2164 /* |
|
2165 * Initialization: |
|
2166 * set r1, r2, r1End and r2End appropriately, preserve the important |
|
2167 * parts of the destination region until the end in case it's one of |
|
2168 * the two source regions, then mark the "new" region empty, allocating |
|
2169 * another array of rectangles for it to use. |
|
2170 */ |
|
2171 if (reg1->numRects == 1) |
|
2172 r1 = ®1->extents; |
|
2173 else |
|
2174 r1 = reg1->rects.constData(); |
|
2175 if (reg2->numRects == 1) |
|
2176 r2 = ®2->extents; |
|
2177 else |
|
2178 r2 = reg2->rects.constData(); |
|
2179 |
|
2180 r1End = r1 + reg1->numRects; |
|
2181 r2End = r2 + reg2->numRects; |
|
2182 |
|
2183 dest.vectorize(); |
|
2184 |
|
2185 QVector<QRect> oldRects = dest.rects; |
|
2186 |
|
2187 dest.numRects = 0; |
|
2188 |
|
2189 /* |
|
2190 * Allocate a reasonable number of rectangles for the new region. The idea |
|
2191 * is to allocate enough so the individual functions don't need to |
|
2192 * reallocate and copy the array, which is time consuming, yet we don't |
|
2193 * have to worry about using too much memory. I hope to be able to |
|
2194 * nuke the realloc() at the end of this function eventually. |
|
2195 */ |
|
2196 dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2); |
|
2197 |
|
2198 /* |
|
2199 * Initialize ybot and ytop. |
|
2200 * In the upcoming loop, ybot and ytop serve different functions depending |
|
2201 * on whether the band being handled is an overlapping or non-overlapping |
|
2202 * band. |
|
2203 * In the case of a non-overlapping band (only one of the regions |
|
2204 * has points in the band), ybot is the bottom of the most recent |
|
2205 * intersection and thus clips the top of the rectangles in that band. |
|
2206 * ytop is the top of the next intersection between the two regions and |
|
2207 * serves to clip the bottom of the rectangles in the current band. |
|
2208 * For an overlapping band (where the two regions intersect), ytop clips |
|
2209 * the top of the rectangles of both regions and ybot clips the bottoms. |
|
2210 */ |
|
2211 if (reg1->extents.top() < reg2->extents.top()) |
|
2212 ybot = reg1->extents.top() - 1; |
|
2213 else |
|
2214 ybot = reg2->extents.top() - 1; |
|
2215 |
|
2216 /* |
|
2217 * prevBand serves to mark the start of the previous band so rectangles |
|
2218 * can be coalesced into larger rectangles. qv. miCoalesce, above. |
|
2219 * In the beginning, there is no previous band, so prevBand == curBand |
|
2220 * (curBand is set later on, of course, but the first band will always |
|
2221 * start at index 0). prevBand and curBand must be indices because of |
|
2222 * the possible expansion, and resultant moving, of the new region's |
|
2223 * array of rectangles. |
|
2224 */ |
|
2225 prevBand = 0; |
|
2226 |
|
2227 do { |
|
2228 curBand = dest.numRects; |
|
2229 |
|
2230 /* |
|
2231 * This algorithm proceeds one source-band (as opposed to a |
|
2232 * destination band, which is determined by where the two regions |
|
2233 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the |
|
2234 * rectangle after the last one in the current band for their |
|
2235 * respective regions. |
|
2236 */ |
|
2237 r1BandEnd = r1; |
|
2238 while (r1BandEnd != r1End && r1BandEnd->top() == r1->top()) |
|
2239 ++r1BandEnd; |
|
2240 |
|
2241 r2BandEnd = r2; |
|
2242 while (r2BandEnd != r2End && r2BandEnd->top() == r2->top()) |
|
2243 ++r2BandEnd; |
|
2244 |
|
2245 /* |
|
2246 * First handle the band that doesn't intersect, if any. |
|
2247 * |
|
2248 * Note that attention is restricted to one band in the |
|
2249 * non-intersecting region at once, so if a region has n |
|
2250 * bands between the current position and the next place it overlaps |
|
2251 * the other, this entire loop will be passed through n times. |
|
2252 */ |
|
2253 if (r1->top() < r2->top()) { |
|
2254 top = qMax(r1->top(), ybot + 1); |
|
2255 bot = qMin(r1->bottom(), r2->top() - 1); |
|
2256 |
|
2257 if (nonOverlap1Func != 0 && bot >= top) |
|
2258 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot); |
|
2259 ytop = r2->top(); |
|
2260 } else if (r2->top() < r1->top()) { |
|
2261 top = qMax(r2->top(), ybot + 1); |
|
2262 bot = qMin(r2->bottom(), r1->top() - 1); |
|
2263 |
|
2264 if (nonOverlap2Func != 0 && bot >= top) |
|
2265 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot); |
|
2266 ytop = r1->top(); |
|
2267 } else { |
|
2268 ytop = r1->top(); |
|
2269 } |
|
2270 |
|
2271 /* |
|
2272 * If any rectangles got added to the region, try and coalesce them |
|
2273 * with rectangles from the previous band. Note we could just do |
|
2274 * this test in miCoalesce, but some machines incur a not |
|
2275 * inconsiderable cost for function calls, so... |
|
2276 */ |
|
2277 if (dest.numRects != curBand) |
|
2278 prevBand = miCoalesce(dest, prevBand, curBand); |
|
2279 |
|
2280 /* |
|
2281 * Now see if we've hit an intersecting band. The two bands only |
|
2282 * intersect if ybot >= ytop |
|
2283 */ |
|
2284 ybot = qMin(r1->bottom(), r2->bottom()); |
|
2285 curBand = dest.numRects; |
|
2286 if (ybot >= ytop) |
|
2287 (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); |
|
2288 |
|
2289 if (dest.numRects != curBand) |
|
2290 prevBand = miCoalesce(dest, prevBand, curBand); |
|
2291 |
|
2292 /* |
|
2293 * If we've finished with a band (y2 == ybot) we skip forward |
|
2294 * in the region to the next band. |
|
2295 */ |
|
2296 if (r1->bottom() == ybot) |
|
2297 r1 = r1BandEnd; |
|
2298 if (r2->bottom() == ybot) |
|
2299 r2 = r2BandEnd; |
|
2300 } while (r1 != r1End && r2 != r2End); |
|
2301 |
|
2302 /* |
|
2303 * Deal with whichever region still has rectangles left. |
|
2304 */ |
|
2305 curBand = dest.numRects; |
|
2306 if (r1 != r1End) { |
|
2307 if (nonOverlap1Func != 0) { |
|
2308 do { |
|
2309 r1BandEnd = r1; |
|
2310 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top()) |
|
2311 ++r1BandEnd; |
|
2312 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom()); |
|
2313 r1 = r1BandEnd; |
|
2314 } while (r1 != r1End); |
|
2315 } |
|
2316 } else if ((r2 != r2End) && (nonOverlap2Func != 0)) { |
|
2317 do { |
|
2318 r2BandEnd = r2; |
|
2319 while (r2BandEnd < r2End && r2BandEnd->top() == r2->top()) |
|
2320 ++r2BandEnd; |
|
2321 (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom()); |
|
2322 r2 = r2BandEnd; |
|
2323 } while (r2 != r2End); |
|
2324 } |
|
2325 |
|
2326 if (dest.numRects != curBand) |
|
2327 (void)miCoalesce(dest, prevBand, curBand); |
|
2328 |
|
2329 /* |
|
2330 * A bit of cleanup. To keep regions from growing without bound, |
|
2331 * we shrink the array of rectangles to match the new number of |
|
2332 * rectangles in the region. |
|
2333 * |
|
2334 * Only do this stuff if the number of rectangles allocated is more than |
|
2335 * twice the number of rectangles in the region (a simple optimization). |
|
2336 */ |
|
2337 if (qMax(4, dest.numRects) < (dest.rects.size() >> 1)) |
|
2338 dest.rects.resize(dest.numRects); |
|
2339 } |
|
2340 |
|
2341 /*====================================================================== |
|
2342 * Region Union |
|
2343 *====================================================================*/ |
|
2344 |
|
2345 /*- |
|
2346 *----------------------------------------------------------------------- |
|
2347 * miUnionNonO -- |
|
2348 * Handle a non-overlapping band for the union operation. Just |
|
2349 * Adds the rectangles into the region. Doesn't have to check for |
|
2350 * subsumption or anything. |
|
2351 * |
|
2352 * Results: |
|
2353 * None. |
|
2354 * |
|
2355 * Side Effects: |
|
2356 * dest.numRects is incremented and the final rectangles overwritten |
|
2357 * with the rectangles we're passed. |
|
2358 * |
|
2359 *----------------------------------------------------------------------- |
|
2360 */ |
|
2361 |
|
2362 static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd, |
|
2363 register int y1, register int y2) |
|
2364 { |
|
2365 register QRect *pNextRect; |
|
2366 |
|
2367 pNextRect = dest.rects.data() + dest.numRects; |
|
2368 |
|
2369 Q_ASSERT(y1 <= y2); |
|
2370 |
|
2371 while (r != rEnd) { |
|
2372 Q_ASSERT(r->left() <= r->right()); |
|
2373 MEMCHECK(dest, pNextRect, dest.rects) |
|
2374 pNextRect->setCoords(r->left(), y1, r->right(), y2); |
|
2375 dest.numRects++; |
|
2376 ++pNextRect; |
|
2377 ++r; |
|
2378 } |
|
2379 } |
|
2380 |
|
2381 |
|
2382 /*- |
|
2383 *----------------------------------------------------------------------- |
|
2384 * miUnionO -- |
|
2385 * Handle an overlapping band for the union operation. Picks the |
|
2386 * left-most rectangle each time and merges it into the region. |
|
2387 * |
|
2388 * Results: |
|
2389 * None. |
|
2390 * |
|
2391 * Side Effects: |
|
2392 * Rectangles are overwritten in dest.rects and dest.numRects will |
|
2393 * be changed. |
|
2394 * |
|
2395 *----------------------------------------------------------------------- |
|
2396 */ |
|
2397 |
|
2398 static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, |
|
2399 register const QRect *r2, const QRect *r2End, register int y1, register int y2) |
|
2400 { |
|
2401 register QRect *pNextRect; |
|
2402 |
|
2403 pNextRect = dest.rects.data() + dest.numRects; |
|
2404 |
|
2405 #define MERGERECT(r) \ |
|
2406 if ((dest.numRects != 0) && \ |
|
2407 (pNextRect[-1].top() == y1) && \ |
|
2408 (pNextRect[-1].bottom() == y2) && \ |
|
2409 (pNextRect[-1].right() >= r->left()-1)) { \ |
|
2410 if (pNextRect[-1].right() < r->right()) { \ |
|
2411 pNextRect[-1].setRight(r->right()); \ |
|
2412 dest.updateInnerRect(pNextRect[-1]); \ |
|
2413 Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \ |
|
2414 } \ |
|
2415 } else { \ |
|
2416 MEMCHECK(dest, pNextRect, dest.rects) \ |
|
2417 pNextRect->setCoords(r->left(), y1, r->right(), y2); \ |
|
2418 dest.updateInnerRect(*pNextRect); \ |
|
2419 dest.numRects++; \ |
|
2420 pNextRect++; \ |
|
2421 } \ |
|
2422 r++; |
|
2423 |
|
2424 Q_ASSERT(y1 <= y2); |
|
2425 while (r1 != r1End && r2 != r2End) { |
|
2426 if (r1->left() < r2->left()) { |
|
2427 MERGERECT(r1) |
|
2428 } else { |
|
2429 MERGERECT(r2) |
|
2430 } |
|
2431 } |
|
2432 |
|
2433 if (r1 != r1End) { |
|
2434 do { |
|
2435 MERGERECT(r1) |
|
2436 } while (r1 != r1End); |
|
2437 } else { |
|
2438 while (r2 != r2End) { |
|
2439 MERGERECT(r2) |
|
2440 } |
|
2441 } |
|
2442 } |
|
2443 |
|
2444 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest) |
|
2445 { |
|
2446 Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2)); |
|
2447 Q_ASSERT(!reg1->contains(*reg2)); |
|
2448 Q_ASSERT(!reg2->contains(*reg1)); |
|
2449 Q_ASSERT(!EqualRegion(reg1, reg2)); |
|
2450 Q_ASSERT(!reg1->canAppend(reg2)); |
|
2451 Q_ASSERT(!reg2->canAppend(reg1)); |
|
2452 |
|
2453 if (reg1->innerArea > reg2->innerArea) { |
|
2454 dest.innerArea = reg1->innerArea; |
|
2455 dest.innerRect = reg1->innerRect; |
|
2456 } else { |
|
2457 dest.innerArea = reg2->innerArea; |
|
2458 dest.innerRect = reg2->innerRect; |
|
2459 } |
|
2460 miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO); |
|
2461 |
|
2462 dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()), |
|
2463 qMin(reg1->extents.top(), reg2->extents.top()), |
|
2464 qMax(reg1->extents.right(), reg2->extents.right()), |
|
2465 qMax(reg1->extents.bottom(), reg2->extents.bottom())); |
|
2466 } |
|
2467 |
|
2468 /*====================================================================== |
|
2469 * Region Subtraction |
|
2470 *====================================================================*/ |
|
2471 |
|
2472 /*- |
|
2473 *----------------------------------------------------------------------- |
|
2474 * miSubtractNonO -- |
|
2475 * Deal with non-overlapping band for subtraction. Any parts from |
|
2476 * region 2 we discard. Anything from region 1 we add to the region. |
|
2477 * |
|
2478 * Results: |
|
2479 * None. |
|
2480 * |
|
2481 * Side Effects: |
|
2482 * dest may be affected. |
|
2483 * |
|
2484 *----------------------------------------------------------------------- |
|
2485 */ |
|
2486 |
|
2487 static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r, |
|
2488 const QRect *rEnd, register int y1, register int y2) |
|
2489 { |
|
2490 register QRect *pNextRect; |
|
2491 |
|
2492 pNextRect = dest.rects.data() + dest.numRects; |
|
2493 |
|
2494 Q_ASSERT(y1<=y2); |
|
2495 |
|
2496 while (r != rEnd) { |
|
2497 Q_ASSERT(r->left() <= r->right()); |
|
2498 MEMCHECK(dest, pNextRect, dest.rects) |
|
2499 pNextRect->setCoords(r->left(), y1, r->right(), y2); |
|
2500 ++dest.numRects; |
|
2501 ++pNextRect; |
|
2502 ++r; |
|
2503 } |
|
2504 } |
|
2505 |
|
2506 /*- |
|
2507 *----------------------------------------------------------------------- |
|
2508 * miSubtractO -- |
|
2509 * Overlapping band subtraction. x1 is the left-most point not yet |
|
2510 * checked. |
|
2511 * |
|
2512 * Results: |
|
2513 * None. |
|
2514 * |
|
2515 * Side Effects: |
|
2516 * dest may have rectangles added to it. |
|
2517 * |
|
2518 *----------------------------------------------------------------------- |
|
2519 */ |
|
2520 |
|
2521 static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, |
|
2522 register const QRect *r2, const QRect *r2End, register int y1, register int y2) |
|
2523 { |
|
2524 register QRect *pNextRect; |
|
2525 register int x1; |
|
2526 |
|
2527 x1 = r1->left(); |
|
2528 |
|
2529 Q_ASSERT(y1 <= y2); |
|
2530 pNextRect = dest.rects.data() + dest.numRects; |
|
2531 |
|
2532 while (r1 != r1End && r2 != r2End) { |
|
2533 if (r2->right() < x1) { |
|
2534 /* |
|
2535 * Subtrahend missed the boat: go to next subtrahend. |
|
2536 */ |
|
2537 ++r2; |
|
2538 } else if (r2->left() <= x1) { |
|
2539 /* |
|
2540 * Subtrahend precedes minuend: nuke left edge of minuend. |
|
2541 */ |
|
2542 x1 = r2->right() + 1; |
|
2543 if (x1 > r1->right()) { |
|
2544 /* |
|
2545 * Minuend completely covered: advance to next minuend and |
|
2546 * reset left fence to edge of new minuend. |
|
2547 */ |
|
2548 ++r1; |
|
2549 if (r1 != r1End) |
|
2550 x1 = r1->left(); |
|
2551 } else { |
|
2552 // Subtrahend now used up since it doesn't extend beyond minuend |
|
2553 ++r2; |
|
2554 } |
|
2555 } else if (r2->left() <= r1->right()) { |
|
2556 /* |
|
2557 * Left part of subtrahend covers part of minuend: add uncovered |
|
2558 * part of minuend to region and skip to next subtrahend. |
|
2559 */ |
|
2560 Q_ASSERT(x1 < r2->left()); |
|
2561 MEMCHECK(dest, pNextRect, dest.rects) |
|
2562 pNextRect->setCoords(x1, y1, r2->left() - 1, y2); |
|
2563 ++dest.numRects; |
|
2564 ++pNextRect; |
|
2565 |
|
2566 x1 = r2->right() + 1; |
|
2567 if (x1 > r1->right()) { |
|
2568 /* |
|
2569 * Minuend used up: advance to new... |
|
2570 */ |
|
2571 ++r1; |
|
2572 if (r1 != r1End) |
|
2573 x1 = r1->left(); |
|
2574 } else { |
|
2575 // Subtrahend used up |
|
2576 ++r2; |
|
2577 } |
|
2578 } else { |
|
2579 /* |
|
2580 * Minuend used up: add any remaining piece before advancing. |
|
2581 */ |
|
2582 if (r1->right() >= x1) { |
|
2583 MEMCHECK(dest, pNextRect, dest.rects) |
|
2584 pNextRect->setCoords(x1, y1, r1->right(), y2); |
|
2585 ++dest.numRects; |
|
2586 ++pNextRect; |
|
2587 } |
|
2588 ++r1; |
|
2589 if (r1 != r1End) |
|
2590 x1 = r1->left(); |
|
2591 } |
|
2592 } |
|
2593 |
|
2594 /* |
|
2595 * Add remaining minuend rectangles to region. |
|
2596 */ |
|
2597 while (r1 != r1End) { |
|
2598 Q_ASSERT(x1 <= r1->right()); |
|
2599 MEMCHECK(dest, pNextRect, dest.rects) |
|
2600 pNextRect->setCoords(x1, y1, r1->right(), y2); |
|
2601 ++dest.numRects; |
|
2602 ++pNextRect; |
|
2603 |
|
2604 ++r1; |
|
2605 if (r1 != r1End) |
|
2606 x1 = r1->left(); |
|
2607 } |
|
2608 } |
|
2609 |
|
2610 /*- |
|
2611 *----------------------------------------------------------------------- |
|
2612 * miSubtract -- |
|
2613 * Subtract regS from regM and leave the result in regD. |
|
2614 * S stands for subtrahend, M for minuend and D for difference. |
|
2615 * |
|
2616 * Side Effects: |
|
2617 * regD is overwritten. |
|
2618 * |
|
2619 *----------------------------------------------------------------------- |
|
2620 */ |
|
2621 |
|
2622 static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS, |
|
2623 register QRegionPrivate &dest) |
|
2624 { |
|
2625 Q_ASSERT(!isEmptyHelper(regM)); |
|
2626 Q_ASSERT(!isEmptyHelper(regS)); |
|
2627 Q_ASSERT(EXTENTCHECK(®M->extents, ®S->extents)); |
|
2628 Q_ASSERT(!regS->contains(*regM)); |
|
2629 Q_ASSERT(!EqualRegion(regM, regS)); |
|
2630 |
|
2631 miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0); |
|
2632 |
|
2633 /* |
|
2634 * Can't alter dest's extents before we call miRegionOp because |
|
2635 * it might be one of the source regions and miRegionOp depends |
|
2636 * on the extents of those regions being the unaltered. Besides, this |
|
2637 * way there's no checking against rectangles that will be nuked |
|
2638 * due to coalescing, so we have to examine fewer rectangles. |
|
2639 */ |
|
2640 miSetExtents(dest); |
|
2641 } |
|
2642 |
|
2643 static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest) |
|
2644 { |
|
2645 Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb)); |
|
2646 Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents)); |
|
2647 Q_ASSERT(!EqualRegion(sra, srb)); |
|
2648 |
|
2649 QRegionPrivate tra, trb; |
|
2650 |
|
2651 if (!srb->contains(*sra)) |
|
2652 SubtractRegion(sra, srb, tra); |
|
2653 if (!sra->contains(*srb)) |
|
2654 SubtractRegion(srb, sra, trb); |
|
2655 |
|
2656 Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb)); |
|
2657 Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra)); |
|
2658 |
|
2659 if (isEmptyHelper(&tra)) { |
|
2660 dest = trb; |
|
2661 } else if (isEmptyHelper(&trb)) { |
|
2662 dest = tra; |
|
2663 } else if (tra.canAppend(&trb)) { |
|
2664 dest = tra; |
|
2665 dest.append(&trb); |
|
2666 } else if (trb.canAppend(&tra)) { |
|
2667 dest = trb; |
|
2668 dest.append(&tra); |
|
2669 } else { |
|
2670 UnionRegion(&tra, &trb, dest); |
|
2671 } |
|
2672 } |
|
2673 |
|
2674 /* |
|
2675 * Check to see if two regions are equal |
|
2676 */ |
|
2677 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2) |
|
2678 { |
|
2679 if (r1->numRects != r2->numRects) { |
|
2680 return false; |
|
2681 } else if (r1->numRects == 0) { |
|
2682 return true; |
|
2683 } else if (r1->extents != r2->extents) { |
|
2684 return false; |
|
2685 } else if (r1->numRects == 1 && r2->numRects == 1) { |
|
2686 return true; // equality tested in previous if-statement |
|
2687 } else { |
|
2688 const QRect *rr1 = (r1->numRects == 1) ? &r1->extents : r1->rects.constData(); |
|
2689 const QRect *rr2 = (r2->numRects == 1) ? &r2->extents : r2->rects.constData(); |
|
2690 for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) { |
|
2691 if (*rr1 != *rr2) |
|
2692 return false; |
|
2693 } |
|
2694 } |
|
2695 |
|
2696 return true; |
|
2697 } |
|
2698 |
|
2699 static bool PointInRegion(QRegionPrivate *pRegion, int x, int y) |
|
2700 { |
|
2701 int i; |
|
2702 |
|
2703 if (isEmptyHelper(pRegion)) |
|
2704 return false; |
|
2705 if (!pRegion->extents.contains(x, y)) |
|
2706 return false; |
|
2707 if (pRegion->numRects == 1) |
|
2708 return pRegion->extents.contains(x, y); |
|
2709 if (pRegion->innerRect.contains(x, y)) |
|
2710 return true; |
|
2711 for (i = 0; i < pRegion->numRects; ++i) { |
|
2712 if (pRegion->rects[i].contains(x, y)) |
|
2713 return true; |
|
2714 } |
|
2715 return false; |
|
2716 } |
|
2717 |
|
2718 static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight) |
|
2719 { |
|
2720 register const QRect *pbox; |
|
2721 register const QRect *pboxEnd; |
|
2722 QRect rect(rx, ry, rwidth, rheight); |
|
2723 register QRect *prect = ▭ |
|
2724 int partIn, partOut; |
|
2725 |
|
2726 if (!region || region->numRects == 0 || !EXTENTCHECK(®ion->extents, prect)) |
|
2727 return RectangleOut; |
|
2728 |
|
2729 partOut = false; |
|
2730 partIn = false; |
|
2731 |
|
2732 /* can stop when both partOut and partIn are true, or we reach prect->y2 */ |
|
2733 pbox = (region->numRects == 1) ? ®ion->extents : region->rects.constData(); |
|
2734 pboxEnd = pbox + region->numRects; |
|
2735 for (; pbox < pboxEnd; ++pbox) { |
|
2736 if (pbox->bottom() < ry) |
|
2737 continue; |
|
2738 |
|
2739 if (pbox->top() > ry) { |
|
2740 partOut = true; |
|
2741 if (partIn || pbox->top() > prect->bottom()) |
|
2742 break; |
|
2743 ry = pbox->top(); |
|
2744 } |
|
2745 |
|
2746 if (pbox->right() < rx) |
|
2747 continue; /* not far enough over yet */ |
|
2748 |
|
2749 if (pbox->left() > rx) { |
|
2750 partOut = true; /* missed part of rectangle to left */ |
|
2751 if (partIn) |
|
2752 break; |
|
2753 } |
|
2754 |
|
2755 if (pbox->left() <= prect->right()) { |
|
2756 partIn = true; /* definitely overlap */ |
|
2757 if (partOut) |
|
2758 break; |
|
2759 } |
|
2760 |
|
2761 if (pbox->right() >= prect->right()) { |
|
2762 ry = pbox->bottom() + 1; /* finished with this band */ |
|
2763 if (ry > prect->bottom()) |
|
2764 break; |
|
2765 rx = prect->left(); /* reset x out to left again */ |
|
2766 } else { |
|
2767 /* |
|
2768 * Because boxes in a band are maximal width, if the first box |
|
2769 * to overlap the rectangle doesn't completely cover it in that |
|
2770 * band, the rectangle must be partially out, since some of it |
|
2771 * will be uncovered in that band. partIn will have been set true |
|
2772 * by now... |
|
2773 */ |
|
2774 break; |
|
2775 } |
|
2776 } |
|
2777 return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut; |
|
2778 } |
|
2779 // END OF Region.c extract |
|
2780 // START OF poly.h extract |
|
2781 /* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */ |
|
2782 /************************************************************************ |
|
2783 |
|
2784 Copyright (c) 1987 X Consortium |
|
2785 |
|
2786 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
2787 of this software and associated documentation files (the "Software"), to deal |
|
2788 in the Software without restriction, including without limitation the rights |
|
2789 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
2790 copies of the Software, and to permit persons to whom the Software is |
|
2791 furnished to do so, subject to the following conditions: |
|
2792 |
|
2793 The above copyright notice and this permission notice shall be included in |
|
2794 all copies or substantial portions of the Software. |
|
2795 |
|
2796 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
2797 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
2798 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
2799 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
2800 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
2801 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
2802 |
|
2803 Except as contained in this notice, the name of the X Consortium shall not be |
|
2804 used in advertising or otherwise to promote the sale, use or other dealings |
|
2805 in this Software without prior written authorization from the X Consortium. |
|
2806 |
|
2807 |
|
2808 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. |
|
2809 |
|
2810 All Rights Reserved |
|
2811 |
|
2812 Permission to use, copy, modify, and distribute this software and its |
|
2813 documentation for any purpose and without fee is hereby granted, |
|
2814 provided that the above copyright notice appear in all copies and that |
|
2815 both that copyright notice and this permission notice appear in |
|
2816 supporting documentation, and that the name of Digital not be |
|
2817 used in advertising or publicity pertaining to distribution of the |
|
2818 software without specific, written prior permission. |
|
2819 |
|
2820 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
2821 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
2822 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
2823 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
2824 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
2825 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
2826 SOFTWARE. |
|
2827 |
|
2828 ************************************************************************/ |
|
2829 |
|
2830 /* |
|
2831 * This file contains a few macros to help track |
|
2832 * the edge of a filled object. The object is assumed |
|
2833 * to be filled in scanline order, and thus the |
|
2834 * algorithm used is an extension of Bresenham's line |
|
2835 * drawing algorithm which assumes that y is always the |
|
2836 * major axis. |
|
2837 * Since these pieces of code are the same for any filled shape, |
|
2838 * it is more convenient to gather the library in one |
|
2839 * place, but since these pieces of code are also in |
|
2840 * the inner loops of output primitives, procedure call |
|
2841 * overhead is out of the question. |
|
2842 * See the author for a derivation if needed. |
|
2843 */ |
|
2844 |
|
2845 |
|
2846 /* |
|
2847 * In scan converting polygons, we want to choose those pixels |
|
2848 * which are inside the polygon. Thus, we add .5 to the starting |
|
2849 * x coordinate for both left and right edges. Now we choose the |
|
2850 * first pixel which is inside the pgon for the left edge and the |
|
2851 * first pixel which is outside the pgon for the right edge. |
|
2852 * Draw the left pixel, but not the right. |
|
2853 * |
|
2854 * How to add .5 to the starting x coordinate: |
|
2855 * If the edge is moving to the right, then subtract dy from the |
|
2856 * error term from the general form of the algorithm. |
|
2857 * If the edge is moving to the left, then add dy to the error term. |
|
2858 * |
|
2859 * The reason for the difference between edges moving to the left |
|
2860 * and edges moving to the right is simple: If an edge is moving |
|
2861 * to the right, then we want the algorithm to flip immediately. |
|
2862 * If it is moving to the left, then we don't want it to flip until |
|
2863 * we traverse an entire pixel. |
|
2864 */ |
|
2865 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \ |
|
2866 int dx; /* local storage */ \ |
|
2867 \ |
|
2868 /* \ |
|
2869 * if the edge is horizontal, then it is ignored \ |
|
2870 * and assumed not to be processed. Otherwise, do this stuff. \ |
|
2871 */ \ |
|
2872 if ((dy) != 0) { \ |
|
2873 xStart = (x1); \ |
|
2874 dx = (x2) - xStart; \ |
|
2875 if (dx < 0) { \ |
|
2876 m = dx / (dy); \ |
|
2877 m1 = m - 1; \ |
|
2878 incr1 = -2 * dx + 2 * (dy) * m1; \ |
|
2879 incr2 = -2 * dx + 2 * (dy) * m; \ |
|
2880 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \ |
|
2881 } else { \ |
|
2882 m = dx / (dy); \ |
|
2883 m1 = m + 1; \ |
|
2884 incr1 = 2 * dx - 2 * (dy) * m1; \ |
|
2885 incr2 = 2 * dx - 2 * (dy) * m; \ |
|
2886 d = -2 * m * (dy) + 2 * dx; \ |
|
2887 } \ |
|
2888 } \ |
|
2889 } |
|
2890 |
|
2891 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \ |
|
2892 if (m1 > 0) { \ |
|
2893 if (d > 0) { \ |
|
2894 minval += m1; \ |
|
2895 d += incr1; \ |
|
2896 } \ |
|
2897 else { \ |
|
2898 minval += m; \ |
|
2899 d += incr2; \ |
|
2900 } \ |
|
2901 } else {\ |
|
2902 if (d >= 0) { \ |
|
2903 minval += m1; \ |
|
2904 d += incr1; \ |
|
2905 } \ |
|
2906 else { \ |
|
2907 minval += m; \ |
|
2908 d += incr2; \ |
|
2909 } \ |
|
2910 } \ |
|
2911 } |
|
2912 |
|
2913 |
|
2914 /* |
|
2915 * This structure contains all of the information needed |
|
2916 * to run the bresenham algorithm. |
|
2917 * The variables may be hardcoded into the declarations |
|
2918 * instead of using this structure to make use of |
|
2919 * register declarations. |
|
2920 */ |
|
2921 typedef struct { |
|
2922 int minor_axis; /* minor axis */ |
|
2923 int d; /* decision variable */ |
|
2924 int m, m1; /* slope and slope+1 */ |
|
2925 int incr1, incr2; /* error increments */ |
|
2926 } BRESINFO; |
|
2927 |
|
2928 |
|
2929 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \ |
|
2930 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \ |
|
2931 bres.m, bres.m1, bres.incr1, bres.incr2) |
|
2932 |
|
2933 #define BRESINCRPGONSTRUCT(bres) \ |
|
2934 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2) |
|
2935 |
|
2936 |
|
2937 |
|
2938 /* |
|
2939 * These are the data structures needed to scan |
|
2940 * convert regions. Two different scan conversion |
|
2941 * methods are available -- the even-odd method, and |
|
2942 * the winding number method. |
|
2943 * The even-odd rule states that a point is inside |
|
2944 * the polygon if a ray drawn from that point in any |
|
2945 * direction will pass through an odd number of |
|
2946 * path segments. |
|
2947 * By the winding number rule, a point is decided |
|
2948 * to be inside the polygon if a ray drawn from that |
|
2949 * point in any direction passes through a different |
|
2950 * number of clockwise and counter-clockwise path |
|
2951 * segments. |
|
2952 * |
|
2953 * These data structures are adapted somewhat from |
|
2954 * the algorithm in (Foley/Van Dam) for scan converting |
|
2955 * polygons. |
|
2956 * The basic algorithm is to start at the top (smallest y) |
|
2957 * of the polygon, stepping down to the bottom of |
|
2958 * the polygon by incrementing the y coordinate. We |
|
2959 * keep a list of edges which the current scanline crosses, |
|
2960 * sorted by x. This list is called the Active Edge Table (AET) |
|
2961 * As we change the y-coordinate, we update each entry in |
|
2962 * in the active edge table to reflect the edges new xcoord. |
|
2963 * This list must be sorted at each scanline in case |
|
2964 * two edges intersect. |
|
2965 * We also keep a data structure known as the Edge Table (ET), |
|
2966 * which keeps track of all the edges which the current |
|
2967 * scanline has not yet reached. The ET is basically a |
|
2968 * list of ScanLineList structures containing a list of |
|
2969 * edges which are entered at a given scanline. There is one |
|
2970 * ScanLineList per scanline at which an edge is entered. |
|
2971 * When we enter a new edge, we move it from the ET to the AET. |
|
2972 * |
|
2973 * From the AET, we can implement the even-odd rule as in |
|
2974 * (Foley/Van Dam). |
|
2975 * The winding number rule is a little trickier. We also |
|
2976 * keep the EdgeTableEntries in the AET linked by the |
|
2977 * nextWETE (winding EdgeTableEntry) link. This allows |
|
2978 * the edges to be linked just as before for updating |
|
2979 * purposes, but only uses the edges linked by the nextWETE |
|
2980 * link as edges representing spans of the polygon to |
|
2981 * drawn (as with the even-odd rule). |
|
2982 */ |
|
2983 |
|
2984 /* |
|
2985 * for the winding number rule |
|
2986 */ |
|
2987 #define CLOCKWISE 1 |
|
2988 #define COUNTERCLOCKWISE -1 |
|
2989 |
|
2990 typedef struct _EdgeTableEntry { |
|
2991 int ymax; /* ycoord at which we exit this edge. */ |
|
2992 BRESINFO bres; /* Bresenham info to run the edge */ |
|
2993 struct _EdgeTableEntry *next; /* next in the list */ |
|
2994 struct _EdgeTableEntry *back; /* for insertion sort */ |
|
2995 struct _EdgeTableEntry *nextWETE; /* for winding num rule */ |
|
2996 int ClockWise; /* flag for winding number rule */ |
|
2997 } EdgeTableEntry; |
|
2998 |
|
2999 |
|
3000 typedef struct _ScanLineList{ |
|
3001 int scanline; /* the scanline represented */ |
|
3002 EdgeTableEntry *edgelist; /* header node */ |
|
3003 struct _ScanLineList *next; /* next in the list */ |
|
3004 } ScanLineList; |
|
3005 |
|
3006 |
|
3007 typedef struct { |
|
3008 int ymax; /* ymax for the polygon */ |
|
3009 int ymin; /* ymin for the polygon */ |
|
3010 ScanLineList scanlines; /* header node */ |
|
3011 } EdgeTable; |
|
3012 |
|
3013 |
|
3014 /* |
|
3015 * Here is a struct to help with storage allocation |
|
3016 * so we can allocate a big chunk at a time, and then take |
|
3017 * pieces from this heap when we need to. |
|
3018 */ |
|
3019 #define SLLSPERBLOCK 25 |
|
3020 |
|
3021 typedef struct _ScanLineListBlock { |
|
3022 ScanLineList SLLs[SLLSPERBLOCK]; |
|
3023 struct _ScanLineListBlock *next; |
|
3024 } ScanLineListBlock; |
|
3025 |
|
3026 |
|
3027 |
|
3028 /* |
|
3029 * |
|
3030 * a few macros for the inner loops of the fill code where |
|
3031 * performance considerations don't allow a procedure call. |
|
3032 * |
|
3033 * Evaluate the given edge at the given scanline. |
|
3034 * If the edge has expired, then we leave it and fix up |
|
3035 * the active edge table; otherwise, we increment the |
|
3036 * x value to be ready for the next scanline. |
|
3037 * The winding number rule is in effect, so we must notify |
|
3038 * the caller when the edge has been removed so he |
|
3039 * can reorder the Winding Active Edge Table. |
|
3040 */ |
|
3041 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \ |
|
3042 if (pAET->ymax == y) { /* leaving this edge */ \ |
|
3043 pPrevAET->next = pAET->next; \ |
|
3044 pAET = pPrevAET->next; \ |
|
3045 fixWAET = 1; \ |
|
3046 if (pAET) \ |
|
3047 pAET->back = pPrevAET; \ |
|
3048 } \ |
|
3049 else { \ |
|
3050 BRESINCRPGONSTRUCT(pAET->bres) \ |
|
3051 pPrevAET = pAET; \ |
|
3052 pAET = pAET->next; \ |
|
3053 } \ |
|
3054 } |
|
3055 |
|
3056 |
|
3057 /* |
|
3058 * Evaluate the given edge at the given scanline. |
|
3059 * If the edge has expired, then we leave it and fix up |
|
3060 * the active edge table; otherwise, we increment the |
|
3061 * x value to be ready for the next scanline. |
|
3062 * The even-odd rule is in effect. |
|
3063 */ |
|
3064 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \ |
|
3065 if (pAET->ymax == y) { /* leaving this edge */ \ |
|
3066 pPrevAET->next = pAET->next; \ |
|
3067 pAET = pPrevAET->next; \ |
|
3068 if (pAET) \ |
|
3069 pAET->back = pPrevAET; \ |
|
3070 } \ |
|
3071 else { \ |
|
3072 BRESINCRPGONSTRUCT(pAET->bres) \ |
|
3073 pPrevAET = pAET; \ |
|
3074 pAET = pAET->next; \ |
|
3075 } \ |
|
3076 } |
|
3077 // END OF poly.h extract |
|
3078 // START OF PolyReg.c extract |
|
3079 /* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */ |
|
3080 /************************************************************************ |
|
3081 |
|
3082 Copyright (c) 1987 X Consortium |
|
3083 |
|
3084 Permission is hereby granted, free of charge, to any person obtaining a copy |
|
3085 of this software and associated documentation files (the "Software"), to deal |
|
3086 in the Software without restriction, including without limitation the rights |
|
3087 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
3088 copies of the Software, and to permit persons to whom the Software is |
|
3089 furnished to do so, subject to the following conditions: |
|
3090 |
|
3091 The above copyright notice and this permission notice shall be included in |
|
3092 all copies or substantial portions of the Software. |
|
3093 |
|
3094 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
3095 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
3096 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
3097 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
3098 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
3099 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
3100 |
|
3101 Except as contained in this notice, the name of the X Consortium shall not be |
|
3102 used in advertising or otherwise to promote the sale, use or other dealings |
|
3103 in this Software without prior written authorization from the X Consortium. |
|
3104 |
|
3105 |
|
3106 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. |
|
3107 |
|
3108 All Rights Reserved |
|
3109 |
|
3110 Permission to use, copy, modify, and distribute this software and its |
|
3111 documentation for any purpose and without fee is hereby granted, |
|
3112 provided that the above copyright notice appear in all copies and that |
|
3113 both that copyright notice and this permission notice appear in |
|
3114 supporting documentation, and that the name of Digital not be |
|
3115 used in advertising or publicity pertaining to distribution of the |
|
3116 software without specific, written prior permission. |
|
3117 |
|
3118 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
3119 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
3120 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
3121 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
3122 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
3123 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
3124 SOFTWARE. |
|
3125 |
|
3126 ************************************************************************/ |
|
3127 /* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */ |
|
3128 |
|
3129 #define LARGE_COORDINATE 1000000 |
|
3130 #define SMALL_COORDINATE -LARGE_COORDINATE |
|
3131 |
|
3132 /* |
|
3133 * InsertEdgeInET |
|
3134 * |
|
3135 * Insert the given edge into the edge table. |
|
3136 * First we must find the correct bucket in the |
|
3137 * Edge table, then find the right slot in the |
|
3138 * bucket. Finally, we can insert it. |
|
3139 * |
|
3140 */ |
|
3141 static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, |
|
3142 ScanLineListBlock **SLLBlock, int *iSLLBlock) |
|
3143 { |
|
3144 register EdgeTableEntry *start, *prev; |
|
3145 register ScanLineList *pSLL, *pPrevSLL; |
|
3146 ScanLineListBlock *tmpSLLBlock; |
|
3147 |
|
3148 /* |
|
3149 * find the right bucket to put the edge into |
|
3150 */ |
|
3151 pPrevSLL = &ET->scanlines; |
|
3152 pSLL = pPrevSLL->next; |
|
3153 while (pSLL && (pSLL->scanline < scanline)) { |
|
3154 pPrevSLL = pSLL; |
|
3155 pSLL = pSLL->next; |
|
3156 } |
|
3157 |
|
3158 /* |
|
3159 * reassign pSLL (pointer to ScanLineList) if necessary |
|
3160 */ |
|
3161 if ((!pSLL) || (pSLL->scanline > scanline)) { |
|
3162 if (*iSLLBlock > SLLSPERBLOCK-1) |
|
3163 { |
|
3164 tmpSLLBlock = |
|
3165 (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock)); |
|
3166 Q_CHECK_PTR(tmpSLLBlock); |
|
3167 (*SLLBlock)->next = tmpSLLBlock; |
|
3168 tmpSLLBlock->next = (ScanLineListBlock *)NULL; |
|
3169 *SLLBlock = tmpSLLBlock; |
|
3170 *iSLLBlock = 0; |
|
3171 } |
|
3172 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]); |
|
3173 |
|
3174 pSLL->next = pPrevSLL->next; |
|
3175 pSLL->edgelist = (EdgeTableEntry *)NULL; |
|
3176 pPrevSLL->next = pSLL; |
|
3177 } |
|
3178 pSLL->scanline = scanline; |
|
3179 |
|
3180 /* |
|
3181 * now insert the edge in the right bucket |
|
3182 */ |
|
3183 prev = 0; |
|
3184 start = pSLL->edgelist; |
|
3185 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) { |
|
3186 prev = start; |
|
3187 start = start->next; |
|
3188 } |
|
3189 ETE->next = start; |
|
3190 |
|
3191 if (prev) |
|
3192 prev->next = ETE; |
|
3193 else |
|
3194 pSLL->edgelist = ETE; |
|
3195 } |
|
3196 |
|
3197 /* |
|
3198 * CreateEdgeTable |
|
3199 * |
|
3200 * This routine creates the edge table for |
|
3201 * scan converting polygons. |
|
3202 * The Edge Table (ET) looks like: |
|
3203 * |
|
3204 * EdgeTable |
|
3205 * -------- |
|
3206 * | ymax | ScanLineLists |
|
3207 * |scanline|-->------------>-------------->... |
|
3208 * -------- |scanline| |scanline| |
|
3209 * |edgelist| |edgelist| |
|
3210 * --------- --------- |
|
3211 * | | |
|
3212 * | | |
|
3213 * V V |
|
3214 * list of ETEs list of ETEs |
|
3215 * |
|
3216 * where ETE is an EdgeTableEntry data structure, |
|
3217 * and there is one ScanLineList per scanline at |
|
3218 * which an edge is initially entered. |
|
3219 * |
|
3220 */ |
|
3221 |
|
3222 static void CreateETandAET(register int count, register const QPoint *pts, |
|
3223 EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs, |
|
3224 ScanLineListBlock *pSLLBlock) |
|
3225 { |
|
3226 register const QPoint *top, |
|
3227 *bottom, |
|
3228 *PrevPt, |
|
3229 *CurrPt; |
|
3230 int iSLLBlock = 0; |
|
3231 int dy; |
|
3232 |
|
3233 if (count < 2) |
|
3234 return; |
|
3235 |
|
3236 /* |
|
3237 * initialize the Active Edge Table |
|
3238 */ |
|
3239 AET->next = 0; |
|
3240 AET->back = 0; |
|
3241 AET->nextWETE = 0; |
|
3242 AET->bres.minor_axis = SMALL_COORDINATE; |
|
3243 |
|
3244 /* |
|
3245 * initialize the Edge Table. |
|
3246 */ |
|
3247 ET->scanlines.next = 0; |
|
3248 ET->ymax = SMALL_COORDINATE; |
|
3249 ET->ymin = LARGE_COORDINATE; |
|
3250 pSLLBlock->next = 0; |
|
3251 |
|
3252 PrevPt = &pts[count - 1]; |
|
3253 |
|
3254 /* |
|
3255 * for each vertex in the array of points. |
|
3256 * In this loop we are dealing with two vertices at |
|
3257 * a time -- these make up one edge of the polygon. |
|
3258 */ |
|
3259 while (count--) { |
|
3260 CurrPt = pts++; |
|
3261 |
|
3262 /* |
|
3263 * find out which point is above and which is below. |
|
3264 */ |
|
3265 if (PrevPt->y() > CurrPt->y()) { |
|
3266 bottom = PrevPt; |
|
3267 top = CurrPt; |
|
3268 pETEs->ClockWise = 0; |
|
3269 } else { |
|
3270 bottom = CurrPt; |
|
3271 top = PrevPt; |
|
3272 pETEs->ClockWise = 1; |
|
3273 } |
|
3274 |
|
3275 /* |
|
3276 * don't add horizontal edges to the Edge table. |
|
3277 */ |
|
3278 if (bottom->y() != top->y()) { |
|
3279 pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */ |
|
3280 |
|
3281 /* |
|
3282 * initialize integer edge algorithm |
|
3283 */ |
|
3284 dy = bottom->y() - top->y(); |
|
3285 BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres) |
|
3286 |
|
3287 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock); |
|
3288 |
|
3289 if (PrevPt->y() > ET->ymax) |
|
3290 ET->ymax = PrevPt->y(); |
|
3291 if (PrevPt->y() < ET->ymin) |
|
3292 ET->ymin = PrevPt->y(); |
|
3293 ++pETEs; |
|
3294 } |
|
3295 |
|
3296 PrevPt = CurrPt; |
|
3297 } |
|
3298 } |
|
3299 |
|
3300 /* |
|
3301 * loadAET |
|
3302 * |
|
3303 * This routine moves EdgeTableEntries from the |
|
3304 * EdgeTable into the Active Edge Table, |
|
3305 * leaving them sorted by smaller x coordinate. |
|
3306 * |
|
3307 */ |
|
3308 |
|
3309 static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs) |
|
3310 { |
|
3311 register EdgeTableEntry *pPrevAET; |
|
3312 register EdgeTableEntry *tmp; |
|
3313 |
|
3314 pPrevAET = AET; |
|
3315 AET = AET->next; |
|
3316 while (ETEs) { |
|
3317 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) { |
|
3318 pPrevAET = AET; |
|
3319 AET = AET->next; |
|
3320 } |
|
3321 tmp = ETEs->next; |
|
3322 ETEs->next = AET; |
|
3323 if (AET) |
|
3324 AET->back = ETEs; |
|
3325 ETEs->back = pPrevAET; |
|
3326 pPrevAET->next = ETEs; |
|
3327 pPrevAET = ETEs; |
|
3328 |
|
3329 ETEs = tmp; |
|
3330 } |
|
3331 } |
|
3332 |
|
3333 /* |
|
3334 * computeWAET |
|
3335 * |
|
3336 * This routine links the AET by the |
|
3337 * nextWETE (winding EdgeTableEntry) link for |
|
3338 * use by the winding number rule. The final |
|
3339 * Active Edge Table (AET) might look something |
|
3340 * like: |
|
3341 * |
|
3342 * AET |
|
3343 * ---------- --------- --------- |
|
3344 * |ymax | |ymax | |ymax | |
|
3345 * | ... | |... | |... | |
|
3346 * |next |->|next |->|next |->... |
|
3347 * |nextWETE| |nextWETE| |nextWETE| |
|
3348 * --------- --------- ^-------- |
|
3349 * | | | |
|
3350 * V-------------------> V---> ... |
|
3351 * |
|
3352 */ |
|
3353 static void computeWAET(register EdgeTableEntry *AET) |
|
3354 { |
|
3355 register EdgeTableEntry *pWETE; |
|
3356 register int inside = 1; |
|
3357 register int isInside = 0; |
|
3358 |
|
3359 AET->nextWETE = 0; |
|
3360 pWETE = AET; |
|
3361 AET = AET->next; |
|
3362 while (AET) { |
|
3363 if (AET->ClockWise) |
|
3364 ++isInside; |
|
3365 else |
|
3366 --isInside; |
|
3367 |
|
3368 if ((!inside && !isInside) || (inside && isInside)) { |
|
3369 pWETE->nextWETE = AET; |
|
3370 pWETE = AET; |
|
3371 inside = !inside; |
|
3372 } |
|
3373 AET = AET->next; |
|
3374 } |
|
3375 pWETE->nextWETE = 0; |
|
3376 } |
|
3377 |
|
3378 /* |
|
3379 * InsertionSort |
|
3380 * |
|
3381 * Just a simple insertion sort using |
|
3382 * pointers and back pointers to sort the Active |
|
3383 * Edge Table. |
|
3384 * |
|
3385 */ |
|
3386 |
|
3387 static int InsertionSort(register EdgeTableEntry *AET) |
|
3388 { |
|
3389 register EdgeTableEntry *pETEchase; |
|
3390 register EdgeTableEntry *pETEinsert; |
|
3391 register EdgeTableEntry *pETEchaseBackTMP; |
|
3392 register int changed = 0; |
|
3393 |
|
3394 AET = AET->next; |
|
3395 while (AET) { |
|
3396 pETEinsert = AET; |
|
3397 pETEchase = AET; |
|
3398 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis) |
|
3399 pETEchase = pETEchase->back; |
|
3400 |
|
3401 AET = AET->next; |
|
3402 if (pETEchase != pETEinsert) { |
|
3403 pETEchaseBackTMP = pETEchase->back; |
|
3404 pETEinsert->back->next = AET; |
|
3405 if (AET) |
|
3406 AET->back = pETEinsert->back; |
|
3407 pETEinsert->next = pETEchase; |
|
3408 pETEchase->back->next = pETEinsert; |
|
3409 pETEchase->back = pETEinsert; |
|
3410 pETEinsert->back = pETEchaseBackTMP; |
|
3411 changed = 1; |
|
3412 } |
|
3413 } |
|
3414 return changed; |
|
3415 } |
|
3416 |
|
3417 /* |
|
3418 * Clean up our act. |
|
3419 */ |
|
3420 static void FreeStorage(register ScanLineListBlock *pSLLBlock) |
|
3421 { |
|
3422 register ScanLineListBlock *tmpSLLBlock; |
|
3423 |
|
3424 while (pSLLBlock) { |
|
3425 tmpSLLBlock = pSLLBlock->next; |
|
3426 free(pSLLBlock); |
|
3427 pSLLBlock = tmpSLLBlock; |
|
3428 } |
|
3429 } |
|
3430 |
|
3431 struct QRegionSpan { |
|
3432 QRegionSpan() {} |
|
3433 QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {} |
|
3434 |
|
3435 int x1; |
|
3436 int x2; |
|
3437 int width() const { return x2 - x1; } |
|
3438 }; |
|
3439 |
|
3440 Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE); |
|
3441 |
|
3442 static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend) |
|
3443 { |
|
3444 QRect *regRects = reg->rects.data() + *lastRow; |
|
3445 bool canExtend = reg->rects.size() - *lastRow == numSpans |
|
3446 && !(*needsExtend && *extendTo + 1 != y) |
|
3447 && (*needsExtend || regRects[0].y() + regRects[0].height() == y); |
|
3448 |
|
3449 for (int i = 0; i < numSpans && canExtend; ++i) { |
|
3450 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1) |
|
3451 canExtend = false; |
|
3452 } |
|
3453 |
|
3454 if (canExtend) { |
|
3455 *extendTo = y; |
|
3456 *needsExtend = true; |
|
3457 } else { |
|
3458 if (*needsExtend) { |
|
3459 for (int i = 0; i < reg->rects.size() - *lastRow; ++i) |
|
3460 regRects[i].setBottom(*extendTo); |
|
3461 } |
|
3462 |
|
3463 *lastRow = reg->rects.size(); |
|
3464 reg->rects.reserve(*lastRow + numSpans); |
|
3465 for (int i = 0; i < numSpans; ++i) |
|
3466 reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1); |
|
3467 |
|
3468 if (spans[0].x1 < reg->extents.left()) |
|
3469 reg->extents.setLeft(spans[0].x1); |
|
3470 |
|
3471 if (spans[numSpans-1].x2 - 1 > reg->extents.right()) |
|
3472 reg->extents.setRight(spans[numSpans-1].x2 - 1); |
|
3473 |
|
3474 *needsExtend = false; |
|
3475 } |
|
3476 } |
|
3477 |
|
3478 /* |
|
3479 * Create an array of rectangles from a list of points. |
|
3480 * If indeed these things (POINTS, RECTS) are the same, |
|
3481 * then this proc is still needed, because it allocates |
|
3482 * storage for the array, which was allocated on the |
|
3483 * stack by the calling procedure. |
|
3484 * |
|
3485 */ |
|
3486 static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock, |
|
3487 POINTBLOCK *FirstPtBlock, QRegionPrivate *reg) |
|
3488 { |
|
3489 int lastRow = 0; |
|
3490 int extendTo = 0; |
|
3491 bool needsExtend = false; |
|
3492 QVarLengthArray<QRegionSpan> row; |
|
3493 int rowSize = 0; |
|
3494 |
|
3495 reg->extents.setLeft(INT_MAX); |
|
3496 reg->extents.setRight(INT_MIN); |
|
3497 reg->innerArea = -1; |
|
3498 |
|
3499 POINTBLOCK *CurPtBlock = FirstPtBlock; |
|
3500 for (; numFullPtBlocks >= 0; --numFullPtBlocks) { |
|
3501 /* the loop uses 2 points per iteration */ |
|
3502 int i = NUMPTSTOBUFFER >> 1; |
|
3503 if (!numFullPtBlocks) |
|
3504 i = iCurPtBlock >> 1; |
|
3505 if(i) { |
|
3506 row.resize(qMax(row.size(), rowSize + i)); |
|
3507 for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) { |
|
3508 const int width = pts[1].x() - pts[0].x(); |
|
3509 if (width) { |
|
3510 if (rowSize && row[rowSize-1].x2 == pts[0].x()) |
|
3511 row[rowSize-1].x2 = pts[1].x(); |
|
3512 else |
|
3513 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x()); |
|
3514 } |
|
3515 |
|
3516 if (rowSize) { |
|
3517 QPoint *next = i ? &pts[2] : (numFullPtBlocks ? CurPtBlock->next->pts : 0); |
|
3518 |
|
3519 if (!next || next->y() != pts[0].y()) { |
|
3520 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend); |
|
3521 rowSize = 0; |
|
3522 } |
|
3523 } |
|
3524 } |
|
3525 } |
|
3526 CurPtBlock = CurPtBlock->next; |
|
3527 } |
|
3528 |
|
3529 if (needsExtend) { |
|
3530 for (int i = lastRow; i < reg->rects.size(); ++i) |
|
3531 reg->rects[i].setBottom(extendTo); |
|
3532 } |
|
3533 |
|
3534 reg->numRects = reg->rects.size(); |
|
3535 |
|
3536 if (reg->numRects) { |
|
3537 reg->extents.setTop(reg->rects[0].top()); |
|
3538 reg->extents.setBottom(reg->rects[lastRow].bottom()); |
|
3539 |
|
3540 for (int i = 0; i < reg->rects.size(); ++i) |
|
3541 reg->updateInnerRect(reg->rects[i]); |
|
3542 } else { |
|
3543 reg->extents.setCoords(0, 0, 0, 0); |
|
3544 } |
|
3545 } |
|
3546 |
|
3547 /* |
|
3548 * polytoregion |
|
3549 * |
|
3550 * Scan converts a polygon by returning a run-length |
|
3551 * encoding of the resultant bitmap -- the run-length |
|
3552 * encoding is in the form of an array of rectangles. |
|
3553 * |
|
3554 * Can return 0 in case of errors. |
|
3555 */ |
|
3556 static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule) |
|
3557 //Point *Pts; /* the pts */ |
|
3558 //int Count; /* number of pts */ |
|
3559 //int rule; /* winding rule */ |
|
3560 { |
|
3561 QRegionPrivate *region; |
|
3562 register EdgeTableEntry *pAET; /* Active Edge Table */ |
|
3563 register int y; /* current scanline */ |
|
3564 register int iPts = 0; /* number of pts in buffer */ |
|
3565 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/ |
|
3566 register ScanLineList *pSLL; /* current scanLineList */ |
|
3567 register QPoint *pts; /* output buffer */ |
|
3568 EdgeTableEntry *pPrevAET; /* ptr to previous AET */ |
|
3569 EdgeTable ET; /* header node for ET */ |
|
3570 EdgeTableEntry AET; /* header node for AET */ |
|
3571 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */ |
|
3572 ScanLineListBlock SLLBlock; /* header for scanlinelist */ |
|
3573 int fixWAET = false; |
|
3574 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */ |
|
3575 FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data); |
|
3576 POINTBLOCK *tmpPtBlock; |
|
3577 int numFullPtBlocks = 0; |
|
3578 |
|
3579 if (!(region = new QRegionPrivate)) |
|
3580 return 0; |
|
3581 |
|
3582 /* special case a rectangle */ |
|
3583 if (((Count == 4) || |
|
3584 ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y()))) |
|
3585 && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y()) |
|
3586 && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x()) |
|
3587 && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x()) |
|
3588 && (Pts[3].y() == Pts[0].y())))) { |
|
3589 int x = qMin(Pts[0].x(), Pts[2].x()); |
|
3590 region->extents.setLeft(x); |
|
3591 int y = qMin(Pts[0].y(), Pts[2].y()); |
|
3592 region->extents.setTop(y); |
|
3593 region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x); |
|
3594 region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y); |
|
3595 if ((region->extents.left() <= region->extents.right()) && |
|
3596 (region->extents.top() <= region->extents.bottom())) { |
|
3597 region->numRects = 1; |
|
3598 region->innerRect = region->extents; |
|
3599 region->innerArea = region->innerRect.width() * region->innerRect.height(); |
|
3600 } |
|
3601 return region; |
|
3602 } |
|
3603 |
|
3604 if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count)))) |
|
3605 return 0; |
|
3606 |
|
3607 region->vectorize(); |
|
3608 |
|
3609 pts = FirstPtBlock.pts; |
|
3610 CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock); |
|
3611 |
|
3612 pSLL = ET.scanlines.next; |
|
3613 curPtBlock = &FirstPtBlock; |
|
3614 |
|
3615 // sanity check that the region won't become too big... |
|
3616 if (ET.ymax - ET.ymin > 100000) { |
|
3617 // clean up region ptr |
|
3618 #ifndef QT_NO_DEBUG |
|
3619 qWarning("QRegion: creating region from big polygon failed...!"); |
|
3620 #endif |
|
3621 delete region; |
|
3622 return 0; |
|
3623 } |
|
3624 |
|
3625 |
|
3626 QT_TRY { |
|
3627 if (rule == EvenOddRule) { |
|
3628 /* |
|
3629 * for each scanline |
|
3630 */ |
|
3631 for (y = ET.ymin; y < ET.ymax; ++y) { |
|
3632 |
|
3633 /* |
|
3634 * Add a new edge to the active edge table when we |
|
3635 * get to the next edge. |
|
3636 */ |
|
3637 if (pSLL && y == pSLL->scanline) { |
|
3638 loadAET(&AET, pSLL->edgelist); |
|
3639 pSLL = pSLL->next; |
|
3640 } |
|
3641 pPrevAET = &AET; |
|
3642 pAET = AET.next; |
|
3643 |
|
3644 /* |
|
3645 * for each active edge |
|
3646 */ |
|
3647 while (pAET) { |
|
3648 pts->setX(pAET->bres.minor_axis); |
|
3649 pts->setY(y); |
|
3650 ++pts; |
|
3651 ++iPts; |
|
3652 |
|
3653 /* |
|
3654 * send out the buffer |
|
3655 */ |
|
3656 if (iPts == NUMPTSTOBUFFER) { |
|
3657 tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK)); |
|
3658 Q_CHECK_PTR(tmpPtBlock); |
|
3659 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data); |
|
3660 curPtBlock->next = tmpPtBlock; |
|
3661 curPtBlock = tmpPtBlock; |
|
3662 pts = curPtBlock->pts; |
|
3663 ++numFullPtBlocks; |
|
3664 iPts = 0; |
|
3665 } |
|
3666 EVALUATEEDGEEVENODD(pAET, pPrevAET, y) |
|
3667 } |
|
3668 InsertionSort(&AET); |
|
3669 } |
|
3670 } else { |
|
3671 /* |
|
3672 * for each scanline |
|
3673 */ |
|
3674 for (y = ET.ymin; y < ET.ymax; ++y) { |
|
3675 /* |
|
3676 * Add a new edge to the active edge table when we |
|
3677 * get to the next edge. |
|
3678 */ |
|
3679 if (pSLL && y == pSLL->scanline) { |
|
3680 loadAET(&AET, pSLL->edgelist); |
|
3681 computeWAET(&AET); |
|
3682 pSLL = pSLL->next; |
|
3683 } |
|
3684 pPrevAET = &AET; |
|
3685 pAET = AET.next; |
|
3686 pWETE = pAET; |
|
3687 |
|
3688 /* |
|
3689 * for each active edge |
|
3690 */ |
|
3691 while (pAET) { |
|
3692 /* |
|
3693 * add to the buffer only those edges that |
|
3694 * are in the Winding active edge table. |
|
3695 */ |
|
3696 if (pWETE == pAET) { |
|
3697 pts->setX(pAET->bres.minor_axis); |
|
3698 pts->setY(y); |
|
3699 ++pts; |
|
3700 ++iPts; |
|
3701 |
|
3702 /* |
|
3703 * send out the buffer |
|
3704 */ |
|
3705 if (iPts == NUMPTSTOBUFFER) { |
|
3706 tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK))); |
|
3707 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data); |
|
3708 curPtBlock->next = tmpPtBlock; |
|
3709 curPtBlock = tmpPtBlock; |
|
3710 pts = curPtBlock->pts; |
|
3711 ++numFullPtBlocks; |
|
3712 iPts = 0; |
|
3713 } |
|
3714 pWETE = pWETE->nextWETE; |
|
3715 } |
|
3716 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) |
|
3717 } |
|
3718 |
|
3719 /* |
|
3720 * recompute the winding active edge table if |
|
3721 * we just resorted or have exited an edge. |
|
3722 */ |
|
3723 if (InsertionSort(&AET) || fixWAET) { |
|
3724 computeWAET(&AET); |
|
3725 fixWAET = false; |
|
3726 } |
|
3727 } |
|
3728 } |
|
3729 } QT_CATCH(...) { |
|
3730 FreeStorage(SLLBlock.next); |
|
3731 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region); |
|
3732 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { |
|
3733 tmpPtBlock = curPtBlock->next; |
|
3734 free(curPtBlock); |
|
3735 curPtBlock = tmpPtBlock; |
|
3736 } |
|
3737 free(pETEs); |
|
3738 return 0; // this function returns 0 in case of an error |
|
3739 } |
|
3740 |
|
3741 FreeStorage(SLLBlock.next); |
|
3742 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region); |
|
3743 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { |
|
3744 tmpPtBlock = curPtBlock->next; |
|
3745 free(curPtBlock); |
|
3746 curPtBlock = tmpPtBlock; |
|
3747 } |
|
3748 free(pETEs); |
|
3749 return region; |
|
3750 } |
|
3751 // END OF PolyReg.c extract |
|
3752 |
|
3753 QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap) |
|
3754 { |
|
3755 QImage image = bitmap.toImage(); |
|
3756 |
|
3757 QRegionPrivate *region = new QRegionPrivate; |
|
3758 |
|
3759 QRect xr; |
|
3760 |
|
3761 #define AddSpan \ |
|
3762 { \ |
|
3763 xr.setCoords(prev1, y, x-1, y); \ |
|
3764 UnionRectWithRegion(&xr, region, *region); \ |
|
3765 } |
|
3766 |
|
3767 const uchar zero = 0; |
|
3768 bool little = image.format() == QImage::Format_MonoLSB; |
|
3769 |
|
3770 int x, |
|
3771 y; |
|
3772 for (y = 0; y < image.height(); ++y) { |
|
3773 uchar *line = image.scanLine(y); |
|
3774 int w = image.width(); |
|
3775 uchar all = zero; |
|
3776 int prev1 = -1; |
|
3777 for (x = 0; x < w;) { |
|
3778 uchar byte = line[x / 8]; |
|
3779 if (x > w - 8 || byte!=all) { |
|
3780 if (little) { |
|
3781 for (int b = 8; b > 0 && x < w; --b) { |
|
3782 if (!(byte & 0x01) == !all) { |
|
3783 // More of the same |
|
3784 } else { |
|
3785 // A change. |
|
3786 if (all!=zero) { |
|
3787 AddSpan |
|
3788 all = zero; |
|
3789 } else { |
|
3790 prev1 = x; |
|
3791 all = ~zero; |
|
3792 } |
|
3793 } |
|
3794 byte >>= 1; |
|
3795 ++x; |
|
3796 } |
|
3797 } else { |
|
3798 for (int b = 8; b > 0 && x < w; --b) { |
|
3799 if (!(byte & 0x80) == !all) { |
|
3800 // More of the same |
|
3801 } else { |
|
3802 // A change. |
|
3803 if (all != zero) { |
|
3804 AddSpan |
|
3805 all = zero; |
|
3806 } else { |
|
3807 prev1 = x; |
|
3808 all = ~zero; |
|
3809 } |
|
3810 } |
|
3811 byte <<= 1; |
|
3812 ++x; |
|
3813 } |
|
3814 } |
|
3815 } else { |
|
3816 x += 8; |
|
3817 } |
|
3818 } |
|
3819 if (all != zero) { |
|
3820 AddSpan |
|
3821 } |
|
3822 } |
|
3823 #undef AddSpan |
|
3824 |
|
3825 return region; |
|
3826 } |
|
3827 |
|
3828 QRegion::QRegion() |
|
3829 : d(&shared_empty) |
|
3830 { |
|
3831 d->ref.ref(); |
|
3832 } |
|
3833 |
|
3834 QRegion::QRegion(const QRect &r, RegionType t) |
|
3835 { |
|
3836 if (r.isEmpty()) { |
|
3837 d = &shared_empty; |
|
3838 d->ref.ref(); |
|
3839 } else { |
|
3840 d = new QRegionData; |
|
3841 d->ref = 1; |
|
3842 #if defined(Q_WS_X11) |
|
3843 d->rgn = 0; |
|
3844 d->xrectangles = 0; |
|
3845 #elif defined(Q_WS_WIN) |
|
3846 d->rgn = 0; |
|
3847 #endif |
|
3848 if (t == Rectangle) { |
|
3849 d->qt_rgn = new QRegionPrivate(r); |
|
3850 } else if (t == Ellipse) { |
|
3851 QPainterPath path; |
|
3852 path.addEllipse(r.x(), r.y(), r.width(), r.height()); |
|
3853 QPolygon a = path.toSubpathPolygons().at(0).toPolygon(); |
|
3854 d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule); |
|
3855 } |
|
3856 } |
|
3857 } |
|
3858 |
|
3859 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) |
|
3860 { |
|
3861 if (a.count() > 2) { |
|
3862 d = new QRegionData; |
|
3863 d->ref = 1; |
|
3864 #if defined(Q_WS_X11) |
|
3865 d->rgn = 0; |
|
3866 d->xrectangles = 0; |
|
3867 #elif defined(Q_WS_WIN) |
|
3868 d->rgn = 0; |
|
3869 #endif |
|
3870 d->qt_rgn = PolygonRegion(a.constData(), a.size(), |
|
3871 fillRule == Qt::WindingFill ? WindingRule : EvenOddRule); |
|
3872 } else { |
|
3873 d = &shared_empty; |
|
3874 d->ref.ref(); |
|
3875 } |
|
3876 } |
|
3877 |
|
3878 |
|
3879 QRegion::QRegion(const QRegion &r) |
|
3880 { |
|
3881 d = r.d; |
|
3882 d->ref.ref(); |
|
3883 } |
|
3884 |
|
3885 |
|
3886 QRegion::QRegion(const QBitmap &bm) |
|
3887 { |
|
3888 if (bm.isNull()) { |
|
3889 d = &shared_empty; |
|
3890 d->ref.ref(); |
|
3891 } else { |
|
3892 d = new QRegionData; |
|
3893 d->ref = 1; |
|
3894 #if defined(Q_WS_X11) |
|
3895 d->rgn = 0; |
|
3896 d->xrectangles = 0; |
|
3897 #elif defined(Q_WS_WIN) |
|
3898 d->rgn = 0; |
|
3899 #endif |
|
3900 d->qt_rgn = qt_bitmapToRegion(bm); |
|
3901 } |
|
3902 } |
|
3903 |
|
3904 void QRegion::cleanUp(QRegion::QRegionData *x) |
|
3905 { |
|
3906 delete x->qt_rgn; |
|
3907 #if defined(Q_WS_X11) |
|
3908 if (x->rgn) |
|
3909 XDestroyRegion(x->rgn); |
|
3910 if (x->xrectangles) |
|
3911 free(x->xrectangles); |
|
3912 #elif defined(Q_WS_WIN) |
|
3913 if (x->rgn) |
|
3914 qt_win_dispose_rgn(x->rgn); |
|
3915 #endif |
|
3916 delete x; |
|
3917 } |
|
3918 |
|
3919 QRegion::~QRegion() |
|
3920 { |
|
3921 if (!d->ref.deref()) |
|
3922 cleanUp(d); |
|
3923 } |
|
3924 |
|
3925 |
|
3926 QRegion &QRegion::operator=(const QRegion &r) |
|
3927 { |
|
3928 r.d->ref.ref(); |
|
3929 if (!d->ref.deref()) |
|
3930 cleanUp(d); |
|
3931 d = r.d; |
|
3932 return *this; |
|
3933 } |
|
3934 |
|
3935 |
|
3936 /*! |
|
3937 \internal |
|
3938 */ |
|
3939 QRegion QRegion::copy() const |
|
3940 { |
|
3941 QRegion r; |
|
3942 QScopedPointer<QRegionData> x(new QRegionData); |
|
3943 x->ref = 1; |
|
3944 #if defined(Q_WS_X11) |
|
3945 x->rgn = 0; |
|
3946 x->xrectangles = 0; |
|
3947 #elif defined(Q_WS_WIN) |
|
3948 x->rgn = 0; |
|
3949 #endif |
|
3950 if (d->qt_rgn) |
|
3951 x->qt_rgn = new QRegionPrivate(*d->qt_rgn); |
|
3952 else |
|
3953 x->qt_rgn = new QRegionPrivate; |
|
3954 if (!r.d->ref.deref()) |
|
3955 cleanUp(r.d); |
|
3956 r.d = x.take(); |
|
3957 return r; |
|
3958 } |
|
3959 |
|
3960 bool QRegion::isEmpty() const |
|
3961 { |
|
3962 return d == &shared_empty || d->qt_rgn->numRects == 0; |
|
3963 } |
|
3964 |
|
3965 |
|
3966 bool QRegion::contains(const QPoint &p) const |
|
3967 { |
|
3968 return PointInRegion(d->qt_rgn, p.x(), p.y()); |
|
3969 } |
|
3970 |
|
3971 bool QRegion::contains(const QRect &r) const |
|
3972 { |
|
3973 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut; |
|
3974 } |
|
3975 |
|
3976 |
|
3977 |
|
3978 void QRegion::translate(int dx, int dy) |
|
3979 { |
|
3980 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn)) |
|
3981 return; |
|
3982 |
|
3983 detach(); |
|
3984 OffsetRegion(*d->qt_rgn, dx, dy); |
|
3985 } |
|
3986 |
|
3987 QRegion QRegion::unite(const QRegion &r) const |
|
3988 { |
|
3989 if (isEmptyHelper(d->qt_rgn)) |
|
3990 return r; |
|
3991 if (isEmptyHelper(r.d->qt_rgn)) |
|
3992 return *this; |
|
3993 if (d == r.d) |
|
3994 return *this; |
|
3995 |
|
3996 if (d->qt_rgn->contains(*r.d->qt_rgn)) { |
|
3997 return *this; |
|
3998 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) { |
|
3999 return r; |
|
4000 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) { |
|
4001 QRegion result(*this); |
|
4002 result.detach(); |
|
4003 result.d->qt_rgn->append(r.d->qt_rgn); |
|
4004 return result; |
|
4005 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) { |
|
4006 QRegion result(*this); |
|
4007 result.detach(); |
|
4008 result.d->qt_rgn->prepend(r.d->qt_rgn); |
|
4009 return result; |
|
4010 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) { |
|
4011 return *this; |
|
4012 } else { |
|
4013 QRegion result; |
|
4014 result.detach(); |
|
4015 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn); |
|
4016 return result; |
|
4017 } |
|
4018 } |
|
4019 |
|
4020 QRegion& QRegion::operator+=(const QRegion &r) |
|
4021 { |
|
4022 if (isEmptyHelper(d->qt_rgn)) |
|
4023 return *this = r; |
|
4024 if (isEmptyHelper(r.d->qt_rgn)) |
|
4025 return *this; |
|
4026 if (d == r.d) |
|
4027 return *this; |
|
4028 |
|
4029 if (d->qt_rgn->contains(*r.d->qt_rgn)) { |
|
4030 return *this; |
|
4031 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) { |
|
4032 return *this = r; |
|
4033 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) { |
|
4034 detach(); |
|
4035 d->qt_rgn->append(r.d->qt_rgn); |
|
4036 return *this; |
|
4037 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) { |
|
4038 detach(); |
|
4039 d->qt_rgn->prepend(r.d->qt_rgn); |
|
4040 return *this; |
|
4041 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) { |
|
4042 return *this; |
|
4043 } else { |
|
4044 detach(); |
|
4045 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn); |
|
4046 return *this; |
|
4047 } |
|
4048 } |
|
4049 |
|
4050 QRegion QRegion::unite(const QRect &r) const |
|
4051 { |
|
4052 if (isEmptyHelper(d->qt_rgn)) |
|
4053 return r; |
|
4054 if (r.isEmpty()) |
|
4055 return *this; |
|
4056 |
|
4057 if (d->qt_rgn->contains(r)) { |
|
4058 return *this; |
|
4059 } else if (d->qt_rgn->within(r)) { |
|
4060 return r; |
|
4061 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) { |
|
4062 return *this; |
|
4063 } else if (d->qt_rgn->canAppend(&r)) { |
|
4064 QRegion result(*this); |
|
4065 result.detach(); |
|
4066 result.d->qt_rgn->append(&r); |
|
4067 return result; |
|
4068 } else if (d->qt_rgn->canPrepend(&r)) { |
|
4069 QRegion result(*this); |
|
4070 result.detach(); |
|
4071 result.d->qt_rgn->prepend(&r); |
|
4072 return result; |
|
4073 } else { |
|
4074 QRegion result; |
|
4075 result.detach(); |
|
4076 QRegionPrivate rp(r); |
|
4077 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn); |
|
4078 return result; |
|
4079 } |
|
4080 } |
|
4081 |
|
4082 QRegion& QRegion::operator+=(const QRect &r) |
|
4083 { |
|
4084 if (isEmptyHelper(d->qt_rgn)) |
|
4085 return *this = r; |
|
4086 if (r.isEmpty()) |
|
4087 return *this; |
|
4088 |
|
4089 if (d->qt_rgn->contains(r)) { |
|
4090 return *this; |
|
4091 } else if (d->qt_rgn->within(r)) { |
|
4092 return *this = r; |
|
4093 } else if (d->qt_rgn->canAppend(&r)) { |
|
4094 detach(); |
|
4095 d->qt_rgn->append(&r); |
|
4096 return *this; |
|
4097 } else if (d->qt_rgn->canPrepend(&r)) { |
|
4098 detach(); |
|
4099 d->qt_rgn->prepend(&r); |
|
4100 return *this; |
|
4101 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) { |
|
4102 return *this; |
|
4103 } else { |
|
4104 detach(); |
|
4105 QRegionPrivate p(r); |
|
4106 UnionRegion(d->qt_rgn, &p, *d->qt_rgn); |
|
4107 return *this; |
|
4108 } |
|
4109 } |
|
4110 |
|
4111 QRegion QRegion::intersect(const QRegion &r) const |
|
4112 { |
|
4113 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn) |
|
4114 || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) |
|
4115 return QRegion(); |
|
4116 |
|
4117 /* this is fully contained in r */ |
|
4118 if (r.d->qt_rgn->contains(*d->qt_rgn)) |
|
4119 return *this; |
|
4120 |
|
4121 /* r is fully contained in this */ |
|
4122 if (d->qt_rgn->contains(*r.d->qt_rgn)) |
|
4123 return r; |
|
4124 |
|
4125 if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) { |
|
4126 const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents, |
|
4127 d->qt_rgn->extents); |
|
4128 return QRegion(rect); |
|
4129 } else if (r.d->qt_rgn->numRects == 1) { |
|
4130 QRegion result(*this); |
|
4131 result.detach(); |
|
4132 result.d->qt_rgn->intersect(r.d->qt_rgn->extents); |
|
4133 return result; |
|
4134 } else if (d->qt_rgn->numRects == 1) { |
|
4135 QRegion result(r); |
|
4136 result.detach(); |
|
4137 result.d->qt_rgn->intersect(d->qt_rgn->extents); |
|
4138 return result; |
|
4139 } |
|
4140 |
|
4141 QRegion result; |
|
4142 result.detach(); |
|
4143 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0); |
|
4144 |
|
4145 /* |
|
4146 * Can't alter dest's extents before we call miRegionOp because |
|
4147 * it might be one of the source regions and miRegionOp depends |
|
4148 * on the extents of those regions being the same. Besides, this |
|
4149 * way there's no checking against rectangles that will be nuked |
|
4150 * due to coalescing, so we have to examine fewer rectangles. |
|
4151 */ |
|
4152 miSetExtents(*result.d->qt_rgn); |
|
4153 return result; |
|
4154 } |
|
4155 |
|
4156 QRegion QRegion::intersect(const QRect &r) const |
|
4157 { |
|
4158 if (isEmptyHelper(d->qt_rgn) || r.isEmpty() |
|
4159 || !EXTENTCHECK(&d->qt_rgn->extents, &r)) |
|
4160 return QRegion(); |
|
4161 |
|
4162 /* this is fully contained in r */ |
|
4163 if (d->qt_rgn->within(r)) |
|
4164 return *this; |
|
4165 |
|
4166 /* r is fully contained in this */ |
|
4167 if (d->qt_rgn->contains(r)) |
|
4168 return r; |
|
4169 |
|
4170 if (d->qt_rgn->numRects == 1) { |
|
4171 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents, |
|
4172 r.normalized()); |
|
4173 return QRegion(rect); |
|
4174 } |
|
4175 |
|
4176 QRegion result(*this); |
|
4177 result.detach(); |
|
4178 result.d->qt_rgn->intersect(r); |
|
4179 return result; |
|
4180 } |
|
4181 |
|
4182 QRegion QRegion::subtract(const QRegion &r) const |
|
4183 { |
|
4184 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)) |
|
4185 return *this; |
|
4186 if (r.d->qt_rgn->contains(*d->qt_rgn)) |
|
4187 return QRegion(); |
|
4188 if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) |
|
4189 return *this; |
|
4190 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) |
|
4191 return QRegion(); |
|
4192 |
|
4193 #ifdef QT_REGION_DEBUG |
|
4194 d->qt_rgn->selfTest(); |
|
4195 r.d->qt_rgn->selfTest(); |
|
4196 #endif |
|
4197 |
|
4198 QRegion result; |
|
4199 result.detach(); |
|
4200 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn); |
|
4201 #ifdef QT_REGION_DEBUG |
|
4202 result.d->qt_rgn->selfTest(); |
|
4203 #endif |
|
4204 return result; |
|
4205 } |
|
4206 |
|
4207 QRegion QRegion::eor(const QRegion &r) const |
|
4208 { |
|
4209 if (isEmptyHelper(d->qt_rgn)) { |
|
4210 return r; |
|
4211 } else if (isEmptyHelper(r.d->qt_rgn)) { |
|
4212 return *this; |
|
4213 } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) { |
|
4214 return (*this + r); |
|
4215 } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) { |
|
4216 return QRegion(); |
|
4217 } else { |
|
4218 QRegion result; |
|
4219 result.detach(); |
|
4220 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn); |
|
4221 return result; |
|
4222 } |
|
4223 } |
|
4224 |
|
4225 QRect QRegion::boundingRect() const |
|
4226 { |
|
4227 if (isEmpty()) |
|
4228 return QRect(); |
|
4229 return d->qt_rgn->extents; |
|
4230 } |
|
4231 |
|
4232 /*! \internal |
|
4233 Returns true if \a rect is guaranteed to be fully contained in \a region. |
|
4234 A false return value does not guarantee the opposite. |
|
4235 */ |
|
4236 #ifdef Q_WS_QWS |
|
4237 Q_GUI_EXPORT |
|
4238 #endif |
|
4239 bool qt_region_strictContains(const QRegion ®ion, const QRect &rect) |
|
4240 { |
|
4241 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid()) |
|
4242 return false; |
|
4243 |
|
4244 #if 0 // TEST_INNERRECT |
|
4245 static bool guard = false; |
|
4246 if (guard) |
|
4247 return false; |
|
4248 guard = true; |
|
4249 QRegion inner = region.d->qt_rgn->innerRect; |
|
4250 Q_ASSERT((inner - region).isEmpty()); |
|
4251 guard = false; |
|
4252 |
|
4253 int maxArea = 0; |
|
4254 for (int i = 0; i < region.d->qt_rgn->numRects; ++i) { |
|
4255 const QRect r = region.d->qt_rgn->rects.at(i); |
|
4256 if (r.width() * r.height() > maxArea) |
|
4257 maxArea = r.width() * r.height(); |
|
4258 } |
|
4259 |
|
4260 if (maxArea > region.d->qt_rgn->innerArea) { |
|
4261 qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect; |
|
4262 } |
|
4263 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea); |
|
4264 #endif |
|
4265 |
|
4266 const QRect r1 = region.d->qt_rgn->innerRect; |
|
4267 return (rect.left() >= r1.left() && rect.right() <= r1.right() |
|
4268 && rect.top() >= r1.top() && rect.bottom() <= r1.bottom()); |
|
4269 } |
|
4270 |
|
4271 QVector<QRect> QRegion::rects() const |
|
4272 { |
|
4273 if (d->qt_rgn) { |
|
4274 d->qt_rgn->vectorize(); |
|
4275 // hw: modify the vector size directly to avoid reallocation |
|
4276 d->qt_rgn->rects.d->size = d->qt_rgn->numRects; |
|
4277 return d->qt_rgn->rects; |
|
4278 } else { |
|
4279 return QVector<QRect>(); |
|
4280 } |
|
4281 } |
|
4282 |
|
4283 void QRegion::setRects(const QRect *rects, int num) |
|
4284 { |
|
4285 *this = QRegion(); |
|
4286 if (!rects || num == 0 || (num == 1 && rects->isEmpty())) |
|
4287 return; |
|
4288 |
|
4289 detach(); |
|
4290 |
|
4291 d->qt_rgn->numRects = num; |
|
4292 if (num == 1) { |
|
4293 d->qt_rgn->extents = *rects; |
|
4294 d->qt_rgn->innerRect = *rects; |
|
4295 } else { |
|
4296 d->qt_rgn->rects.resize(num); |
|
4297 |
|
4298 int left = INT_MAX, |
|
4299 right = INT_MIN, |
|
4300 top = INT_MAX, |
|
4301 bottom = INT_MIN; |
|
4302 for (int i = 0; i < num; ++i) { |
|
4303 const QRect &rect = rects[i]; |
|
4304 d->qt_rgn->rects[i] = rect; |
|
4305 left = qMin(rect.left(), left); |
|
4306 right = qMax(rect.right(), right); |
|
4307 top = qMin(rect.top(), top); |
|
4308 bottom = qMax(rect.bottom(), bottom); |
|
4309 d->qt_rgn->updateInnerRect(rect); |
|
4310 } |
|
4311 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom)); |
|
4312 } |
|
4313 } |
|
4314 |
|
4315 int QRegion::numRects() const |
|
4316 { |
|
4317 return (d->qt_rgn ? d->qt_rgn->numRects : 0); |
|
4318 } |
|
4319 |
|
4320 bool QRegion::operator==(const QRegion &r) const |
|
4321 { |
|
4322 if (!d->qt_rgn) |
|
4323 return r.isEmpty(); |
|
4324 if (!r.d->qt_rgn) |
|
4325 return isEmpty(); |
|
4326 |
|
4327 if (d == r.d) |
|
4328 return true; |
|
4329 else |
|
4330 return EqualRegion(d->qt_rgn, r.d->qt_rgn); |
|
4331 } |
|
4332 |
|
4333 #endif |
|
4334 QT_END_NAMESPACE |