source: trunk/src/gui/painting/qregion.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 132.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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
58QT_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*/
248QRegion::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*/
260QRegion::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
273void 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#if defined(Q_WS_PM)
284 else {
285 // cause a new HRGN to be created when necessary
286 disposeHandle(d->rgn);
287 d->height = 0;
288 }
289#endif
290}
291
292// duplicates in qregion_win.cpp and qregion_wce.cpp
293#define QRGN_SETRECT 1 // region stream commands
294#define QRGN_SETELLIPSE 2 // (these are internal)
295#define QRGN_SETPTARRAY_ALT 3
296#define QRGN_SETPTARRAY_WIND 4
297#define QRGN_TRANSLATE 5
298#define QRGN_OR 6
299#define QRGN_AND 7
300#define QRGN_SUB 8
301#define QRGN_XOR 9
302#define QRGN_RECTS 10
303
304
305#ifndef QT_NO_DATASTREAM
306
307/*
308 Executes region commands in the internal buffer and rebuilds the
309 original region.
310
311 We do this when we read a region from the data stream.
312
313 If \a ver is non-0, uses the format version \a ver on reading the
314 byte array.
315*/
316void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
317{
318 QByteArray copy = buffer;
319 QDataStream s(&copy, QIODevice::ReadOnly);
320 if (ver)
321 s.setVersion(ver);
322 s.setByteOrder(byteOrder);
323 QRegion rgn;
324#ifndef QT_NO_DEBUG
325 int test_cnt = 0;
326#endif
327 while (!s.atEnd()) {
328 qint32 id;
329 if (s.version() == 1) {
330 int id_int;
331 s >> id_int;
332 id = id_int;
333 } else {
334 s >> id;
335 }
336#ifndef QT_NO_DEBUG
337 if (test_cnt > 0 && id != QRGN_TRANSLATE)
338 qWarning("QRegion::exec: Internal error");
339 test_cnt++;
340#endif
341 if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
342 QRect r;
343 s >> r;
344 rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
345 } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
346 QPolygon a;
347 s >> a;
348 rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
349 } else if (id == QRGN_TRANSLATE) {
350 QPoint p;
351 s >> p;
352 rgn.translate(p.x(), p.y());
353 } else if (id >= QRGN_OR && id <= QRGN_XOR) {
354 QByteArray bop1, bop2;
355 QRegion r1, r2;
356 s >> bop1;
357 r1.exec(bop1);
358 s >> bop2;
359 r2.exec(bop2);
360
361 switch (id) {
362 case QRGN_OR:
363 rgn = r1.united(r2);
364 break;
365 case QRGN_AND:
366 rgn = r1.intersected(r2);
367 break;
368 case QRGN_SUB:
369 rgn = r1.subtracted(r2);
370 break;
371 case QRGN_XOR:
372 rgn = r1.xored(r2);
373 break;
374 }
375 } else if (id == QRGN_RECTS) {
376 // (This is the only form used in Qt 2.0)
377 quint32 n;
378 s >> n;
379 QRect r;
380 for (int i=0; i<(int)n; i++) {
381 s >> r;
382 rgn = rgn.united(QRegion(r));
383 }
384 }
385 }
386 *this = rgn;
387}
388
389
390/*****************************************************************************
391 QRegion stream functions
392 *****************************************************************************/
393
394/*!
395 \fn QRegion &QRegion::operator=(const QRegion &r)
396
397 Assigns \a r to this region and returns a reference to the region.
398*/
399
400/*!
401 \relates QRegion
402
403 Writes the region \a r to the stream \a s and returns a reference
404 to the stream.
405
406 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
407*/
408
409QDataStream &operator<<(QDataStream &s, const QRegion &r)
410{
411 QVector<QRect> a = r.rects();
412 if (a.isEmpty()) {
413 s << (quint32)0;
414 } else {
415 if (s.version() == 1) {
416 int i;
417 for (i = a.size() - 1; i > 0; --i) {
418 s << (quint32)(12 + i * 24);
419 s << (int)QRGN_OR;
420 }
421 for (i = 0; i < a.size(); ++i) {
422 s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i];
423 }
424 } else {
425 s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect
426 s << (qint32)QRGN_RECTS;
427 s << a;
428 }
429 }
430 return s;
431}
432
433/*!
434 \relates QRegion
435
436 Reads a region from the stream \a s into \a r and returns a
437 reference to the stream.
438
439 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
440*/
441
442QDataStream &operator>>(QDataStream &s, QRegion &r)
443{
444 QByteArray b;
445 s >> b;
446 r.exec(b, s.version(), s.byteOrder());
447 return s;
448}
449#endif //QT_NO_DATASTREAM
450
451#ifndef QT_NO_DEBUG_STREAM
452QDebug operator<<(QDebug s, const QRegion &r)
453{
454 QVector<QRect> rects = r.rects();
455 s.nospace() << "QRegion(size=" << rects.size() << "), "
456 << "bounds = " << r.boundingRect() << '\n';
457 for (int i=0; i<rects.size(); ++i)
458 s << "- " << i << rects.at(i) << '\n';
459 return s;
460}
461#endif
462
463
464// These are not inline - they can be implemented better on some platforms
465// (eg. Windows at least provides 3-variable operations). For now, simple.
466
467
468/*!
469 Applies the united() function to this region and \a r. \c r1|r2 is
470 equivalent to \c r1.united(r2).
471
472 \sa united(), operator+()
473*/
474const QRegion QRegion::operator|(const QRegion &r) const
475 { return united(r); }
476
477/*!
478 Applies the united() function to this region and \a r. \c r1+r2 is
479 equivalent to \c r1.united(r2).
480
481 \sa united(), operator|()
482*/
483const QRegion QRegion::operator+(const QRegion &r) const
484 { return united(r); }
485
486/*!
487 \overload
488 \since 4.4
489 */
490const QRegion QRegion::operator+(const QRect &r) const
491 { return united(r); }
492
493/*!
494 Applies the intersected() function to this region and \a r. \c r1&r2
495 is equivalent to \c r1.intersected(r2).
496
497 \sa intersected()
498*/
499const QRegion QRegion::operator&(const QRegion &r) const
500 { return intersected(r); }
501
502/*!
503 \overload
504 \since 4.4
505 */
506const QRegion QRegion::operator&(const QRect &r) const
507{
508 return intersected(r);
509}
510
511/*!
512 Applies the subtracted() function to this region and \a r. \c r1-r2
513 is equivalent to \c r1.subtracted(r2).
514
515 \sa subtracted()
516*/
517const QRegion QRegion::operator-(const QRegion &r) const
518 { return subtracted(r); }
519
520/*!
521 Applies the xored() function to this region and \a r. \c r1^r2 is
522 equivalent to \c r1.xored(r2).
523
524 \sa xored()
525*/
526const QRegion QRegion::operator^(const QRegion &r) const
527 { return xored(r); }
528
529/*!
530 Applies the united() function to this region and \a r and assigns
531 the result to this region. \c r1|=r2 is equivalent to \c
532 {r1 = r1.united(r2)}.
533
534 \sa united()
535*/
536QRegion& QRegion::operator|=(const QRegion &r)
537 { return *this = *this | r; }
538
539/*!
540 \fn QRegion& QRegion::operator+=(const QRect &rect)
541
542 Returns a region that is the union of this region with the specified \a rect.
543
544 \sa united()
545*/
546/*!
547 \fn QRegion& QRegion::operator+=(const QRegion &r)
548
549 Applies the united() function to this region and \a r and assigns
550 the result to this region. \c r1+=r2 is equivalent to \c
551 {r1 = r1.united(r2)}.
552
553 \sa intersected()
554*/
555#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) && !defined (Q_WS_PM)
556QRegion& QRegion::operator+=(const QRect &r)
557{
558 return operator+=(QRegion(r));
559}
560#endif
561
562/*!
563 \fn QRegion& QRegion::operator&=(const QRegion &r)
564
565 Applies the intersected() function to this region and \a r and
566 assigns the result to this region. \c r1&=r2 is equivalent to \c
567 r1 = r1.intersected(r2).
568
569 \sa intersected()
570*/
571QRegion& QRegion::operator&=(const QRegion &r)
572 { return *this = *this & r; }
573
574/*!
575 \overload
576 \since 4.4
577 */
578#if defined (Q_OS_UNIX) || defined (Q_WS_WIN) || defined (Q_WS_PM)
579QRegion& QRegion::operator&=(const QRect &r)
580{
581 return *this = *this & r;
582}
583#else
584QRegion& QRegion::operator&=(const QRect &r)
585{
586 return *this &= (QRegion(r));
587}
588#endif
589
590/*!
591 \fn QRegion& QRegion::operator-=(const QRegion &r)
592
593 Applies the subtracted() function to this region and \a r and
594 assigns the result to this region. \c r1-=r2 is equivalent to \c
595 {r1 = r1.subtracted(r2)}.
596
597 \sa subtracted()
598*/
599QRegion& QRegion::operator-=(const QRegion &r)
600 { return *this = *this - r; }
601
602/*!
603 Applies the xored() function to this region and \a r and
604 assigns the result to this region. \c r1^=r2 is equivalent to \c
605 {r1 = r1.xored(r2)}.
606
607 \sa xored()
608*/
609QRegion& QRegion::operator^=(const QRegion &r)
610 { return *this = *this ^ r; }
611
612/*!
613 \fn bool QRegion::operator!=(const QRegion &other) const
614
615 Returns true if this region is different from the \a other region;
616 otherwise returns false.
617*/
618
619/*!
620 Returns the region as a QVariant
621*/
622QRegion::operator QVariant() const
623{
624 return QVariant(QVariant::Region, this);
625}
626
627/*!
628 \fn bool QRegion::operator==(const QRegion &r) const
629
630 Returns true if the region is equal to \a r; otherwise returns
631 false.
632*/
633
634/*!
635 \fn bool QRegion::isNull() const
636
637 Use isEmpty() instead.
638*/
639
640
641/*!
642 \fn void QRegion::translate(int dx, int dy)
643
644 Translates (moves) the region \a dx along the X axis and \a dy
645 along the Y axis.
646*/
647
648/*!
649 \fn QRegion QRegion::translated(const QPoint &p) const
650 \overload
651 \since 4.1
652
653 Returns a copy of the regtion that is translated \a{p}\e{.x()}
654 along the x axis and \a{p}\e{.y()} along the y axis, relative to
655 the current position. Positive values move the rectangle to the
656 right and down.
657
658 \sa translate()
659*/
660
661/*!
662 \since 4.1
663
664 Returns a copy of the region that is translated \a dx along the
665 x axis and \a dy along the y axis, relative to the current
666 position. Positive values move the region to the right and
667 down.
668
669 \sa translate()
670*/
671
672QRegion
673QRegion::translated(int dx, int dy) const
674{
675 QRegion ret(*this);
676 ret.translate(dx, dy);
677 return ret;
678}
679
680
681inline bool rect_intersects(const QRect &r1, const QRect &r2)
682{
683 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
684 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
685}
686
687/*!
688 \since 4.2
689
690 Returns true if this region intersects with \a region, otherwise
691 returns false.
692*/
693bool QRegion::intersects(const QRegion &region) const
694{
695 if (isEmpty() || region.isEmpty())
696 return false;
697
698 if (!rect_intersects(boundingRect(), region.boundingRect()))
699 return false;
700 if (rectCount() == 1 && region.rectCount() == 1)
701 return true;
702
703 const QVector<QRect> myRects = rects();
704 const QVector<QRect> otherRects = region.rects();
705
706 for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1)
707 for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2)
708 if (rect_intersects(*i1, *i2))
709 return true;
710 return false;
711}
712
713/*!
714 \fn bool QRegion::intersects(const QRect &rect) const
715 \since 4.2
716
717 Returns true if this region intersects with \a rect, otherwise
718 returns false.
719*/
720
721
722#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN) && !defined (Q_WS_PM)
723/*!
724 \overload
725 \since 4.4
726*/
727QRegion QRegion::intersect(const QRect &r) const
728{
729 return intersect(QRegion(r));
730}
731#endif
732
733/*!
734 \obsolete
735 \fn int QRegion::numRects() const
736 \since 4.4
737
738 Returns the number of rectangles that will be returned in rects().
739*/
740
741/*!
742 \fn int QRegion::rectCount() const
743 \since 4.6
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
925namespace {
926
927struct 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
990void 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
1007void 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
1027Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
1028{
1029 QPainterPath result;
1030 if (region.rectCount() == 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) || defined(Q_WS_PM)
1086
1087//#define QT_REGION_DEBUG
1088/*
1089 * clip region
1090 */
1091
1092struct 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
1188static inline bool isEmptyHelper(const QRegionPrivate *preg)
1189{
1190 return !preg || preg->numRects == 0;
1191}
1192
1193static 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
1200static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
1201{
1202 return canMergeFromRight(left, right);
1203}
1204
1205bool 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
1215bool 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
1225static 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
1239bool 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
1251bool 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
1263static 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
1274void 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
1327void 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
1358void 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
1431void 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
1504void 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
1536bool 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
1553bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
1554{
1555 return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
1556}
1557
1558bool 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
1575bool 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
1581void 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)
1619QT_BEGIN_INCLUDE_NAMESPACE
1620# include "qregion_x11.cpp"
1621QT_END_INCLUDE_NAMESPACE
1622#elif defined(Q_WS_MAC)
1623QT_BEGIN_INCLUDE_NAMESPACE
1624# include "qregion_mac.cpp"
1625QT_END_INCLUDE_NAMESPACE
1626#elif defined(Q_WS_WIN)
1627QT_BEGIN_INCLUDE_NAMESPACE
1628# include "qregion_win.cpp"
1629QT_END_INCLUDE_NAMESPACE
1630#elif defined(Q_WS_PM)
1631QT_BEGIN_INCLUDE_NAMESPACE
1632# include "qregion_pm.cpp"
1633QT_END_INCLUDE_NAMESPACE
1634#elif defined(Q_WS_QWS)
1635static QRegionPrivate qrp;
1636QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp};
1637#endif
1638
1639typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
1640 register const QRect *r2, const QRect *r2End, register int y1, register int y2);
1641typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
1642 register int y1, register int y2);
1643
1644static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
1645static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
1646static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
1647 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
1648 NonOverlapFunc nonOverlap2Func);
1649
1650#define RectangleOut 0
1651#define RectangleIn 1
1652#define RectanglePart 2
1653#define EvenOddRule 0
1654#define WindingRule 1
1655
1656// START OF region.h extract
1657/* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
1658/************************************************************************
1659
1660Copyright (c) 1987 X Consortium
1661
1662Permission is hereby granted, free of charge, to any person obtaining a copy
1663of this software and associated documentation files (the "Software"), to deal
1664in the Software without restriction, including without limitation the rights
1665to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1666copies of the Software, and to permit persons to whom the Software is
1667furnished to do so, subject to the following conditions:
1668
1669The above copyright notice and this permission notice shall be included in
1670all copies or substantial portions of the Software.
1671
1672THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1673IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1674FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1675X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1676AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1677CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1678
1679Except as contained in this notice, the name of the X Consortium shall not be
1680used in advertising or otherwise to promote the sale, use or other dealings
1681in this Software without prior written authorization from the X Consortium.
1682
1683
1684Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
1685
1686 All Rights Reserved
1687
1688Permission to use, copy, modify, and distribute this software and its
1689documentation for any purpose and without fee is hereby granted,
1690provided that the above copyright notice appear in all copies and that
1691both that copyright notice and this permission notice appear in
1692supporting documentation, and that the name of Digital not be
1693used in advertising or publicity pertaining to distribution of the
1694software without specific, written prior permission.
1695
1696DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1697ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1698DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1699ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1700WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1701ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1702SOFTWARE.
1703
1704************************************************************************/
1705
1706#ifndef _XREGION_H
1707#define _XREGION_H
1708
1709QT_BEGIN_INCLUDE_NAMESPACE
1710#include <limits.h>
1711QT_END_INCLUDE_NAMESPACE
1712
1713/* 1 if two BOXes overlap.
1714 * 0 if two BOXes do not overlap.
1715 * Remember, x2 and y2 are not in the region
1716 */
1717#define EXTENTCHECK(r1, r2) \
1718 ((r1)->right() >= (r2)->left() && \
1719 (r1)->left() <= (r2)->right() && \
1720 (r1)->bottom() >= (r2)->top() && \
1721 (r1)->top() <= (r2)->bottom())
1722
1723/*
1724 * update region extents
1725 */
1726#define EXTENTS(r,idRect){\
1727 if((r)->left() < (idRect)->extents.left())\
1728 (idRect)->extents.setLeft((r)->left());\
1729 if((r)->top() < (idRect)->extents.top())\
1730 (idRect)->extents.setTop((r)->top());\
1731 if((r)->right() > (idRect)->extents.right())\
1732 (idRect)->extents.setRight((r)->right());\
1733 if((r)->bottom() > (idRect)->extents.bottom())\
1734 (idRect)->extents.setBottom((r)->bottom());\
1735 }
1736
1737/*
1738 * Check to see if there is enough memory in the present region.
1739 */
1740#define MEMCHECK(dest, rect, firstrect){\
1741 if ((dest).numRects >= ((dest).rects.size()-1)){\
1742 firstrect.resize(firstrect.size() * 2); \
1743 (rect) = (firstrect).data() + (dest).numRects;\
1744 }\
1745 }
1746
1747
1748/*
1749 * number of points to buffer before sending them off
1750 * to scanlines(): Must be an even number
1751 */
1752#define NUMPTSTOBUFFER 200
1753
1754/*
1755 * used to allocate buffers for points and link
1756 * the buffers together
1757 */
1758typedef struct _POINTBLOCK {
1759 int data[NUMPTSTOBUFFER * sizeof(QPoint)];
1760 QPoint *pts;
1761 struct _POINTBLOCK *next;
1762} POINTBLOCK;
1763
1764#endif
1765// END OF region.h extract
1766
1767// START OF Region.c extract
1768/* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
1769/************************************************************************
1770
1771Copyright (c) 1987, 1988 X Consortium
1772
1773Permission is hereby granted, free of charge, to any person obtaining a copy
1774of this software and associated documentation files (the "Software"), to deal
1775in the Software without restriction, including without limitation the rights
1776to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1777copies of the Software, and to permit persons to whom the Software is
1778furnished to do so, subject to the following conditions:
1779
1780The above copyright notice and this permission notice shall be included in
1781all copies or substantial portions of the Software.
1782
1783THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1784IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1785FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1786X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1787AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1788CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1789
1790Except as contained in this notice, the name of the X Consortium shall not be
1791used in advertising or otherwise to promote the sale, use or other dealings
1792in this Software without prior written authorization from the X Consortium.
1793
1794
1795Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
1796
1797 All Rights Reserved
1798
1799Permission to use, copy, modify, and distribute this software and its
1800documentation for any purpose and without fee is hereby granted,
1801provided that the above copyright notice appear in all copies and that
1802both that copyright notice and this permission notice appear in
1803supporting documentation, and that the name of Digital not be
1804used in advertising or publicity pertaining to distribution of the
1805software without specific, written prior permission.
1806
1807DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1808ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1809DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1810ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1811WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1812ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1813SOFTWARE.
1814
1815************************************************************************/
1816/*
1817 * The functions in this file implement the Region abstraction, similar to one
1818 * used in the X11 sample server. A Region is simply an area, as the name
1819 * implies, and is implemented as a "y-x-banded" array of rectangles. To
1820 * explain: Each Region is made up of a certain number of rectangles sorted
1821 * by y coordinate first, and then by x coordinate.
1822 *
1823 * Furthermore, the rectangles are banded such that every rectangle with a
1824 * given upper-left y coordinate (y1) will have the same lower-right y
1825 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
1826 * will span the entire vertical distance of the band. This means that some
1827 * areas that could be merged into a taller rectangle will be represented as
1828 * several shorter rectangles to account for shorter rectangles to its left
1829 * or right but within its "vertical scope".
1830 *
1831 * An added constraint on the rectangles is that they must cover as much
1832 * horizontal area as possible. E.g. no two rectangles in a band are allowed
1833 * to touch.
1834 *
1835 * Whenever possible, bands will be merged together to cover a greater vertical
1836 * distance (and thus reduce the number of rectangles). Two bands can be merged
1837 * only if the bottom of one touches the top of the other and they have
1838 * rectangles in the same places (of the same width, of course). This maintains
1839 * the y-x-banding that's so nice to have...
1840 */
1841/* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
1842
1843static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source,
1844 QRegionPrivate &dest)
1845{
1846 if (rect->isEmpty())
1847 return;
1848
1849 Q_ASSERT(EqualRegion(source, &dest));
1850
1851 if (dest.numRects == 0) {
1852 dest = QRegionPrivate(*rect);
1853 } else if (dest.canAppend(rect)) {
1854 dest.append(rect);
1855 } else {
1856 QRegionPrivate p(*rect);
1857 UnionRegion(&p, source, dest);
1858 }
1859}
1860
1861/*-
1862 *-----------------------------------------------------------------------
1863 * miSetExtents --
1864 * Reset the extents and innerRect of a region to what they should be.
1865 * Called by miSubtract and miIntersect b/c they can't figure it out
1866 * along the way or do so easily, as miUnion can.
1867 *
1868 * Results:
1869 * None.
1870 *
1871 * Side Effects:
1872 * The region's 'extents' and 'innerRect' structure is overwritten.
1873 *
1874 *-----------------------------------------------------------------------
1875 */
1876static void miSetExtents(QRegionPrivate &dest)
1877{
1878 register const QRect *pBox,
1879 *pBoxEnd;
1880 register QRect *pExtents;
1881
1882 dest.innerRect.setCoords(0, 0, -1, -1);
1883 dest.innerArea = -1;
1884 if (dest.numRects == 0) {
1885 dest.extents.setCoords(0, 0, -1, -1);
1886 return;
1887 }
1888
1889 pExtents = &dest.extents;
1890 if (dest.rects.isEmpty())
1891 pBox = &dest.extents;
1892 else
1893 pBox = dest.rects.constData();
1894 pBoxEnd = pBox + dest.numRects - 1;
1895
1896 /*
1897 * Since pBox is the first rectangle in the region, it must have the
1898 * smallest y1 and since pBoxEnd is the last rectangle in the region,
1899 * it must have the largest y2, because of banding. Initialize x1 and
1900 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
1901 * to...
1902 */
1903 pExtents->setLeft(pBox->left());
1904 pExtents->setTop(pBox->top());
1905 pExtents->setRight(pBoxEnd->right());
1906 pExtents->setBottom(pBoxEnd->bottom());
1907
1908 Q_ASSERT(pExtents->top() <= pExtents->bottom());
1909 while (pBox <= pBoxEnd) {
1910 if (pBox->left() < pExtents->left())
1911 pExtents->setLeft(pBox->left());
1912 if (pBox->right() > pExtents->right())
1913 pExtents->setRight(pBox->right());
1914 dest.updateInnerRect(*pBox);
1915 ++pBox;
1916 }
1917 Q_ASSERT(pExtents->left() <= pExtents->right());
1918}
1919
1920/* TranslateRegion(pRegion, x, y)
1921 translates in place
1922 added by raymond
1923*/
1924
1925static void OffsetRegion(register QRegionPrivate &region, register int x, register int y)
1926{
1927 if (region.rects.size()) {
1928 register QRect *pbox = region.rects.data();
1929 register int nbox = region.numRects;
1930
1931 while (nbox--) {
1932 pbox->translate(x, y);
1933 ++pbox;
1934 }
1935 }
1936 region.extents.translate(x, y);
1937 region.innerRect.translate(x, y);
1938}
1939
1940/*======================================================================
1941 * Region Intersection
1942 *====================================================================*/
1943/*-
1944 *-----------------------------------------------------------------------
1945 * miIntersectO --
1946 * Handle an overlapping band for miIntersect.
1947 *
1948 * Results:
1949 * None.
1950 *
1951 * Side Effects:
1952 * Rectangles may be added to the region.
1953 *
1954 *-----------------------------------------------------------------------
1955 */
1956static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
1957 register const QRect *r2, const QRect *r2End, int y1, int y2)
1958{
1959 register int x1;
1960 register int x2;
1961 register QRect *pNextRect;
1962
1963 pNextRect = dest.rects.data() + dest.numRects;
1964
1965 while (r1 != r1End && r2 != r2End) {
1966 x1 = qMax(r1->left(), r2->left());
1967 x2 = qMin(r1->right(), r2->right());
1968
1969 /*
1970 * If there's any overlap between the two rectangles, add that
1971 * overlap to the new region.
1972 * There's no need to check for subsumption because the only way
1973 * such a need could arise is if some region has two rectangles
1974 * right next to each other. Since that should never happen...
1975 */
1976 if (x1 <= x2) {
1977 Q_ASSERT(y1 <= y2);
1978 MEMCHECK(dest, pNextRect, dest.rects)
1979 pNextRect->setCoords(x1, y1, x2, y2);
1980 ++dest.numRects;
1981 ++pNextRect;
1982 }
1983
1984 /*
1985 * Need to advance the pointers. Shift the one that extends
1986 * to the right the least, since the other still has a chance to
1987 * overlap with that region's next rectangle, if you see what I mean.
1988 */
1989 if (r1->right() < r2->right()) {
1990 ++r1;
1991 } else if (r2->right() < r1->right()) {
1992 ++r2;
1993 } else {
1994 ++r1;
1995 ++r2;
1996 }
1997 }
1998}
1999
2000/*======================================================================
2001 * Generic Region Operator
2002 *====================================================================*/
2003
2004/*-
2005 *-----------------------------------------------------------------------
2006 * miCoalesce --
2007 * Attempt to merge the boxes in the current band with those in the
2008 * previous one. Used only by miRegionOp.
2009 *
2010 * Results:
2011 * The new index for the previous band.
2012 *
2013 * Side Effects:
2014 * If coalescing takes place:
2015 * - rectangles in the previous band will have their y2 fields
2016 * altered.
2017 * - dest.numRects will be decreased.
2018 *
2019 *-----------------------------------------------------------------------
2020 */
2021static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart)
2022{
2023 register QRect *pPrevBox; /* Current box in previous band */
2024 register QRect *pCurBox; /* Current box in current band */
2025 register QRect *pRegEnd; /* End of region */
2026 int curNumRects; /* Number of rectangles in current band */
2027 int prevNumRects; /* Number of rectangles in previous band */
2028 int bandY1; /* Y1 coordinate for current band */
2029 QRect *rData = dest.rects.data();
2030
2031 pRegEnd = rData + dest.numRects;
2032
2033 pPrevBox = rData + prevStart;
2034 prevNumRects = curStart - prevStart;
2035
2036 /*
2037 * Figure out how many rectangles are in the current band. Have to do
2038 * this because multiple bands could have been added in miRegionOp
2039 * at the end when one region has been exhausted.
2040 */
2041 pCurBox = rData + curStart;
2042 bandY1 = pCurBox->top();
2043 for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
2044 ++pCurBox;
2045 }
2046
2047 if (pCurBox != pRegEnd) {
2048 /*
2049 * If more than one band was added, we have to find the start
2050 * of the last band added so the next coalescing job can start
2051 * at the right place... (given when multiple bands are added,
2052 * this may be pointless -- see above).
2053 */
2054 --pRegEnd;
2055 while ((pRegEnd - 1)->top() == pRegEnd->top())
2056 --pRegEnd;
2057 curStart = pRegEnd - rData;
2058 pRegEnd = rData + dest.numRects;
2059 }
2060
2061 if (curNumRects == prevNumRects && curNumRects != 0) {
2062 pCurBox -= curNumRects;
2063 /*
2064 * The bands may only be coalesced if the bottom of the previous
2065 * matches the top scanline of the current.
2066 */
2067 if (pPrevBox->bottom() == pCurBox->top() - 1) {
2068 /*
2069 * Make sure the bands have boxes in the same places. This
2070 * assumes that boxes have been added in such a way that they
2071 * cover the most area possible. I.e. two boxes in a band must
2072 * have some horizontal space between them.
2073 */
2074 do {
2075 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
2076 // The bands don't line up so they can't be coalesced.
2077 return curStart;
2078 }
2079 ++pPrevBox;
2080 ++pCurBox;
2081 --prevNumRects;
2082 } while (prevNumRects != 0);
2083
2084 dest.numRects -= curNumRects;
2085 pCurBox -= curNumRects;
2086 pPrevBox -= curNumRects;
2087
2088 /*
2089 * The bands may be merged, so set the bottom y of each box
2090 * in the previous band to that of the corresponding box in
2091 * the current band.
2092 */
2093 do {
2094 pPrevBox->setBottom(pCurBox->bottom());
2095 dest.updateInnerRect(*pPrevBox);
2096 ++pPrevBox;
2097 ++pCurBox;
2098 curNumRects -= 1;
2099 } while (curNumRects != 0);
2100
2101 /*
2102 * If only one band was added to the region, we have to backup
2103 * curStart to the start of the previous band.
2104 *
2105 * If more than one band was added to the region, copy the
2106 * other bands down. The assumption here is that the other bands
2107 * came from the same region as the current one and no further
2108 * coalescing can be done on them since it's all been done
2109 * already... curStart is already in the right place.
2110 */
2111 if (pCurBox == pRegEnd) {
2112 curStart = prevStart;
2113 } else {
2114 do {
2115 *pPrevBox++ = *pCurBox++;
2116 dest.updateInnerRect(*pPrevBox);
2117 } while (pCurBox != pRegEnd);
2118 }
2119 }
2120 }
2121 return curStart;
2122}
2123
2124/*-
2125 *-----------------------------------------------------------------------
2126 * miRegionOp --
2127 * Apply an operation to two regions. Called by miUnion, miInverse,
2128 * miSubtract, miIntersect...
2129 *
2130 * Results:
2131 * None.
2132 *
2133 * Side Effects:
2134 * The new region is overwritten.
2135 *
2136 * Notes:
2137 * The idea behind this function is to view the two regions as sets.
2138 * Together they cover a rectangle of area that this function divides
2139 * into horizontal bands where points are covered only by one region
2140 * or by both. For the first case, the nonOverlapFunc is called with
2141 * each the band and the band's upper and lower extents. For the
2142 * second, the overlapFunc is called to process the entire band. It
2143 * is responsible for clipping the rectangles in the band, though
2144 * this function provides the boundaries.
2145 * At the end of each band, the new region is coalesced, if possible,
2146 * to reduce the number of rectangles in the region.
2147 *
2148 *-----------------------------------------------------------------------
2149 */
2150static void miRegionOp(register QRegionPrivate &dest,
2151 const QRegionPrivate *reg1, const QRegionPrivate *reg2,
2152 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
2153 NonOverlapFunc nonOverlap2Func)
2154{
2155 register const QRect *r1; // Pointer into first region
2156 register const QRect *r2; // Pointer into 2d region
2157 const QRect *r1End; // End of 1st region
2158 const QRect *r2End; // End of 2d region
2159 register int ybot; // Bottom of intersection
2160 register int ytop; // Top of intersection
2161 int prevBand; // Index of start of previous band in dest
2162 int curBand; // Index of start of current band in dest
2163 register const QRect *r1BandEnd; // End of current band in r1
2164 register const QRect *r2BandEnd; // End of current band in r2
2165 int top; // Top of non-overlapping band
2166 int bot; // Bottom of non-overlapping band
2167
2168 /*
2169 * Initialization:
2170 * set r1, r2, r1End and r2End appropriately, preserve the important
2171 * parts of the destination region until the end in case it's one of
2172 * the two source regions, then mark the "new" region empty, allocating
2173 * another array of rectangles for it to use.
2174 */
2175 if (reg1->numRects == 1)
2176 r1 = &reg1->extents;
2177 else
2178 r1 = reg1->rects.constData();
2179 if (reg2->numRects == 1)
2180 r2 = &reg2->extents;
2181 else
2182 r2 = reg2->rects.constData();
2183
2184 r1End = r1 + reg1->numRects;
2185 r2End = r2 + reg2->numRects;
2186
2187 dest.vectorize();
2188
2189 QVector<QRect> oldRects = dest.rects;
2190
2191 dest.numRects = 0;
2192
2193 /*
2194 * Allocate a reasonable number of rectangles for the new region. The idea
2195 * is to allocate enough so the individual functions don't need to
2196 * reallocate and copy the array, which is time consuming, yet we don't
2197 * have to worry about using too much memory. I hope to be able to
2198 * nuke the realloc() at the end of this function eventually.
2199 */
2200 dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
2201
2202 /*
2203 * Initialize ybot and ytop.
2204 * In the upcoming loop, ybot and ytop serve different functions depending
2205 * on whether the band being handled is an overlapping or non-overlapping
2206 * band.
2207 * In the case of a non-overlapping band (only one of the regions
2208 * has points in the band), ybot is the bottom of the most recent
2209 * intersection and thus clips the top of the rectangles in that band.
2210 * ytop is the top of the next intersection between the two regions and
2211 * serves to clip the bottom of the rectangles in the current band.
2212 * For an overlapping band (where the two regions intersect), ytop clips
2213 * the top of the rectangles of both regions and ybot clips the bottoms.
2214 */
2215 if (reg1->extents.top() < reg2->extents.top())
2216 ybot = reg1->extents.top() - 1;
2217 else
2218 ybot = reg2->extents.top() - 1;
2219
2220 /*
2221 * prevBand serves to mark the start of the previous band so rectangles
2222 * can be coalesced into larger rectangles. qv. miCoalesce, above.
2223 * In the beginning, there is no previous band, so prevBand == curBand
2224 * (curBand is set later on, of course, but the first band will always
2225 * start at index 0). prevBand and curBand must be indices because of
2226 * the possible expansion, and resultant moving, of the new region's
2227 * array of rectangles.
2228 */
2229 prevBand = 0;
2230
2231 do {
2232 curBand = dest.numRects;
2233
2234 /*
2235 * This algorithm proceeds one source-band (as opposed to a
2236 * destination band, which is determined by where the two regions
2237 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
2238 * rectangle after the last one in the current band for their
2239 * respective regions.
2240 */
2241 r1BandEnd = r1;
2242 while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
2243 ++r1BandEnd;
2244
2245 r2BandEnd = r2;
2246 while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
2247 ++r2BandEnd;
2248
2249 /*
2250 * First handle the band that doesn't intersect, if any.
2251 *
2252 * Note that attention is restricted to one band in the
2253 * non-intersecting region at once, so if a region has n
2254 * bands between the current position and the next place it overlaps
2255 * the other, this entire loop will be passed through n times.
2256 */
2257 if (r1->top() < r2->top()) {
2258 top = qMax(r1->top(), ybot + 1);
2259 bot = qMin(r1->bottom(), r2->top() - 1);
2260
2261 if (nonOverlap1Func != 0 && bot >= top)
2262 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
2263 ytop = r2->top();
2264 } else if (r2->top() < r1->top()) {
2265 top = qMax(r2->top(), ybot + 1);
2266 bot = qMin(r2->bottom(), r1->top() - 1);
2267
2268 if (nonOverlap2Func != 0 && bot >= top)
2269 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
2270 ytop = r1->top();
2271 } else {
2272 ytop = r1->top();
2273 }
2274
2275 /*
2276 * If any rectangles got added to the region, try and coalesce them
2277 * with rectangles from the previous band. Note we could just do
2278 * this test in miCoalesce, but some machines incur a not
2279 * inconsiderable cost for function calls, so...
2280 */
2281 if (dest.numRects != curBand)
2282 prevBand = miCoalesce(dest, prevBand, curBand);
2283
2284 /*
2285 * Now see if we've hit an intersecting band. The two bands only
2286 * intersect if ybot >= ytop
2287 */
2288 ybot = qMin(r1->bottom(), r2->bottom());
2289 curBand = dest.numRects;
2290 if (ybot >= ytop)
2291 (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
2292
2293 if (dest.numRects != curBand)
2294 prevBand = miCoalesce(dest, prevBand, curBand);
2295
2296 /*
2297 * If we've finished with a band (y2 == ybot) we skip forward
2298 * in the region to the next band.
2299 */
2300 if (r1->bottom() == ybot)
2301 r1 = r1BandEnd;
2302 if (r2->bottom() == ybot)
2303 r2 = r2BandEnd;
2304 } while (r1 != r1End && r2 != r2End);
2305
2306 /*
2307 * Deal with whichever region still has rectangles left.
2308 */
2309 curBand = dest.numRects;
2310 if (r1 != r1End) {
2311 if (nonOverlap1Func != 0) {
2312 do {
2313 r1BandEnd = r1;
2314 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
2315 ++r1BandEnd;
2316 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
2317 r1 = r1BandEnd;
2318 } while (r1 != r1End);
2319 }
2320 } else if ((r2 != r2End) && (nonOverlap2Func != 0)) {
2321 do {
2322 r2BandEnd = r2;
2323 while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
2324 ++r2BandEnd;
2325 (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
2326 r2 = r2BandEnd;
2327 } while (r2 != r2End);
2328 }
2329
2330 if (dest.numRects != curBand)
2331 (void)miCoalesce(dest, prevBand, curBand);
2332
2333 /*
2334 * A bit of cleanup. To keep regions from growing without bound,
2335 * we shrink the array of rectangles to match the new number of
2336 * rectangles in the region.
2337 *
2338 * Only do this stuff if the number of rectangles allocated is more than
2339 * twice the number of rectangles in the region (a simple optimization).
2340 */
2341 if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
2342 dest.rects.resize(dest.numRects);
2343}
2344
2345/*======================================================================
2346 * Region Union
2347 *====================================================================*/
2348
2349/*-
2350 *-----------------------------------------------------------------------
2351 * miUnionNonO --
2352 * Handle a non-overlapping band for the union operation. Just
2353 * Adds the rectangles into the region. Doesn't have to check for
2354 * subsumption or anything.
2355 *
2356 * Results:
2357 * None.
2358 *
2359 * Side Effects:
2360 * dest.numRects is incremented and the final rectangles overwritten
2361 * with the rectangles we're passed.
2362 *
2363 *-----------------------------------------------------------------------
2364 */
2365
2366static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
2367 register int y1, register int y2)
2368{
2369 register QRect *pNextRect;
2370
2371 pNextRect = dest.rects.data() + dest.numRects;
2372
2373 Q_ASSERT(y1 <= y2);
2374
2375 while (r != rEnd) {
2376 Q_ASSERT(r->left() <= r->right());
2377 MEMCHECK(dest, pNextRect, dest.rects)
2378 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2379 dest.numRects++;
2380 ++pNextRect;
2381 ++r;
2382 }
2383}
2384
2385
2386/*-
2387 *-----------------------------------------------------------------------
2388 * miUnionO --
2389 * Handle an overlapping band for the union operation. Picks the
2390 * left-most rectangle each time and merges it into the region.
2391 *
2392 * Results:
2393 * None.
2394 *
2395 * Side Effects:
2396 * Rectangles are overwritten in dest.rects and dest.numRects will
2397 * be changed.
2398 *
2399 *-----------------------------------------------------------------------
2400 */
2401
2402static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
2403 register const QRect *r2, const QRect *r2End, register int y1, register int y2)
2404{
2405 register QRect *pNextRect;
2406
2407 pNextRect = dest.rects.data() + dest.numRects;
2408
2409#define MERGERECT(r) \
2410 if ((dest.numRects != 0) && \
2411 (pNextRect[-1].top() == y1) && \
2412 (pNextRect[-1].bottom() == y2) && \
2413 (pNextRect[-1].right() >= r->left()-1)) { \
2414 if (pNextRect[-1].right() < r->right()) { \
2415 pNextRect[-1].setRight(r->right()); \
2416 dest.updateInnerRect(pNextRect[-1]); \
2417 Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
2418 } \
2419 } else { \
2420 MEMCHECK(dest, pNextRect, dest.rects) \
2421 pNextRect->setCoords(r->left(), y1, r->right(), y2); \
2422 dest.updateInnerRect(*pNextRect); \
2423 dest.numRects++; \
2424 pNextRect++; \
2425 } \
2426 r++;
2427
2428 Q_ASSERT(y1 <= y2);
2429 while (r1 != r1End && r2 != r2End) {
2430 if (r1->left() < r2->left()) {
2431 MERGERECT(r1)
2432 } else {
2433 MERGERECT(r2)
2434 }
2435 }
2436
2437 if (r1 != r1End) {
2438 do {
2439 MERGERECT(r1)
2440 } while (r1 != r1End);
2441 } else {
2442 while (r2 != r2End) {
2443 MERGERECT(r2)
2444 }
2445 }
2446}
2447
2448static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
2449{
2450 Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2));
2451 Q_ASSERT(!reg1->contains(*reg2));
2452 Q_ASSERT(!reg2->contains(*reg1));
2453 Q_ASSERT(!EqualRegion(reg1, reg2));
2454 Q_ASSERT(!reg1->canAppend(reg2));
2455 Q_ASSERT(!reg2->canAppend(reg1));
2456
2457 if (reg1->innerArea > reg2->innerArea) {
2458 dest.innerArea = reg1->innerArea;
2459 dest.innerRect = reg1->innerRect;
2460 } else {
2461 dest.innerArea = reg2->innerArea;
2462 dest.innerRect = reg2->innerRect;
2463 }
2464 miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
2465
2466 dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
2467 qMin(reg1->extents.top(), reg2->extents.top()),
2468 qMax(reg1->extents.right(), reg2->extents.right()),
2469 qMax(reg1->extents.bottom(), reg2->extents.bottom()));
2470}
2471
2472/*======================================================================
2473 * Region Subtraction
2474 *====================================================================*/
2475
2476/*-
2477 *-----------------------------------------------------------------------
2478 * miSubtractNonO --
2479 * Deal with non-overlapping band for subtraction. Any parts from
2480 * region 2 we discard. Anything from region 1 we add to the region.
2481 *
2482 * Results:
2483 * None.
2484 *
2485 * Side Effects:
2486 * dest may be affected.
2487 *
2488 *-----------------------------------------------------------------------
2489 */
2490
2491static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r,
2492 const QRect *rEnd, register int y1, register int y2)
2493{
2494 register QRect *pNextRect;
2495
2496 pNextRect = dest.rects.data() + dest.numRects;
2497
2498 Q_ASSERT(y1<=y2);
2499
2500 while (r != rEnd) {
2501 Q_ASSERT(r->left() <= r->right());
2502 MEMCHECK(dest, pNextRect, dest.rects)
2503 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2504 ++dest.numRects;
2505 ++pNextRect;
2506 ++r;
2507 }
2508}
2509
2510/*-
2511 *-----------------------------------------------------------------------
2512 * miSubtractO --
2513 * Overlapping band subtraction. x1 is the left-most point not yet
2514 * checked.
2515 *
2516 * Results:
2517 * None.
2518 *
2519 * Side Effects:
2520 * dest may have rectangles added to it.
2521 *
2522 *-----------------------------------------------------------------------
2523 */
2524
2525static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
2526 register const QRect *r2, const QRect *r2End, register int y1, register int y2)
2527{
2528 register QRect *pNextRect;
2529 register int x1;
2530
2531 x1 = r1->left();
2532
2533 Q_ASSERT(y1 <= y2);
2534 pNextRect = dest.rects.data() + dest.numRects;
2535
2536 while (r1 != r1End && r2 != r2End) {
2537 if (r2->right() < x1) {
2538 /*
2539 * Subtrahend missed the boat: go to next subtrahend.
2540 */
2541 ++r2;
2542 } else if (r2->left() <= x1) {
2543 /*
2544 * Subtrahend precedes minuend: nuke left edge of minuend.
2545 */
2546 x1 = r2->right() + 1;
2547 if (x1 > r1->right()) {
2548 /*
2549 * Minuend completely covered: advance to next minuend and
2550 * reset left fence to edge of new minuend.
2551 */
2552 ++r1;
2553 if (r1 != r1End)
2554 x1 = r1->left();
2555 } else {
2556 // Subtrahend now used up since it doesn't extend beyond minuend
2557 ++r2;
2558 }
2559 } else if (r2->left() <= r1->right()) {
2560 /*
2561 * Left part of subtrahend covers part of minuend: add uncovered
2562 * part of minuend to region and skip to next subtrahend.
2563 */
2564 Q_ASSERT(x1 < r2->left());
2565 MEMCHECK(dest, pNextRect, dest.rects)
2566 pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
2567 ++dest.numRects;
2568 ++pNextRect;
2569
2570 x1 = r2->right() + 1;
2571 if (x1 > r1->right()) {
2572 /*
2573 * Minuend used up: advance to new...
2574 */
2575 ++r1;
2576 if (r1 != r1End)
2577 x1 = r1->left();
2578 } else {
2579 // Subtrahend used up
2580 ++r2;
2581 }
2582 } else {
2583 /*
2584 * Minuend used up: add any remaining piece before advancing.
2585 */
2586 if (r1->right() >= x1) {
2587 MEMCHECK(dest, pNextRect, dest.rects)
2588 pNextRect->setCoords(x1, y1, r1->right(), y2);
2589 ++dest.numRects;
2590 ++pNextRect;
2591 }
2592 ++r1;
2593 if (r1 != r1End)
2594 x1 = r1->left();
2595 }
2596 }
2597
2598 /*
2599 * Add remaining minuend rectangles to region.
2600 */
2601 while (r1 != r1End) {
2602 Q_ASSERT(x1 <= r1->right());
2603 MEMCHECK(dest, pNextRect, dest.rects)
2604 pNextRect->setCoords(x1, y1, r1->right(), y2);
2605 ++dest.numRects;
2606 ++pNextRect;
2607
2608 ++r1;
2609 if (r1 != r1End)
2610 x1 = r1->left();
2611 }
2612}
2613
2614/*-
2615 *-----------------------------------------------------------------------
2616 * miSubtract --
2617 * Subtract regS from regM and leave the result in regD.
2618 * S stands for subtrahend, M for minuend and D for difference.
2619 *
2620 * Side Effects:
2621 * regD is overwritten.
2622 *
2623 *-----------------------------------------------------------------------
2624 */
2625
2626static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
2627 register QRegionPrivate &dest)
2628{
2629 Q_ASSERT(!isEmptyHelper(regM));
2630 Q_ASSERT(!isEmptyHelper(regS));
2631 Q_ASSERT(EXTENTCHECK(&regM->extents, &regS->extents));
2632 Q_ASSERT(!regS->contains(*regM));
2633 Q_ASSERT(!EqualRegion(regM, regS));
2634
2635 miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0);
2636
2637 /*
2638 * Can't alter dest's extents before we call miRegionOp because
2639 * it might be one of the source regions and miRegionOp depends
2640 * on the extents of those regions being the unaltered. Besides, this
2641 * way there's no checking against rectangles that will be nuked
2642 * due to coalescing, so we have to examine fewer rectangles.
2643 */
2644 miSetExtents(dest);
2645}
2646
2647static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
2648{
2649 Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb));
2650 Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents));
2651 Q_ASSERT(!EqualRegion(sra, srb));
2652
2653 QRegionPrivate tra, trb;
2654
2655 if (!srb->contains(*sra))
2656 SubtractRegion(sra, srb, tra);
2657 if (!sra->contains(*srb))
2658 SubtractRegion(srb, sra, trb);
2659
2660 Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb));
2661 Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra));
2662
2663 if (isEmptyHelper(&tra)) {
2664 dest = trb;
2665 } else if (isEmptyHelper(&trb)) {
2666 dest = tra;
2667 } else if (tra.canAppend(&trb)) {
2668 dest = tra;
2669 dest.append(&trb);
2670 } else if (trb.canAppend(&tra)) {
2671 dest = trb;
2672 dest.append(&tra);
2673 } else {
2674 UnionRegion(&tra, &trb, dest);
2675 }
2676}
2677
2678/*
2679 * Check to see if two regions are equal
2680 */
2681static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
2682{
2683 if (r1->numRects != r2->numRects) {
2684 return false;
2685 } else if (r1->numRects == 0) {
2686 return true;
2687 } else if (r1->extents != r2->extents) {
2688 return false;
2689 } else if (r1->numRects == 1 && r2->numRects == 1) {
2690 return true; // equality tested in previous if-statement
2691 } else {
2692 const QRect *rr1 = (r1->numRects == 1) ? &r1->extents : r1->rects.constData();
2693 const QRect *rr2 = (r2->numRects == 1) ? &r2->extents : r2->rects.constData();
2694 for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
2695 if (*rr1 != *rr2)
2696 return false;
2697 }
2698 }
2699
2700 return true;
2701}
2702
2703static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
2704{
2705 int i;
2706
2707 if (isEmptyHelper(pRegion))
2708 return false;
2709 if (!pRegion->extents.contains(x, y))
2710 return false;
2711 if (pRegion->numRects == 1)
2712 return pRegion->extents.contains(x, y);
2713 if (pRegion->innerRect.contains(x, y))
2714 return true;
2715 for (i = 0; i < pRegion->numRects; ++i) {
2716 if (pRegion->rects[i].contains(x, y))
2717 return true;
2718 }
2719 return false;
2720}
2721
2722static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
2723{
2724 register const QRect *pbox;
2725 register const QRect *pboxEnd;
2726 QRect rect(rx, ry, rwidth, rheight);
2727 register QRect *prect = &rect;
2728 int partIn, partOut;
2729
2730 if (!region || region->numRects == 0 || !EXTENTCHECK(&region->extents, prect))
2731 return RectangleOut;
2732
2733 partOut = false;
2734 partIn = false;
2735
2736 /* can stop when both partOut and partIn are true, or we reach prect->y2 */
2737 pbox = (region->numRects == 1) ? &region->extents : region->rects.constData();
2738 pboxEnd = pbox + region->numRects;
2739 for (; pbox < pboxEnd; ++pbox) {
2740 if (pbox->bottom() < ry)
2741 continue;
2742
2743 if (pbox->top() > ry) {
2744 partOut = true;
2745 if (partIn || pbox->top() > prect->bottom())
2746 break;
2747 ry = pbox->top();
2748 }
2749
2750 if (pbox->right() < rx)
2751 continue; /* not far enough over yet */
2752
2753 if (pbox->left() > rx) {
2754 partOut = true; /* missed part of rectangle to left */
2755 if (partIn)
2756 break;
2757 }
2758
2759 if (pbox->left() <= prect->right()) {
2760 partIn = true; /* definitely overlap */
2761 if (partOut)
2762 break;
2763 }
2764
2765 if (pbox->right() >= prect->right()) {
2766 ry = pbox->bottom() + 1; /* finished with this band */
2767 if (ry > prect->bottom())
2768 break;
2769 rx = prect->left(); /* reset x out to left again */
2770 } else {
2771 /*
2772 * Because boxes in a band are maximal width, if the first box
2773 * to overlap the rectangle doesn't completely cover it in that
2774 * band, the rectangle must be partially out, since some of it
2775 * will be uncovered in that band. partIn will have been set true
2776 * by now...
2777 */
2778 break;
2779 }
2780 }
2781 return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
2782}
2783// END OF Region.c extract
2784// START OF poly.h extract
2785/* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
2786/************************************************************************
2787
2788Copyright (c) 1987 X Consortium
2789
2790Permission is hereby granted, free of charge, to any person obtaining a copy
2791of this software and associated documentation files (the "Software"), to deal
2792in the Software without restriction, including without limitation the rights
2793to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2794copies of the Software, and to permit persons to whom the Software is
2795furnished to do so, subject to the following conditions:
2796
2797The above copyright notice and this permission notice shall be included in
2798all copies or substantial portions of the Software.
2799
2800THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2801IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2802FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2803X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2804AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2805CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2806
2807Except as contained in this notice, the name of the X Consortium shall not be
2808used in advertising or otherwise to promote the sale, use or other dealings
2809in this Software without prior written authorization from the X Consortium.
2810
2811
2812Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2813
2814 All Rights Reserved
2815
2816Permission to use, copy, modify, and distribute this software and its
2817documentation for any purpose and without fee is hereby granted,
2818provided that the above copyright notice appear in all copies and that
2819both that copyright notice and this permission notice appear in
2820supporting documentation, and that the name of Digital not be
2821used in advertising or publicity pertaining to distribution of the
2822software without specific, written prior permission.
2823
2824DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2825ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2826DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2827ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2828WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2829ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2830SOFTWARE.
2831
2832************************************************************************/
2833
2834/*
2835 * This file contains a few macros to help track
2836 * the edge of a filled object. The object is assumed
2837 * to be filled in scanline order, and thus the
2838 * algorithm used is an extension of Bresenham's line
2839 * drawing algorithm which assumes that y is always the
2840 * major axis.
2841 * Since these pieces of code are the same for any filled shape,
2842 * it is more convenient to gather the library in one
2843 * place, but since these pieces of code are also in
2844 * the inner loops of output primitives, procedure call
2845 * overhead is out of the question.
2846 * See the author for a derivation if needed.
2847 */
2848
2849
2850/*
2851 * In scan converting polygons, we want to choose those pixels
2852 * which are inside the polygon. Thus, we add .5 to the starting
2853 * x coordinate for both left and right edges. Now we choose the
2854 * first pixel which is inside the pgon for the left edge and the
2855 * first pixel which is outside the pgon for the right edge.
2856 * Draw the left pixel, but not the right.
2857 *
2858 * How to add .5 to the starting x coordinate:
2859 * If the edge is moving to the right, then subtract dy from the
2860 * error term from the general form of the algorithm.
2861 * If the edge is moving to the left, then add dy to the error term.
2862 *
2863 * The reason for the difference between edges moving to the left
2864 * and edges moving to the right is simple: If an edge is moving
2865 * to the right, then we want the algorithm to flip immediately.
2866 * If it is moving to the left, then we don't want it to flip until
2867 * we traverse an entire pixel.
2868 */
2869#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
2870 int dx; /* local storage */ \
2871\
2872 /* \
2873 * if the edge is horizontal, then it is ignored \
2874 * and assumed not to be processed. Otherwise, do this stuff. \
2875 */ \
2876 if ((dy) != 0) { \
2877 xStart = (x1); \
2878 dx = (x2) - xStart; \
2879 if (dx < 0) { \
2880 m = dx / (dy); \
2881 m1 = m - 1; \
2882 incr1 = -2 * dx + 2 * (dy) * m1; \
2883 incr2 = -2 * dx + 2 * (dy) * m; \
2884 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
2885 } else { \
2886 m = dx / (dy); \
2887 m1 = m + 1; \
2888 incr1 = 2 * dx - 2 * (dy) * m1; \
2889 incr2 = 2 * dx - 2 * (dy) * m; \
2890 d = -2 * m * (dy) + 2 * dx; \
2891 } \
2892 } \
2893}
2894
2895#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
2896 if (m1 > 0) { \
2897 if (d > 0) { \
2898 minval += m1; \
2899 d += incr1; \
2900 } \
2901 else { \
2902 minval += m; \
2903 d += incr2; \
2904 } \
2905 } else {\
2906 if (d >= 0) { \
2907 minval += m1; \
2908 d += incr1; \
2909 } \
2910 else { \
2911 minval += m; \
2912 d += incr2; \
2913 } \
2914 } \
2915}
2916
2917
2918/*
2919 * This structure contains all of the information needed
2920 * to run the bresenham algorithm.
2921 * The variables may be hardcoded into the declarations
2922 * instead of using this structure to make use of
2923 * register declarations.
2924 */
2925typedef struct {
2926 int minor_axis; /* minor axis */
2927 int d; /* decision variable */
2928 int m, m1; /* slope and slope+1 */
2929 int incr1, incr2; /* error increments */
2930} BRESINFO;
2931
2932
2933#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
2934 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
2935 bres.m, bres.m1, bres.incr1, bres.incr2)
2936
2937#define BRESINCRPGONSTRUCT(bres) \
2938 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
2939
2940
2941
2942/*
2943 * These are the data structures needed to scan
2944 * convert regions. Two different scan conversion
2945 * methods are available -- the even-odd method, and
2946 * the winding number method.
2947 * The even-odd rule states that a point is inside
2948 * the polygon if a ray drawn from that point in any
2949 * direction will pass through an odd number of
2950 * path segments.
2951 * By the winding number rule, a point is decided
2952 * to be inside the polygon if a ray drawn from that
2953 * point in any direction passes through a different
2954 * number of clockwise and counter-clockwise path
2955 * segments.
2956 *
2957 * These data structures are adapted somewhat from
2958 * the algorithm in (Foley/Van Dam) for scan converting
2959 * polygons.
2960 * The basic algorithm is to start at the top (smallest y)
2961 * of the polygon, stepping down to the bottom of
2962 * the polygon by incrementing the y coordinate. We
2963 * keep a list of edges which the current scanline crosses,
2964 * sorted by x. This list is called the Active Edge Table (AET)
2965 * As we change the y-coordinate, we update each entry in
2966 * in the active edge table to reflect the edges new xcoord.
2967 * This list must be sorted at each scanline in case
2968 * two edges intersect.
2969 * We also keep a data structure known as the Edge Table (ET),
2970 * which keeps track of all the edges which the current
2971 * scanline has not yet reached. The ET is basically a
2972 * list of ScanLineList structures containing a list of
2973 * edges which are entered at a given scanline. There is one
2974 * ScanLineList per scanline at which an edge is entered.
2975 * When we enter a new edge, we move it from the ET to the AET.
2976 *
2977 * From the AET, we can implement the even-odd rule as in
2978 * (Foley/Van Dam).
2979 * The winding number rule is a little trickier. We also
2980 * keep the EdgeTableEntries in the AET linked by the
2981 * nextWETE (winding EdgeTableEntry) link. This allows
2982 * the edges to be linked just as before for updating
2983 * purposes, but only uses the edges linked by the nextWETE
2984 * link as edges representing spans of the polygon to
2985 * drawn (as with the even-odd rule).
2986 */
2987
2988/*
2989 * for the winding number rule
2990 */
2991#define CLOCKWISE 1
2992#define COUNTERCLOCKWISE -1
2993
2994typedef struct _EdgeTableEntry {
2995 int ymax; /* ycoord at which we exit this edge. */
2996 BRESINFO bres; /* Bresenham info to run the edge */
2997 struct _EdgeTableEntry *next; /* next in the list */
2998 struct _EdgeTableEntry *back; /* for insertion sort */
2999 struct _EdgeTableEntry *nextWETE; /* for winding num rule */
3000 int ClockWise; /* flag for winding number rule */
3001} EdgeTableEntry;
3002
3003
3004typedef struct _ScanLineList{
3005 int scanline; /* the scanline represented */
3006 EdgeTableEntry *edgelist; /* header node */
3007 struct _ScanLineList *next; /* next in the list */
3008} ScanLineList;
3009
3010
3011typedef struct {
3012 int ymax; /* ymax for the polygon */
3013 int ymin; /* ymin for the polygon */
3014 ScanLineList scanlines; /* header node */
3015} EdgeTable;
3016
3017
3018/*
3019 * Here is a struct to help with storage allocation
3020 * so we can allocate a big chunk at a time, and then take
3021 * pieces from this heap when we need to.
3022 */
3023#define SLLSPERBLOCK 25
3024
3025typedef struct _ScanLineListBlock {
3026 ScanLineList SLLs[SLLSPERBLOCK];
3027 struct _ScanLineListBlock *next;
3028} ScanLineListBlock;
3029
3030
3031
3032/*
3033 *
3034 * a few macros for the inner loops of the fill code where
3035 * performance considerations don't allow a procedure call.
3036 *
3037 * Evaluate the given edge at the given scanline.
3038 * If the edge has expired, then we leave it and fix up
3039 * the active edge table; otherwise, we increment the
3040 * x value to be ready for the next scanline.
3041 * The winding number rule is in effect, so we must notify
3042 * the caller when the edge has been removed so he
3043 * can reorder the Winding Active Edge Table.
3044 */
3045#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
3046 if (pAET->ymax == y) { /* leaving this edge */ \
3047 pPrevAET->next = pAET->next; \
3048 pAET = pPrevAET->next; \
3049 fixWAET = 1; \
3050 if (pAET) \
3051 pAET->back = pPrevAET; \
3052 } \
3053 else { \
3054 BRESINCRPGONSTRUCT(pAET->bres) \
3055 pPrevAET = pAET; \
3056 pAET = pAET->next; \
3057 } \
3058}
3059
3060
3061/*
3062 * Evaluate the given edge at the given scanline.
3063 * If the edge has expired, then we leave it and fix up
3064 * the active edge table; otherwise, we increment the
3065 * x value to be ready for the next scanline.
3066 * The even-odd rule is in effect.
3067 */
3068#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
3069 if (pAET->ymax == y) { /* leaving this edge */ \
3070 pPrevAET->next = pAET->next; \
3071 pAET = pPrevAET->next; \
3072 if (pAET) \
3073 pAET->back = pPrevAET; \
3074 } \
3075 else { \
3076 BRESINCRPGONSTRUCT(pAET->bres) \
3077 pPrevAET = pAET; \
3078 pAET = pAET->next; \
3079 } \
3080}
3081// END OF poly.h extract
3082// START OF PolyReg.c extract
3083/* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
3084/************************************************************************
3085
3086Copyright (c) 1987 X Consortium
3087
3088Permission is hereby granted, free of charge, to any person obtaining a copy
3089of this software and associated documentation files (the "Software"), to deal
3090in the Software without restriction, including without limitation the rights
3091to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3092copies of the Software, and to permit persons to whom the Software is
3093furnished to do so, subject to the following conditions:
3094
3095The above copyright notice and this permission notice shall be included in
3096all copies or substantial portions of the Software.
3097
3098THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3099IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3100FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3101X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
3102AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3103CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3104
3105Except as contained in this notice, the name of the X Consortium shall not be
3106used in advertising or otherwise to promote the sale, use or other dealings
3107in this Software without prior written authorization from the X Consortium.
3108
3109
3110Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3111
3112 All Rights Reserved
3113
3114Permission to use, copy, modify, and distribute this software and its
3115documentation for any purpose and without fee is hereby granted,
3116provided that the above copyright notice appear in all copies and that
3117both that copyright notice and this permission notice appear in
3118supporting documentation, and that the name of Digital not be
3119used in advertising or publicity pertaining to distribution of the
3120software without specific, written prior permission.
3121
3122DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3123ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3124DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
3125ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
3126WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
3127ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3128SOFTWARE.
3129
3130************************************************************************/
3131/* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
3132
3133#define LARGE_COORDINATE INT_MAX
3134#define SMALL_COORDINATE INT_MIN
3135
3136/*
3137 * InsertEdgeInET
3138 *
3139 * Insert the given edge into the edge table.
3140 * First we must find the correct bucket in the
3141 * Edge table, then find the right slot in the
3142 * bucket. Finally, we can insert it.
3143 *
3144 */
3145static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
3146 ScanLineListBlock **SLLBlock, int *iSLLBlock)
3147{
3148 register EdgeTableEntry *start, *prev;
3149 register ScanLineList *pSLL, *pPrevSLL;
3150 ScanLineListBlock *tmpSLLBlock;
3151
3152 /*
3153 * find the right bucket to put the edge into
3154 */
3155 pPrevSLL = &ET->scanlines;
3156 pSLL = pPrevSLL->next;
3157 while (pSLL && (pSLL->scanline < scanline)) {
3158 pPrevSLL = pSLL;
3159 pSLL = pSLL->next;
3160 }
3161
3162 /*
3163 * reassign pSLL (pointer to ScanLineList) if necessary
3164 */
3165 if ((!pSLL) || (pSLL->scanline > scanline)) {
3166 if (*iSLLBlock > SLLSPERBLOCK-1)
3167 {
3168 tmpSLLBlock =
3169 (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
3170 Q_CHECK_PTR(tmpSLLBlock);
3171 (*SLLBlock)->next = tmpSLLBlock;
3172 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
3173 *SLLBlock = tmpSLLBlock;
3174 *iSLLBlock = 0;
3175 }
3176 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3177
3178 pSLL->next = pPrevSLL->next;
3179 pSLL->edgelist = (EdgeTableEntry *)NULL;
3180 pPrevSLL->next = pSLL;
3181 }
3182 pSLL->scanline = scanline;
3183
3184 /*
3185 * now insert the edge in the right bucket
3186 */
3187 prev = 0;
3188 start = pSLL->edgelist;
3189 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3190 prev = start;
3191 start = start->next;
3192 }
3193 ETE->next = start;
3194
3195 if (prev)
3196 prev->next = ETE;
3197 else
3198 pSLL->edgelist = ETE;
3199}
3200
3201/*
3202 * CreateEdgeTable
3203 *
3204 * This routine creates the edge table for
3205 * scan converting polygons.
3206 * The Edge Table (ET) looks like:
3207 *
3208 * EdgeTable
3209 * --------
3210 * | ymax | ScanLineLists
3211 * |scanline|-->------------>-------------->...
3212 * -------- |scanline| |scanline|
3213 * |edgelist| |edgelist|
3214 * --------- ---------
3215 * | |
3216 * | |
3217 * V V
3218 * list of ETEs list of ETEs
3219 *
3220 * where ETE is an EdgeTableEntry data structure,
3221 * and there is one ScanLineList per scanline at
3222 * which an edge is initially entered.
3223 *
3224 */
3225
3226static void CreateETandAET(register int count, register const QPoint *pts,
3227 EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
3228 ScanLineListBlock *pSLLBlock)
3229{
3230 register const QPoint *top,
3231 *bottom,
3232 *PrevPt,
3233 *CurrPt;
3234 int iSLLBlock = 0;
3235 int dy;
3236
3237 if (count < 2)
3238 return;
3239
3240 /*
3241 * initialize the Active Edge Table
3242 */
3243 AET->next = 0;
3244 AET->back = 0;
3245 AET->nextWETE = 0;
3246 AET->bres.minor_axis = SMALL_COORDINATE;
3247
3248 /*
3249 * initialize the Edge Table.
3250 */
3251 ET->scanlines.next = 0;
3252 ET->ymax = SMALL_COORDINATE;
3253 ET->ymin = LARGE_COORDINATE;
3254 pSLLBlock->next = 0;
3255
3256 PrevPt = &pts[count - 1];
3257
3258 /*
3259 * for each vertex in the array of points.
3260 * In this loop we are dealing with two vertices at
3261 * a time -- these make up one edge of the polygon.
3262 */
3263 while (count--) {
3264 CurrPt = pts++;
3265
3266 /*
3267 * find out which point is above and which is below.
3268 */
3269 if (PrevPt->y() > CurrPt->y()) {
3270 bottom = PrevPt;
3271 top = CurrPt;
3272 pETEs->ClockWise = 0;
3273 } else {
3274 bottom = CurrPt;
3275 top = PrevPt;
3276 pETEs->ClockWise = 1;
3277 }
3278
3279 /*
3280 * don't add horizontal edges to the Edge table.
3281 */
3282 if (bottom->y() != top->y()) {
3283 pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */
3284
3285 /*
3286 * initialize integer edge algorithm
3287 */
3288 dy = bottom->y() - top->y();
3289 BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
3290
3291 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3292
3293 if (PrevPt->y() > ET->ymax)
3294 ET->ymax = PrevPt->y();
3295 if (PrevPt->y() < ET->ymin)
3296 ET->ymin = PrevPt->y();
3297 ++pETEs;
3298 }
3299
3300 PrevPt = CurrPt;
3301 }
3302}
3303
3304/*
3305 * loadAET
3306 *
3307 * This routine moves EdgeTableEntries from the
3308 * EdgeTable into the Active Edge Table,
3309 * leaving them sorted by smaller x coordinate.
3310 *
3311 */
3312
3313static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
3314{
3315 register EdgeTableEntry *pPrevAET;
3316 register EdgeTableEntry *tmp;
3317
3318 pPrevAET = AET;
3319 AET = AET->next;
3320 while (ETEs) {
3321 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3322 pPrevAET = AET;
3323 AET = AET->next;
3324 }
3325 tmp = ETEs->next;
3326 ETEs->next = AET;
3327 if (AET)
3328 AET->back = ETEs;
3329 ETEs->back = pPrevAET;
3330 pPrevAET->next = ETEs;
3331 pPrevAET = ETEs;
3332
3333 ETEs = tmp;
3334 }
3335}
3336
3337/*
3338 * computeWAET
3339 *
3340 * This routine links the AET by the
3341 * nextWETE (winding EdgeTableEntry) link for
3342 * use by the winding number rule. The final
3343 * Active Edge Table (AET) might look something
3344 * like:
3345 *
3346 * AET
3347 * ---------- --------- ---------
3348 * |ymax | |ymax | |ymax |
3349 * | ... | |... | |... |
3350 * |next |->|next |->|next |->...
3351 * |nextWETE| |nextWETE| |nextWETE|
3352 * --------- --------- ^--------
3353 * | | |
3354 * V-------------------> V---> ...
3355 *
3356 */
3357static void computeWAET(register EdgeTableEntry *AET)
3358{
3359 register EdgeTableEntry *pWETE;
3360 register int inside = 1;
3361 register int isInside = 0;
3362
3363 AET->nextWETE = 0;
3364 pWETE = AET;
3365 AET = AET->next;
3366 while (AET) {
3367 if (AET->ClockWise)
3368 ++isInside;
3369 else
3370 --isInside;
3371
3372 if ((!inside && !isInside) || (inside && isInside)) {
3373 pWETE->nextWETE = AET;
3374 pWETE = AET;
3375 inside = !inside;
3376 }
3377 AET = AET->next;
3378 }
3379 pWETE->nextWETE = 0;
3380}
3381
3382/*
3383 * InsertionSort
3384 *
3385 * Just a simple insertion sort using
3386 * pointers and back pointers to sort the Active
3387 * Edge Table.
3388 *
3389 */
3390
3391static int InsertionSort(register EdgeTableEntry *AET)
3392{
3393 register EdgeTableEntry *pETEchase;
3394 register EdgeTableEntry *pETEinsert;
3395 register EdgeTableEntry *pETEchaseBackTMP;
3396 register int changed = 0;
3397
3398 AET = AET->next;
3399 while (AET) {
3400 pETEinsert = AET;
3401 pETEchase = AET;
3402 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3403 pETEchase = pETEchase->back;
3404
3405 AET = AET->next;
3406 if (pETEchase != pETEinsert) {
3407 pETEchaseBackTMP = pETEchase->back;
3408 pETEinsert->back->next = AET;
3409 if (AET)
3410 AET->back = pETEinsert->back;
3411 pETEinsert->next = pETEchase;
3412 pETEchase->back->next = pETEinsert;
3413 pETEchase->back = pETEinsert;
3414 pETEinsert->back = pETEchaseBackTMP;
3415 changed = 1;
3416 }
3417 }
3418 return changed;
3419}
3420
3421/*
3422 * Clean up our act.
3423 */
3424static void FreeStorage(register ScanLineListBlock *pSLLBlock)
3425{
3426 register ScanLineListBlock *tmpSLLBlock;
3427
3428 while (pSLLBlock) {
3429 tmpSLLBlock = pSLLBlock->next;
3430 free(pSLLBlock);
3431 pSLLBlock = tmpSLLBlock;
3432 }
3433}
3434
3435struct QRegionSpan {
3436 QRegionSpan() {}
3437 QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {}
3438
3439 int x1;
3440 int x2;
3441 int width() const { return x2 - x1; }
3442};
3443
3444Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3445
3446static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend)
3447{
3448 QRect *regRects = reg->rects.data() + *lastRow;
3449 bool canExtend = reg->rects.size() - *lastRow == numSpans
3450 && !(*needsExtend && *extendTo + 1 != y)
3451 && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
3452
3453 for (int i = 0; i < numSpans && canExtend; ++i) {
3454 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3455 canExtend = false;
3456 }
3457
3458 if (canExtend) {
3459 *extendTo = y;
3460 *needsExtend = true;
3461 } else {
3462 if (*needsExtend) {
3463 for (int i = 0; i < reg->rects.size() - *lastRow; ++i)
3464 regRects[i].setBottom(*extendTo);
3465 }
3466
3467 *lastRow = reg->rects.size();
3468 reg->rects.reserve(*lastRow + numSpans);
3469 for (int i = 0; i < numSpans; ++i)
3470 reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
3471
3472 if (spans[0].x1 < reg->extents.left())
3473 reg->extents.setLeft(spans[0].x1);
3474
3475 if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3476 reg->extents.setRight(spans[numSpans-1].x2 - 1);
3477
3478 *needsExtend = false;
3479 }
3480}
3481
3482/*
3483 * Create an array of rectangles from a list of points.
3484 * If indeed these things (POINTS, RECTS) are the same,
3485 * then this proc is still needed, because it allocates
3486 * storage for the array, which was allocated on the
3487 * stack by the calling procedure.
3488 *
3489 */
3490static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
3491 POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
3492{
3493 int lastRow = 0;
3494 int extendTo = 0;
3495 bool needsExtend = false;
3496 QVarLengthArray<QRegionSpan> row;
3497 int rowSize = 0;
3498
3499 reg->extents.setLeft(INT_MAX);
3500 reg->extents.setRight(INT_MIN);
3501 reg->innerArea = -1;
3502
3503 POINTBLOCK *CurPtBlock = FirstPtBlock;
3504 for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3505 /* the loop uses 2 points per iteration */
3506 int i = NUMPTSTOBUFFER >> 1;
3507 if (!numFullPtBlocks)
3508 i = iCurPtBlock >> 1;
3509 if(i) {
3510 row.resize(qMax(row.size(), rowSize + i));
3511 for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) {
3512 const int width = pts[1].x() - pts[0].x();
3513 if (width) {
3514 if (rowSize && row[rowSize-1].x2 == pts[0].x())
3515 row[rowSize-1].x2 = pts[1].x();
3516 else
3517 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3518 }
3519
3520 if (rowSize) {
3521 QPoint *next = i ? &pts[2] : (numFullPtBlocks ? CurPtBlock->next->pts : 0);
3522
3523 if (!next || next->y() != pts[0].y()) {
3524 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3525 rowSize = 0;
3526 }
3527 }
3528 }
3529 }
3530 CurPtBlock = CurPtBlock->next;
3531 }
3532
3533 if (needsExtend) {
3534 for (int i = lastRow; i < reg->rects.size(); ++i)
3535 reg->rects[i].setBottom(extendTo);
3536 }
3537
3538 reg->numRects = reg->rects.size();
3539
3540 if (reg->numRects) {
3541 reg->extents.setTop(reg->rects[0].top());
3542 reg->extents.setBottom(reg->rects[lastRow].bottom());
3543
3544 for (int i = 0; i < reg->rects.size(); ++i)
3545 reg->updateInnerRect(reg->rects[i]);
3546 } else {
3547 reg->extents.setCoords(0, 0, 0, 0);
3548 }
3549}
3550
3551/*
3552 * polytoregion
3553 *
3554 * Scan converts a polygon by returning a run-length
3555 * encoding of the resultant bitmap -- the run-length
3556 * encoding is in the form of an array of rectangles.
3557 *
3558 * Can return 0 in case of errors.
3559 */
3560static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
3561 //Point *Pts; /* the pts */
3562 //int Count; /* number of pts */
3563 //int rule; /* winding rule */
3564{
3565 QRegionPrivate *region;
3566 register EdgeTableEntry *pAET; /* Active Edge Table */
3567 register int y; /* current scanline */
3568 register int iPts = 0; /* number of pts in buffer */
3569 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
3570 register ScanLineList *pSLL; /* current scanLineList */
3571 register QPoint *pts; /* output buffer */
3572 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
3573 EdgeTable ET; /* header node for ET */
3574 EdgeTableEntry AET; /* header node for AET */
3575 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
3576 ScanLineListBlock SLLBlock; /* header for scanlinelist */
3577 int fixWAET = false;
3578 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
3579 FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
3580 POINTBLOCK *tmpPtBlock;
3581 int numFullPtBlocks = 0;
3582
3583 if (!(region = new QRegionPrivate))
3584 return 0;
3585
3586 /* special case a rectangle */
3587 if (((Count == 4) ||
3588 ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
3589 && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
3590 && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
3591 && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
3592 && (Pts[3].y() == Pts[0].y())))) {
3593 int x = qMin(Pts[0].x(), Pts[2].x());
3594 region->extents.setLeft(x);
3595 int y = qMin(Pts[0].y(), Pts[2].y());
3596 region->extents.setTop(y);
3597 region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
3598 region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
3599 if ((region->extents.left() <= region->extents.right()) &&
3600 (region->extents.top() <= region->extents.bottom())) {
3601 region->numRects = 1;
3602 region->innerRect = region->extents;
3603 region->innerArea = region->innerRect.width() * region->innerRect.height();
3604 }
3605 return region;
3606 }
3607
3608 if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
3609 return 0;
3610
3611 region->vectorize();
3612
3613 pts = FirstPtBlock.pts;
3614 CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
3615
3616 pSLL = ET.scanlines.next;
3617 curPtBlock = &FirstPtBlock;
3618
3619 // sanity check that the region won't become too big...
3620 if (ET.ymax - ET.ymin > 100000) {
3621 // clean up region ptr
3622#ifndef QT_NO_DEBUG
3623 qWarning("QRegion: creating region from big polygon failed...!");
3624#endif
3625 delete region;
3626 return 0;
3627 }
3628
3629
3630 QT_TRY {
3631 if (rule == EvenOddRule) {
3632 /*
3633 * for each scanline
3634 */
3635 for (y = ET.ymin; y < ET.ymax; ++y) {
3636
3637 /*
3638 * Add a new edge to the active edge table when we
3639 * get to the next edge.
3640 */
3641 if (pSLL && y == pSLL->scanline) {
3642 loadAET(&AET, pSLL->edgelist);
3643 pSLL = pSLL->next;
3644 }
3645 pPrevAET = &AET;
3646 pAET = AET.next;
3647
3648 /*
3649 * for each active edge
3650 */
3651 while (pAET) {
3652 pts->setX(pAET->bres.minor_axis);
3653 pts->setY(y);
3654 ++pts;
3655 ++iPts;
3656
3657 /*
3658 * send out the buffer
3659 */
3660 if (iPts == NUMPTSTOBUFFER) {
3661 tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
3662 Q_CHECK_PTR(tmpPtBlock);
3663 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3664 curPtBlock->next = tmpPtBlock;
3665 curPtBlock = tmpPtBlock;
3666 pts = curPtBlock->pts;
3667 ++numFullPtBlocks;
3668 iPts = 0;
3669 }
3670 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
3671 }
3672 InsertionSort(&AET);
3673 }
3674 } else {
3675 /*
3676 * for each scanline
3677 */
3678 for (y = ET.ymin; y < ET.ymax; ++y) {
3679 /*
3680 * Add a new edge to the active edge table when we
3681 * get to the next edge.
3682 */
3683 if (pSLL && y == pSLL->scanline) {
3684 loadAET(&AET, pSLL->edgelist);
3685 computeWAET(&AET);
3686 pSLL = pSLL->next;
3687 }
3688 pPrevAET = &AET;
3689 pAET = AET.next;
3690 pWETE = pAET;
3691
3692 /*
3693 * for each active edge
3694 */
3695 while (pAET) {
3696 /*
3697 * add to the buffer only those edges that
3698 * are in the Winding active edge table.
3699 */
3700 if (pWETE == pAET) {
3701 pts->setX(pAET->bres.minor_axis);
3702 pts->setY(y);
3703 ++pts;
3704 ++iPts;
3705
3706 /*
3707 * send out the buffer
3708 */
3709 if (iPts == NUMPTSTOBUFFER) {
3710 tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
3711 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3712 curPtBlock->next = tmpPtBlock;
3713 curPtBlock = tmpPtBlock;
3714 pts = curPtBlock->pts;
3715 ++numFullPtBlocks;
3716 iPts = 0;
3717 }
3718 pWETE = pWETE->nextWETE;
3719 }
3720 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
3721 }
3722
3723 /*
3724 * recompute the winding active edge table if
3725 * we just resorted or have exited an edge.
3726 */
3727 if (InsertionSort(&AET) || fixWAET) {
3728 computeWAET(&AET);
3729 fixWAET = false;
3730 }
3731 }
3732 }
3733 } QT_CATCH(...) {
3734 FreeStorage(SLLBlock.next);
3735 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3736 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3737 tmpPtBlock = curPtBlock->next;
3738 free(curPtBlock);
3739 curPtBlock = tmpPtBlock;
3740 }
3741 free(pETEs);
3742 return 0; // this function returns 0 in case of an error
3743 }
3744
3745 FreeStorage(SLLBlock.next);
3746 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3747 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3748 tmpPtBlock = curPtBlock->next;
3749 free(curPtBlock);
3750 curPtBlock = tmpPtBlock;
3751 }
3752 free(pETEs);
3753 return region;
3754}
3755// END OF PolyReg.c extract
3756
3757QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
3758{
3759 QImage image = bitmap.toImage();
3760
3761 QRegionPrivate *region = new QRegionPrivate;
3762
3763 QRect xr;
3764
3765#define AddSpan \
3766 { \
3767 xr.setCoords(prev1, y, x-1, y); \
3768 UnionRectWithRegion(&xr, region, *region); \
3769 }
3770
3771 const uchar zero = 0;
3772 bool little = image.format() == QImage::Format_MonoLSB;
3773
3774 int x,
3775 y;
3776 for (y = 0; y < image.height(); ++y) {
3777 uchar *line = image.scanLine(y);
3778 int w = image.width();
3779 uchar all = zero;
3780 int prev1 = -1;
3781 for (x = 0; x < w;) {
3782 uchar byte = line[x / 8];
3783 if (x > w - 8 || byte!=all) {
3784 if (little) {
3785 for (int b = 8; b > 0 && x < w; --b) {
3786 if (!(byte & 0x01) == !all) {
3787 // More of the same
3788 } else {
3789 // A change.
3790 if (all!=zero) {
3791 AddSpan
3792 all = zero;
3793 } else {
3794 prev1 = x;
3795 all = ~zero;
3796 }
3797 }
3798 byte >>= 1;
3799 ++x;
3800 }
3801 } else {
3802 for (int b = 8; b > 0 && x < w; --b) {
3803 if (!(byte & 0x80) == !all) {
3804 // More of the same
3805 } else {
3806 // A change.
3807 if (all != zero) {
3808 AddSpan
3809 all = zero;
3810 } else {
3811 prev1 = x;
3812 all = ~zero;
3813 }
3814 }
3815 byte <<= 1;
3816 ++x;
3817 }
3818 }
3819 } else {
3820 x += 8;
3821 }
3822 }
3823 if (all != zero) {
3824 AddSpan
3825 }
3826 }
3827#undef AddSpan
3828
3829 return region;
3830}
3831
3832QRegion::QRegion()
3833 : d(&shared_empty)
3834{
3835 d->ref.ref();
3836}
3837
3838QRegion::QRegion(const QRect &r, RegionType t)
3839{
3840 if (r.isEmpty()) {
3841 d = &shared_empty;
3842 d->ref.ref();
3843 } else {
3844 d = new QRegionData;
3845 d->ref = 1;
3846#if defined(Q_WS_X11)
3847 d->rgn = 0;
3848 d->xrectangles = 0;
3849#elif defined(Q_WS_WIN)
3850 d->rgn = 0;
3851#elif defined(Q_WS_PM)
3852 d->rgn = 0;
3853 d->height = 0;
3854#endif
3855 if (t == Rectangle) {
3856 d->qt_rgn = new QRegionPrivate(r);
3857 } else if (t == Ellipse) {
3858 QPainterPath path;
3859 path.addEllipse(r.x(), r.y(), r.width(), r.height());
3860 QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
3861 d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
3862 }
3863 }
3864}
3865
3866QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
3867{
3868 if (a.count() > 2) {
3869 QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
3870 fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
3871 if (qt_rgn) {
3872 d = new QRegionData;
3873 d->ref = 1;
3874#if defined(Q_WS_X11)
3875 d->rgn = 0;
3876 d->xrectangles = 0;
3877#elif defined(Q_WS_WIN)
3878 d->rgn = 0;
3879#elif defined(Q_WS_PM)
3880 d->rgn = 0;
3881 d->height = 0;
3882#endif
3883 d->qt_rgn = qt_rgn;
3884 } else {
3885 d = &shared_empty;
3886 d->ref.ref();
3887 }
3888 } else {
3889 d = &shared_empty;
3890 d->ref.ref();
3891 }
3892}
3893
3894QRegion::QRegion(const QRegion &r)
3895{
3896 d = r.d;
3897 d->ref.ref();
3898}
3899
3900
3901QRegion::QRegion(const QBitmap &bm)
3902{
3903 if (bm.isNull()) {
3904 d = &shared_empty;
3905 d->ref.ref();
3906 } else {
3907 d = new QRegionData;
3908 d->ref = 1;
3909#if defined(Q_WS_X11)
3910 d->rgn = 0;
3911 d->xrectangles = 0;
3912#elif defined(Q_WS_WIN)
3913 d->rgn = 0;
3914#elif defined(Q_WS_PM)
3915 d->rgn = 0;
3916 d->height = 0;
3917#endif
3918 d->qt_rgn = qt_bitmapToRegion(bm);
3919 }
3920}
3921
3922void QRegion::cleanUp(QRegion::QRegionData *x)
3923{
3924 delete x->qt_rgn;
3925#if defined(Q_WS_X11)
3926 if (x->rgn)
3927 XDestroyRegion(x->rgn);
3928 if (x->xrectangles)
3929 free(x->xrectangles);
3930#elif defined(Q_WS_WIN)
3931 if (x->rgn)
3932 qt_win_dispose_rgn(x->rgn);
3933#elif defined(Q_WS_PM)
3934 if (x->rgn)
3935 disposeHandle(x->rgn);
3936#endif
3937 delete x;
3938}
3939
3940QRegion::~QRegion()
3941{
3942 if (!d->ref.deref())
3943 cleanUp(d);
3944}
3945
3946
3947QRegion &QRegion::operator=(const QRegion &r)
3948{
3949 r.d->ref.ref();
3950 if (!d->ref.deref())
3951 cleanUp(d);
3952 d = r.d;
3953 return *this;
3954}
3955
3956
3957/*!
3958 \internal
3959*/
3960QRegion QRegion::copy() const
3961{
3962 QRegion r;
3963 QScopedPointer<QRegionData> x(new QRegionData);
3964 x->ref = 1;
3965#if defined(Q_WS_X11)
3966 x->rgn = 0;
3967 x->xrectangles = 0;
3968#elif defined(Q_WS_WIN)
3969 x->rgn = 0;
3970#elif defined(Q_WS_PM)
3971 x->rgn = 0;
3972 x->height = 0;
3973#endif
3974 if (d->qt_rgn)
3975 x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
3976 else
3977 x->qt_rgn = new QRegionPrivate;
3978 if (!r.d->ref.deref())
3979 cleanUp(r.d);
3980 r.d = x.take();
3981 return r;
3982}
3983
3984bool QRegion::isEmpty() const
3985{
3986 return d == &shared_empty || d->qt_rgn->numRects == 0;
3987}
3988
3989
3990bool QRegion::contains(const QPoint &p) const
3991{
3992 return PointInRegion(d->qt_rgn, p.x(), p.y());
3993}
3994
3995bool QRegion::contains(const QRect &r) const
3996{
3997 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
3998}
3999
4000
4001
4002void QRegion::translate(int dx, int dy)
4003{
4004 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
4005 return;
4006
4007 detach();
4008 OffsetRegion(*d->qt_rgn, dx, dy);
4009}
4010
4011QRegion QRegion::unite(const QRegion &r) const
4012{
4013 if (isEmptyHelper(d->qt_rgn))
4014 return r;
4015 if (isEmptyHelper(r.d->qt_rgn))
4016 return *this;
4017 if (d == r.d)
4018 return *this;
4019
4020 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
4021 return *this;
4022 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
4023 return r;
4024 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
4025 QRegion result(*this);
4026 result.detach();
4027 result.d->qt_rgn->append(r.d->qt_rgn);
4028 return result;
4029 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
4030 QRegion result(*this);
4031 result.detach();
4032 result.d->qt_rgn->prepend(r.d->qt_rgn);
4033 return result;
4034 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4035 return *this;
4036 } else {
4037 QRegion result;
4038 result.detach();
4039 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4040 return result;
4041 }
4042}
4043
4044QRegion& QRegion::operator+=(const QRegion &r)
4045{
4046 if (isEmptyHelper(d->qt_rgn))
4047 return *this = r;
4048 if (isEmptyHelper(r.d->qt_rgn))
4049 return *this;
4050 if (d == r.d)
4051 return *this;
4052
4053 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
4054 return *this;
4055 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
4056 return *this = r;
4057 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
4058 detach();
4059 d->qt_rgn->append(r.d->qt_rgn);
4060 return *this;
4061 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
4062 detach();
4063 d->qt_rgn->prepend(r.d->qt_rgn);
4064 return *this;
4065 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4066 return *this;
4067 } else {
4068 detach();
4069 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
4070 return *this;
4071 }
4072}
4073
4074QRegion QRegion::unite(const QRect &r) const
4075{
4076 if (isEmptyHelper(d->qt_rgn))
4077 return r;
4078 if (r.isEmpty())
4079 return *this;
4080
4081 if (d->qt_rgn->contains(r)) {
4082 return *this;
4083 } else if (d->qt_rgn->within(r)) {
4084 return r;
4085 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4086 return *this;
4087 } else if (d->qt_rgn->canAppend(&r)) {
4088 QRegion result(*this);
4089 result.detach();
4090 result.d->qt_rgn->append(&r);
4091 return result;
4092 } else if (d->qt_rgn->canPrepend(&r)) {
4093 QRegion result(*this);
4094 result.detach();
4095 result.d->qt_rgn->prepend(&r);
4096 return result;
4097 } else {
4098 QRegion result;
4099 result.detach();
4100 QRegionPrivate rp(r);
4101 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4102 return result;
4103 }
4104}
4105
4106QRegion& QRegion::operator+=(const QRect &r)
4107{
4108 if (isEmptyHelper(d->qt_rgn))
4109 return *this = r;
4110 if (r.isEmpty())
4111 return *this;
4112
4113 if (d->qt_rgn->contains(r)) {
4114 return *this;
4115 } else if (d->qt_rgn->within(r)) {
4116 return *this = r;
4117 } else if (d->qt_rgn->canAppend(&r)) {
4118 detach();
4119 d->qt_rgn->append(&r);
4120 return *this;
4121 } else if (d->qt_rgn->canPrepend(&r)) {
4122 detach();
4123 d->qt_rgn->prepend(&r);
4124 return *this;
4125 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4126 return *this;
4127 } else {
4128 detach();
4129 QRegionPrivate p(r);
4130 UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4131 return *this;
4132 }
4133}
4134
4135QRegion QRegion::intersect(const QRegion &r) const
4136{
4137 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4138 || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4139 return QRegion();
4140
4141 /* this is fully contained in r */
4142 if (r.d->qt_rgn->contains(*d->qt_rgn))
4143 return *this;
4144
4145 /* r is fully contained in this */
4146 if (d->qt_rgn->contains(*r.d->qt_rgn))
4147 return r;
4148
4149 if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
4150 const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
4151 d->qt_rgn->extents);
4152 return QRegion(rect);
4153 } else if (r.d->qt_rgn->numRects == 1) {
4154 QRegion result(*this);
4155 result.detach();
4156 result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4157 return result;
4158 } else if (d->qt_rgn->numRects == 1) {
4159 QRegion result(r);
4160 result.detach();
4161 result.d->qt_rgn->intersect(d->qt_rgn->extents);
4162 return result;
4163 }
4164
4165 QRegion result;
4166 result.detach();
4167 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
4168
4169 /*
4170 * Can't alter dest's extents before we call miRegionOp because
4171 * it might be one of the source regions and miRegionOp depends
4172 * on the extents of those regions being the same. Besides, this
4173 * way there's no checking against rectangles that will be nuked
4174 * due to coalescing, so we have to examine fewer rectangles.
4175 */
4176 miSetExtents(*result.d->qt_rgn);
4177 return result;
4178}
4179
4180QRegion QRegion::intersect(const QRect &r) const
4181{
4182 if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4183 || !EXTENTCHECK(&d->qt_rgn->extents, &r))
4184 return QRegion();
4185
4186 /* this is fully contained in r */
4187 if (d->qt_rgn->within(r))
4188 return *this;
4189
4190 /* r is fully contained in this */
4191 if (d->qt_rgn->contains(r))
4192 return r;
4193
4194 if (d->qt_rgn->numRects == 1) {
4195 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4196 r.normalized());
4197 return QRegion(rect);
4198 }
4199
4200 QRegion result(*this);
4201 result.detach();
4202 result.d->qt_rgn->intersect(r);
4203 return result;
4204}
4205
4206QRegion QRegion::subtract(const QRegion &r) const
4207{
4208 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4209 return *this;
4210 if (r.d->qt_rgn->contains(*d->qt_rgn))
4211 return QRegion();
4212 if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4213 return *this;
4214 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4215 return QRegion();
4216
4217#ifdef QT_REGION_DEBUG
4218 d->qt_rgn->selfTest();
4219 r.d->qt_rgn->selfTest();
4220#endif
4221
4222 QRegion result;
4223 result.detach();
4224 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4225#ifdef QT_REGION_DEBUG
4226 result.d->qt_rgn->selfTest();
4227#endif
4228 return result;
4229}
4230
4231QRegion QRegion::eor(const QRegion &r) const
4232{
4233 if (isEmptyHelper(d->qt_rgn)) {
4234 return r;
4235 } else if (isEmptyHelper(r.d->qt_rgn)) {
4236 return *this;
4237 } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4238 return (*this + r);
4239 } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4240 return QRegion();
4241 } else {
4242 QRegion result;
4243 result.detach();
4244 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4245 return result;
4246 }
4247}
4248
4249QRect QRegion::boundingRect() const
4250{
4251 if (isEmpty())
4252 return QRect();
4253 return d->qt_rgn->extents;
4254}
4255
4256/*! \internal
4257 Returns true if \a rect is guaranteed to be fully contained in \a region.
4258 A false return value does not guarantee the opposite.
4259*/
4260#ifdef Q_WS_QWS
4261Q_GUI_EXPORT
4262#endif
4263bool qt_region_strictContains(const QRegion &region, const QRect &rect)
4264{
4265 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4266 return false;
4267
4268#if 0 // TEST_INNERRECT
4269 static bool guard = false;
4270 if (guard)
4271 return false;
4272 guard = true;
4273 QRegion inner = region.d->qt_rgn->innerRect;
4274 Q_ASSERT((inner - region).isEmpty());
4275 guard = false;
4276
4277 int maxArea = 0;
4278 for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
4279 const QRect r = region.d->qt_rgn->rects.at(i);
4280 if (r.width() * r.height() > maxArea)
4281 maxArea = r.width() * r.height();
4282 }
4283
4284 if (maxArea > region.d->qt_rgn->innerArea) {
4285 qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
4286 }
4287 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
4288#endif
4289
4290 const QRect r1 = region.d->qt_rgn->innerRect;
4291 return (rect.left() >= r1.left() && rect.right() <= r1.right()
4292 && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
4293}
4294
4295QVector<QRect> QRegion::rects() const
4296{
4297 if (d->qt_rgn) {
4298 d->qt_rgn->vectorize();
4299 // hw: modify the vector size directly to avoid reallocation
4300 d->qt_rgn->rects.d->size = d->qt_rgn->numRects;
4301 return d->qt_rgn->rects;
4302 } else {
4303 return QVector<QRect>();
4304 }
4305}
4306
4307void QRegion::setRects(const QRect *rects, int num)
4308{
4309 *this = QRegion();
4310 if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
4311 return;
4312
4313 detach();
4314
4315 d->qt_rgn->numRects = num;
4316 if (num == 1) {
4317 d->qt_rgn->extents = *rects;
4318 d->qt_rgn->innerRect = *rects;
4319 } else {
4320 d->qt_rgn->rects.resize(num);
4321
4322 int left = INT_MAX,
4323 right = INT_MIN,
4324 top = INT_MAX,
4325 bottom = INT_MIN;
4326 for (int i = 0; i < num; ++i) {
4327 const QRect &rect = rects[i];
4328 d->qt_rgn->rects[i] = rect;
4329 left = qMin(rect.left(), left);
4330 right = qMax(rect.right(), right);
4331 top = qMin(rect.top(), top);
4332 bottom = qMax(rect.bottom(), bottom);
4333 d->qt_rgn->updateInnerRect(rect);
4334 }
4335 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4336 }
4337}
4338
4339int QRegion::numRects() const
4340{
4341 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4342}
4343
4344int QRegion::rectCount() const
4345{
4346 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4347}
4348
4349
4350bool QRegion::operator==(const QRegion &r) const
4351{
4352 if (!d->qt_rgn)
4353 return r.isEmpty();
4354 if (!r.d->qt_rgn)
4355 return isEmpty();
4356
4357 if (d == r.d)
4358 return true;
4359 else
4360 return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4361}
4362
4363bool QRegion::intersects(const QRect &rect) const
4364{
4365 if (isEmptyHelper(d->qt_rgn) || rect.isNull())
4366 return false;
4367
4368 const QRect r = rect.normalized();
4369 if (!rect_intersects(d->qt_rgn->extents, r))
4370 return false;
4371 if (d->qt_rgn->numRects == 1)
4372 return true;
4373
4374 const QVector<QRect> myRects = rects();
4375 for (QVector<QRect>::const_iterator it = myRects.constBegin(); it < myRects.constEnd(); ++it)
4376 if (rect_intersects(r, *it))
4377 return true;
4378 return false;
4379}
4380
4381
4382#endif
4383QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.