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

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 130.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@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_OS_WINCE)
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 multimedia
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 \warning Due to window system limitations, the whole coordinate space for a
96 region is limited to the points between -32767 and 32767 on Windows
97 95/98/ME. You can circumvent this limitation by using a QPainterPath.
98
99 \section1 Additional License Information
100
101 On Embedded Linux, Windows CE and X11 platforms, parts of this class rely on
102 code obtained under the following licenses:
103
104 \legalese
105 Copyright (c) 1987 X Consortium
106
107 Permission is hereby granted, free of charge, to any person obtaining a copy
108 of this software and associated documentation files (the "Software"), to deal
109 in the Software without restriction, including without limitation the rights
110 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
111 copies of the Software, and to permit persons to whom the Software is
112 furnished to do so, subject to the following conditions:
113
114 The above copyright notice and this permission notice shall be included in
115 all copies or substantial portions of the Software.
116
117 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
118 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
119 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
120 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
121 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
122 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
123
124 Except as contained in this notice, the name of the X Consortium shall not be
125 used in advertising or otherwise to promote the sale, use or other dealings
126 in this Software without prior written authorization from the X Consortium.
127 \endlegalese
128
129 \br
130
131 \legalese
132 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
133
134 All Rights Reserved
135
136 Permission to use, copy, modify, and distribute this software and its
137 documentation for any purpose and without fee is hereby granted,
138 provided that the above copyright notice appear in all copies and that
139 both that copyright notice and this permission notice appear in
140 supporting documentation, and that the name of Digital not be
141 used in advertising or publicity pertaining to distribution of the
142 software without specific, written prior permission.
143
144 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
145 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
146 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
147 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
148 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
149 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
150 SOFTWARE.
151 \endlegalese
152
153 \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
154*/
155
156
157/*!
158 \enum QRegion::RegionType
159
160 Specifies the shape of the region to be created.
161
162 \value Rectangle the region covers the entire rectangle.
163 \value Ellipse the region is an ellipse inside the rectangle.
164*/
165
166/*!
167 \fn void QRegion::translate(const QPoint &point)
168
169 \overload
170
171 Translates the region \a{point}\e{.x()} along the x axis and
172 \a{point}\e{.y()} along the y axis, relative to the current
173 position. Positive values move the region to the right and down.
174
175 Translates to the given \a point.
176*/
177
178/*!
179 \fn Handle QRegion::handle() const
180
181 Returns a platform-specific region handle. The \c Handle type is
182 \c HRGN on Windows, \c Region on X11, and \c RgnHandle on Mac OS
183 X. On \l{Qt for Embedded Linux} it is \c {void *}.
184
185 \warning This function is not portable.
186*/
187
188/*****************************************************************************
189 QRegion member functions
190 *****************************************************************************/
191
192/*!
193 \fn QRegion::QRegion()
194
195 Constructs an empty region.
196
197 \sa isEmpty()
198*/
199
200/*!
201 \fn QRegion::QRegion(const QRect &r, RegionType t)
202 \overload
203
204 Create a region based on the rectange \a r with region type \a t.
205
206 If the rectangle is invalid a null region will be created.
207
208 \sa QRegion::RegionType
209*/
210
211/*!
212 \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
213
214 Constructs a polygon region from the point array \a a with the fill rule
215 specified by \a fillRule.
216
217 If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
218 using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
219 algorithm is used.
220
221 \warning This constructor can be used to create complex regions that will
222 slow down painting when used.
223*/
224
225/*!
226 \fn QRegion::QRegion(const QRegion &r)
227
228 Constructs a new region which is equal to region \a r.
229*/
230
231/*!
232 \fn QRegion::QRegion(const QBitmap &bm)
233
234 Constructs a region from the bitmap \a bm.
235
236 The resulting region consists of the pixels in bitmap \a bm that
237 are Qt::color1, as if each pixel was a 1 by 1 rectangle.
238
239 This constructor may create complex regions that will slow down
240 painting when used. Note that drawing masked pixmaps can be done
241 much faster using QPixmap::setMask().
242*/
243
244/*!
245 Constructs a rectangular or elliptic region.
246
247 If \a t is \c Rectangle, the region is the filled rectangle (\a x,
248 \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled
249 ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size
250 (\a w ,\a h).
251*/
252QRegion::QRegion(int x, int y, int w, int h, RegionType t)
253{
254 QRegion tmp(QRect(x, y, w, h), t);
255 tmp.d->ref.ref();
256 d = tmp.d;
257}
258
259#ifdef QT3_SUPPORT
260/*!
261 Use the constructor tha takes a Qt::FillRule as the second
262 argument instead.
263*/
264QRegion::QRegion(const QPolygon &pa, bool winding)
265{
266 new (this) QRegion(pa, winding ? Qt::WindingFill : Qt::OddEvenFill);
267}
268#endif
269
270/*!
271 \fn QRegion::~QRegion()
272 \internal
273
274 Destroys the region.
275*/
276
277void QRegion::detach()
278{
279 if (d->ref != 1)
280 *this = copy();
281#if defined(Q_WS_X11)
282 else if (d->xrectangles) {
283 free(d->xrectangles);
284 d->xrectangles = 0;
285 }
286#endif
287}
288
289// duplicates in qregion_win.cpp and qregion_wce.cpp
290#define QRGN_SETRECT 1 // region stream commands
291#define QRGN_SETELLIPSE 2 // (these are internal)
292#define QRGN_SETPTARRAY_ALT 3
293#define QRGN_SETPTARRAY_WIND 4
294#define QRGN_TRANSLATE 5
295#define QRGN_OR 6
296#define QRGN_AND 7
297#define QRGN_SUB 8
298#define QRGN_XOR 9
299#define QRGN_RECTS 10
300
301
302#ifndef QT_NO_DATASTREAM
303
304/*
305 Executes region commands in the internal buffer and rebuilds the
306 original region.
307
308 We do this when we read a region from the data stream.
309
310 If \a ver is non-0, uses the format version \a ver on reading the
311 byte array.
312*/
313void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
314{
315 QByteArray copy = buffer;
316 QDataStream s(&copy, QIODevice::ReadOnly);
317 if (ver)
318 s.setVersion(ver);
319 s.setByteOrder(byteOrder);
320 QRegion rgn;
321#ifndef QT_NO_DEBUG
322 int test_cnt = 0;
323#endif
324 while (!s.atEnd()) {
325 qint32 id;
326 if (s.version() == 1) {
327 int id_int;
328 s >> id_int;
329 id = id_int;
330 } else {
331 s >> id;
332 }
333#ifndef QT_NO_DEBUG
334 if (test_cnt > 0 && id != QRGN_TRANSLATE)
335 qWarning("QRegion::exec: Internal error");
336 test_cnt++;
337#endif
338 if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
339 QRect r;
340 s >> r;
341 rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
342 } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
343 QPolygon a;
344 s >> a;
345 rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
346 } else if (id == QRGN_TRANSLATE) {
347 QPoint p;
348 s >> p;
349 rgn.translate(p.x(), p.y());
350 } else if (id >= QRGN_OR && id <= QRGN_XOR) {
351 QByteArray bop1, bop2;
352 QRegion r1, r2;
353 s >> bop1;
354 r1.exec(bop1);
355 s >> bop2;
356 r2.exec(bop2);
357
358 switch (id) {
359 case QRGN_OR:
360 rgn = r1.united(r2);
361 break;
362 case QRGN_AND:
363 rgn = r1.intersected(r2);
364 break;
365 case QRGN_SUB:
366 rgn = r1.subtracted(r2);
367 break;
368 case QRGN_XOR:
369 rgn = r1.xored(r2);
370 break;
371 }
372 } else if (id == QRGN_RECTS) {
373 // (This is the only form used in Qt 2.0)
374 quint32 n;
375 s >> n;
376 QRect r;
377 for (int i=0; i<(int)n; i++) {
378 s >> r;
379 rgn = rgn.united(QRegion(r));
380 }
381 }
382 }
383 *this = rgn;
384}
385
386
387/*****************************************************************************
388 QRegion stream functions
389 *****************************************************************************/
390
391/*!
392 \fn QRegion &QRegion::operator=(const QRegion &r)
393
394 Assigns \a r to this region and returns a reference to the region.
395*/
396
397/*!
398 \relates QRegion
399
400 Writes the region \a r to the stream \a s and returns a reference
401 to the stream.
402
403 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
404*/
405
406QDataStream &operator<<(QDataStream &s, const QRegion &r)
407{
408 QVector<QRect> a = r.rects();
409 if (a.isEmpty()) {
410 s << (quint32)0;
411 } else {
412 if (s.version() == 1) {
413 int i;
414 for (i = a.size() - 1; i > 0; --i) {
415 s << (quint32)(12 + i * 24);
416 s << (int)QRGN_OR;
417 }
418 for (i = 0; i < a.size(); ++i) {
419 s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i];
420 }
421 } else {
422 s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect
423 s << (qint32)QRGN_RECTS;
424 s << a;
425 }
426 }
427 return s;
428}
429
430/*!
431 \relates QRegion
432
433 Reads a region from the stream \a s into \a r and returns a
434 reference to the stream.
435
436 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
437*/
438
439QDataStream &operator>>(QDataStream &s, QRegion &r)
440{
441 QByteArray b;
442 s >> b;
443 r.exec(b, s.version(), s.byteOrder());
444 return s;
445}
446#endif //QT_NO_DATASTREAM
447
448#ifndef QT_NO_DEBUG_STREAM
449QDebug operator<<(QDebug s, const QRegion &r)
450{
451 QVector<QRect> rects = r.rects();
452 s.nospace() << "QRegion(size=" << rects.size() << "), "
453 << "bounds = " << r.boundingRect() << "\n";
454 for (int i=0; i<rects.size(); ++i)
455 s << "- " << i << rects.at(i) << "\n";
456 return s;
457}
458#endif
459
460
461// These are not inline - they can be implemented better on some platforms
462// (eg. Windows at least provides 3-variable operations). For now, simple.
463
464
465/*!
466 Applies the united() function to this region and \a r. \c r1|r2 is
467 equivalent to \c r1.united(r2).
468
469 \sa united(), operator+()
470*/
471const QRegion QRegion::operator|(const QRegion &r) const
472 { return united(r); }
473
474/*!
475 Applies the united() function to this region and \a r. \c r1+r2 is
476 equivalent to \c r1.united(r2).
477
478 \sa united(), operator|()
479*/
480const QRegion QRegion::operator+(const QRegion &r) const
481 { return united(r); }
482
483/*!
484 \overload
485 \since 4.4
486 */
487const QRegion QRegion::operator+(const QRect &r) const
488 { return united(r); }
489
490/*!
491 Applies the intersected() function to this region and \a r. \c r1&r2
492 is equivalent to \c r1.intersected(r2).
493
494 \sa intersected()
495*/
496const QRegion QRegion::operator&(const QRegion &r) const
497 { return intersected(r); }
498
499/*!
500 \overload
501 \since 4.4
502 */
503const QRegion QRegion::operator&(const QRect &r) const
504{
505 return intersected(r);
506}
507
508/*!
509 Applies the subtracted() function to this region and \a r. \c r1-r2
510 is equivalent to \c r1.subtracted(r2).
511
512 \sa subtracted()
513*/
514const QRegion QRegion::operator-(const QRegion &r) const
515 { return subtracted(r); }
516
517/*!
518 Applies the xored() function to this region and \a r. \c r1^r2 is
519 equivalent to \c r1.xored(r2).
520
521 \sa xored()
522*/
523const QRegion QRegion::operator^(const QRegion &r) const
524 { return xored(r); }
525
526/*!
527 Applies the united() function to this region and \a r and assigns
528 the result to this region. \c r1|=r2 is equivalent to \c
529 {r1 = r1.united(r2)}.
530
531 \sa united()
532*/
533QRegion& QRegion::operator|=(const QRegion &r)
534 { return *this = *this | r; }
535
536/*!
537 \fn QRegion& QRegion::operator+=(const QRect &rect)
538
539 Returns a region that is the union of this region with the specified \a rect.
540
541 \sa united()
542*/
543/*!
544 \fn QRegion& QRegion::operator+=(const QRegion &r)
545
546 Applies the united() function to this region and \a r and assigns
547 the result to this region. \c r1+=r2 is equivalent to \c
548 {r1 = r1.united(r2)}.
549
550 \sa intersected()
551*/
552#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE)
553QRegion& QRegion::operator+=(const QRect &r)
554{
555 return operator+=(QRegion(r));
556}
557#endif
558
559/*!
560 \fn QRegion& QRegion::operator&=(const QRegion &r)
561
562 Applies the intersected() function to this region and \a r and
563 assigns the result to this region. \c r1&=r2 is equivalent to \c
564 r1 = r1.intersected(r2).
565
566 \sa intersected()
567*/
568#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE)
569QRegion& QRegion::operator&=(const QRegion &r)
570 { return *this = *this & r; }
571#endif
572
573/*!
574 \overload
575 \since 4.4
576 */
577#if defined (Q_OS_UNIX) || defined (Q_OS_WINCE)
578QRegion& QRegion::operator&=(const QRect &r)
579{
580 return *this = *this & r;
581}
582#else
583QRegion& QRegion::operator&=(const QRect &r)
584{
585 return *this &= (QRegion(r));
586}
587#endif
588
589/*!
590 \fn QRegion& QRegion::operator-=(const QRegion &r)
591
592 Applies the subtracted() function to this region and \a r and
593 assigns the result to this region. \c r1-=r2 is equivalent to \c
594 {r1 = r1.subtracted(r2)}.
595
596 \sa subtracted()
597*/
598#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE)
599QRegion& QRegion::operator-=(const QRegion &r)
600 { return *this = *this - r; }
601#endif
602
603/*!
604 Applies the xored() function to this region and \a r and
605 assigns the result to this region. \c r1^=r2 is equivalent to \c
606 {r1 = r1.xored(r2)}.
607
608 \sa xored()
609*/
610QRegion& QRegion::operator^=(const QRegion &r)
611 { return *this = *this ^ r; }
612
613/*!
614 \fn bool QRegion::operator!=(const QRegion &other) const
615
616 Returns true if this region is different from the \a other region;
617 otherwise returns false.
618*/
619
620/*!
621 Returns the region as a QVariant
622*/
623QRegion::operator QVariant() const
624{
625 return QVariant(QVariant::Region, this);
626}
627
628/*!
629 \fn bool QRegion::operator==(const QRegion &r) const
630
631 Returns true if the region is equal to \a r; otherwise returns
632 false.
633*/
634
635/*!
636 \fn bool QRegion::isNull() const
637
638 Use isEmpty() instead.
639*/
640
641
642/*!
643 \fn void QRegion::translate(int dx, int dy)
644
645 Translates (moves) the region \a dx along the X axis and \a dy
646 along the Y axis.
647*/
648
649/*!
650 \fn QRegion QRegion::translated(const QPoint &p) const
651 \overload
652 \since 4.1
653
654 Returns a copy of the regtion that is translated \a{p}\e{.x()}
655 along the x axis and \a{p}\e{.y()} along the y axis, relative to
656 the current position. Positive values move the rectangle to the
657 right and down.
658
659 \sa translate()
660*/
661
662/*!
663 \since 4.1
664
665 Returns a copy of the region that is translated \a dx along the
666 x axis and \a dy along the y axis, relative to the current
667 position. Positive values move the region to the right and
668 down.
669
670 \sa translate()
671*/
672
673QRegion
674QRegion::translated(int dx, int dy) const
675{
676 QRegion ret(*this);
677 ret.translate(dx, dy);
678 return ret;
679}
680
681
682inline bool rect_intersects(const QRect &r1, const QRect &r2)
683{
684 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
685 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
686}
687
688/*!
689 \since 4.2
690
691 Returns true if this region intersects with \a region, otherwise
692 returns false.
693*/
694bool QRegion::intersects(const QRegion &region) const
695{
696 if (isEmpty() || region.isEmpty())
697 return false;
698
699 if (!rect_intersects(boundingRect(), region.boundingRect()))
700 return false;
701
702 const QVector<QRect> myRects = rects();
703 const QVector<QRect> otherRects = region.rects();
704
705 for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1)
706 for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2)
707 if (rect_intersects(*i1, *i2))
708 return true;
709 return false;
710}
711
712/*!
713 \since 4.2
714
715 Returns true if this region intersects with \a rect, otherwise
716 returns false.
717*/
718bool QRegion::intersects(const QRect &rect) const
719{
720 if (isEmpty() || rect.isNull())
721 return false;
722
723 const QRect r = rect.normalized();
724 if (!rect_intersects(boundingRect(), r))
725 return false;
726
727 const QVector<QRect> myRects = rects();
728 for (QVector<QRect>::const_iterator it = myRects.constBegin(); it < myRects.constEnd(); ++it)
729 if (rect_intersects(r, *it))
730 return true;
731 return false;
732}
733
734#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE)
735/*!
736 \overload
737 \since 4.4
738*/
739QRegion QRegion::intersect(const QRect &r) const
740{
741 return intersect(QRegion(r));
742}
743#endif
744
745/*!
746 \fn int QRegion::numRects() const
747 \since 4.4
748
749 Returns the number of rectangles that will be returned in rects().
750*/
751
752/*!
753 \fn bool QRegion::isEmpty() const
754
755 Returns true if the region is empty; otherwise returns false. An
756 empty region is a region that contains no points.
757
758 Example:
759 \snippet doc/src/snippets/code/src_gui_painting_qregion_unix.cpp 0
760*/
761
762/*!
763 \fn bool QRegion::contains(const QPoint &p) const
764
765 Returns true if the region contains the point \a p; otherwise
766 returns false.
767*/
768
769/*!
770 \fn bool QRegion::contains(const QRect &r) const
771 \overload
772
773 Returns true if the region overlaps the rectangle \a r; otherwise
774 returns false.
775*/
776
777/*!
778 \fn QRegion QRegion::unite(const QRegion &r) const
779 \obsolete
780
781 Use united(\a r) instead.
782*/
783
784/*!
785 \fn QRegion QRegion::unite(const QRect &rect) const
786 \since 4.4
787 \obsolete
788
789 Use united(\a rect) instead.
790*/
791
792/*!
793 \fn QRegion QRegion::united(const QRect &rect) const
794 \since 4.4
795
796 Returns a region which is the union of this region and the given \a rect.
797
798 \sa intersected(), subtracted(), xored()
799*/
800
801/*!
802 \fn QRegion QRegion::united(const QRegion &r) const
803 \since 4.2
804
805 Returns a region which is the union of this region and \a r.
806
807 \img runion.png Region Union
808
809 The figure shows the union of two elliptical regions.
810
811 \sa intersected(), subtracted(), xored()
812*/
813
814/*!
815 \fn QRegion QRegion::intersect(const QRegion &r) const
816 \obsolete
817
818 Use intersected(\a r) instead.
819*/
820
821/*!
822 \fn QRegion QRegion::intersect(const QRect &rect) const
823 \since 4.4
824 \obsolete
825
826 Use intersected(\a rect) instead.
827*/
828
829/*!
830 \fn QRegion QRegion::intersected(const QRect &rect) const
831 \since 4.4
832
833 Returns a region which is the intersection of this region and the given \a rect.
834
835 \sa subtracted(), united(), xored()
836*/
837
838/*!
839 \fn QRegion QRegion::intersected(const QRegion &r) const
840 \since 4.2
841
842 Returns a region which is the intersection of this region and \a r.
843
844 \img rintersect.png Region Intersection
845
846 The figure shows the intersection of two elliptical regions.
847
848 \sa subtracted(), united(), xored()
849*/
850
851/*!
852 \fn QRegion QRegion::subtract(const QRegion &r) const
853 \obsolete
854
855 Use subtracted(\a r) instead.
856*/
857
858/*!
859 \fn QRegion QRegion::subtracted(const QRegion &r) const
860 \since 4.2
861
862 Returns a region which is \a r subtracted from this region.
863
864 \img rsubtract.png Region Subtraction
865
866 The figure shows the result when the ellipse on the right is
867 subtracted from the ellipse on the left (\c {left - right}).
868
869 \sa intersected(), united(), xored()
870*/
871
872/*!
873 \fn QRegion QRegion::eor(const QRegion &r) const
874 \obsolete
875
876 Use xored(\a r) instead.
877*/
878
879/*!
880 \fn QRegion QRegion::xored(const QRegion &r) const
881 \since 4.2
882
883 Returns a region which is the exclusive or (XOR) of this region
884 and \a r.
885
886 \img rxor.png Region XORed
887
888 The figure shows the exclusive or of two elliptical regions.
889
890 \sa intersected(), united(), subtracted()
891*/
892
893/*!
894 \fn QRect QRegion::boundingRect() const
895
896 Returns the bounding rectangle of this region. An empty region
897 gives a rectangle that is QRect::isNull().
898*/
899
900/*!
901 \fn QVector<QRect> QRegion::rects() const
902
903 Returns an array of non-overlapping rectangles that make up the
904 region.
905
906 The union of all the rectangles is equal to the original region.
907*/
908
909/*!
910 \fn void QRegion::setRects(const QRect *rects, int number)
911
912 Sets the region using the array of rectangles specified by \a rects and
913 \a number.
914 The rectangles \e must be optimally Y-X sorted and follow these restrictions:
915
916 \list
917 \o The rectangles must not intersect.
918 \o All rectangles with a given top coordinate must have the same height.
919 \o No two rectangles may abut horizontally (they should be combined
920 into a single wider rectangle in that case).
921 \o The rectangles must be sorted in ascending order, with Y as the major
922 sort key and X as the minor sort key.
923 \endlist
924 \omit
925 Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X).
926 \endomit
927*/
928
929namespace {
930
931struct Segment
932{
933 Segment() {}
934 Segment(const QPoint &p)
935 : added(false)
936 , point(p)
937 {
938 }
939
940 int left() const
941 {
942 return qMin(point.x(), next->point.x());
943 }
944
945 int right() const
946 {
947 return qMax(point.x(), next->point.x());
948 }
949
950 bool overlaps(const Segment &other) const
951 {
952 return left() < other.right() && other.left() < right();
953 }
954
955 void connect(Segment &other)
956 {
957 next = &other;
958 other.prev = this;
959
960 horizontal = (point.y() == other.point.y());
961 }
962
963 void merge(Segment &other)
964 {
965 if (right() <= other.right()) {
966 QPoint p = other.point;
967 Segment *oprev = other.prev;
968
969 other.point = point;
970 other.prev = prev;
971 prev->next = &other;
972
973 point = p;
974 prev = oprev;
975 oprev->next = this;
976 } else {
977 Segment *onext = other.next;
978 other.next = next;
979 next->prev = &other;
980
981 next = onext;
982 next->prev = this;
983 }
984 }
985
986 int horizontal : 1;
987 int added : 1;
988
989 QPoint point;
990 Segment *prev;
991 Segment *next;
992};
993
994void mergeSegments(Segment *a, int na, Segment *b, int nb)
995{
996 int i = 0;
997 int j = 0;
998
999 while (i != na && j != nb) {
1000 Segment &sa = a[i];
1001 Segment &sb = b[j];
1002 const int ra = sa.right();
1003 const int rb = sb.right();
1004 if (sa.overlaps(sb))
1005 sa.merge(sb);
1006 i += (rb >= ra);
1007 j += (ra >= rb);
1008 }
1009}
1010
1011void addSegmentsToPath(Segment *segment, QPainterPath &path)
1012{
1013 Segment *current = segment;
1014 path.moveTo(current->point);
1015
1016 current->added = true;
1017
1018 Segment *last = current;
1019 current = current->next;
1020 while (current != segment) {
1021 if (current->horizontal != last->horizontal)
1022 path.lineTo(current->point);
1023 current->added = true;
1024 last = current;
1025 current = current->next;
1026 }
1027}
1028
1029}
1030
1031Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
1032{
1033 QPainterPath result;
1034 if (region.numRects() == 1) {
1035 result.addRect(region.boundingRect());
1036 return result;
1037 }
1038
1039 const QVector<QRect> rects = region.rects();
1040
1041 QVarLengthArray<Segment> segments;
1042 segments.resize(4 * rects.size());
1043
1044 const QRect *rect = rects.constData();
1045 const QRect *end = rect + rects.size();
1046
1047 int lastRowSegmentCount = 0;
1048 Segment *lastRowSegments = 0;
1049
1050 int lastSegment = 0;
1051 int lastY = 0;
1052 while (rect != end) {
1053 const int y = rect[0].y();
1054 int count = 0;
1055 while (&rect[count] != end && rect[count].y() == y)
1056 ++count;
1057
1058 for (int i = 0; i < count; ++i) {
1059 int offset = lastSegment + i;
1060 segments[offset] = Segment(rect[i].topLeft());
1061 segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
1062 segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
1063 segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
1064
1065 offset = lastSegment + i;
1066 for (int j = 0; j < 4; ++j)
1067 segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
1068 }
1069
1070 if (lastRowSegments && lastY == y)
1071 mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
1072
1073 lastRowSegments = &segments[lastSegment + 2 * count];
1074 lastRowSegmentCount = count;
1075 lastSegment += 4 * count;
1076 lastY = y + rect[0].height();
1077 rect += count;
1078 }
1079
1080 for (int i = 0; i < lastSegment; ++i) {
1081 Segment *segment = &segments[i];
1082 if (!segment->added)
1083 addSegmentsToPath(segment, result);
1084 }
1085
1086 return result;
1087}
1088
1089#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
1090
1091//#define QT_REGION_DEBUG
1092/*
1093 * clip region
1094 */
1095
1096struct QRegionPrivate {
1097 int numRects;
1098 QVector<QRect> rects;
1099 QRect extents;
1100 QRect innerRect;
1101 int innerArea;
1102
1103 inline QRegionPrivate() : numRects(0), innerArea(-1) {}
1104 inline QRegionPrivate(const QRect &r) {
1105 numRects = 1;
1106 extents = r;
1107 innerRect = r;
1108 innerArea = r.width() * r.height();
1109 }
1110
1111 inline QRegionPrivate(const QRegionPrivate &r) {
1112 rects = r.rects;
1113 numRects = r.numRects;
1114 extents = r.extents;
1115 innerRect = r.innerRect;
1116 innerArea = r.innerArea;
1117 }
1118
1119 inline QRegionPrivate &operator=(const QRegionPrivate &r) {
1120 rects = r.rects;
1121 numRects = r.numRects;
1122 extents = r.extents;
1123 innerRect = r.innerRect;
1124 innerArea = r.innerArea;
1125 return *this;
1126 }
1127
1128 void intersect(const QRect &r);
1129
1130 /*
1131 * Returns true if r is guaranteed to be fully contained in this region.
1132 * A false return value does not guarantee the opposite.
1133 */
1134 inline bool contains(const QRegionPrivate &r) const {
1135 return contains(r.extents);
1136 }
1137
1138 inline bool contains(const QRect &r2) const {
1139 const QRect &r1 = innerRect;
1140 return r2.left() >= r1.left() && r2.right() <= r1.right()
1141 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1142 }
1143
1144 /*
1145 * Returns true if this region is guaranteed to be fully contained in r.
1146 */
1147 inline bool within(const QRect &r1) const {
1148 const QRect &r2 = extents;
1149 return r2.left() >= r1.left() && r2.right() <= r1.right()
1150 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1151 }
1152
1153 inline void updateInnerRect(const QRect &rect) {
1154 const int area = rect.width() * rect.height();
1155 if (area > innerArea) {
1156 innerArea = area;
1157 innerRect = rect;
1158 }
1159 }
1160
1161 inline void vectorize() {
1162 if (numRects == 1) {
1163 if (!rects.size())
1164 rects.resize(1);
1165 rects[0] = extents;
1166 }
1167 }
1168
1169 inline void append(const QRect *r);
1170 void append(const QRegionPrivate *r);
1171 void prepend(const QRect *r);
1172 void prepend(const QRegionPrivate *r);
1173 inline bool canAppend(const QRect *r) const;
1174 inline bool canAppend(const QRegionPrivate *r) const;
1175 inline bool canPrepend(const QRect *r) const;
1176 inline bool canPrepend(const QRegionPrivate *r) const;
1177
1178 inline bool mergeFromRight(QRect *left, const QRect *right);
1179 inline bool mergeFromLeft(QRect *left, const QRect *right);
1180 inline bool mergeFromBelow(QRect *top, const QRect *bottom,
1181 const QRect *nextToTop,
1182 const QRect *nextToBottom);
1183 inline bool mergeFromAbove(QRect *bottom, const QRect *top,
1184 const QRect *nextToBottom,
1185 const QRect *nextToTop);
1186
1187#ifdef QT_REGION_DEBUG
1188 void selfTest() const;
1189#endif
1190};
1191
1192static inline bool isEmptyHelper(const QRegionPrivate *preg)
1193{
1194 return !preg || preg->numRects == 0;
1195}
1196
1197static inline bool canMergeFromRight(const QRect *left, const QRect *right)
1198{
1199 return (right->top() == left->top()
1200 && right->bottom() == left->bottom()
1201 && right->left() <= (left->right() + 1));
1202}
1203
1204static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
1205{
1206 return canMergeFromRight(left, right);
1207}
1208
1209bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right)
1210{
1211 if (canMergeFromRight(left, right)) {
1212 left->setRight(right->right());
1213 updateInnerRect(*left);
1214 return true;
1215 }
1216 return false;
1217}
1218
1219bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left)
1220{
1221 if (canMergeFromLeft(right, left)) {
1222 right->setLeft(left->left());
1223 updateInnerRect(*right);
1224 return true;
1225 }
1226 return false;
1227}
1228
1229static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom,
1230 const QRect *nextToTop,
1231 const QRect *nextToBottom)
1232{
1233 if (nextToTop && nextToTop->y() == top->y())
1234 return false;
1235 if (nextToBottom && nextToBottom->y() == bottom->y())
1236 return false;
1237
1238 return ((top->bottom() >= (bottom->top() - 1))
1239 && top->left() == bottom->left()
1240 && top->right() == bottom->right());
1241}
1242
1243bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom,
1244 const QRect *nextToTop,
1245 const QRect *nextToBottom)
1246{
1247 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1248 top->setBottom(bottom->bottom());
1249 updateInnerRect(*top);
1250 return true;
1251 }
1252 return false;
1253}
1254
1255bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top,
1256 const QRect *nextToBottom,
1257 const QRect *nextToTop)
1258{
1259 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1260 bottom->setTop(top->top());
1261 updateInnerRect(*bottom);
1262 return true;
1263 }
1264 return false;
1265}
1266
1267static inline QRect qt_rect_intersect_normalized(const QRect &r1,
1268 const QRect &r2)
1269{
1270 QRect r;
1271 r.setLeft(qMax(r1.left(), r2.left()));
1272 r.setRight(qMin(r1.right(), r2.right()));
1273 r.setTop(qMax(r1.top(), r2.top()));
1274 r.setBottom(qMin(r1.bottom(), r2.bottom()));
1275 return r;
1276}
1277
1278void QRegionPrivate::intersect(const QRect &rect)
1279{
1280 Q_ASSERT(extents.intersects(rect));
1281 Q_ASSERT(numRects > 1);
1282
1283#ifdef QT_REGION_DEBUG
1284 selfTest();
1285#endif
1286
1287 const QRect r = rect.normalized();
1288 extents = QRect();
1289 innerRect = QRect();
1290 innerArea = -1;
1291
1292 QRect *dest = rects.data();
1293 const QRect *src = dest;
1294 int n = numRects;
1295 numRects = 0;
1296 while (n--) {
1297 *dest = qt_rect_intersect_normalized(*src++, r);
1298 if (dest->isEmpty())
1299 continue;
1300
1301 if (numRects == 0) {
1302 extents = *dest;
1303 } else {
1304 extents.setLeft(qMin(extents.left(), dest->left()));
1305 // hw: extents.top() will never change after initialization
1306 //extents.setTop(qMin(extents.top(), dest->top()));
1307 extents.setRight(qMax(extents.right(), dest->right()));
1308 extents.setBottom(qMax(extents.bottom(), dest->bottom()));
1309
1310 const QRect *nextToLast = (numRects > 1 ? dest - 2 : 0);
1311
1312 // mergeFromBelow inlined and optimized
1313 if (canMergeFromBelow(dest - 1, dest, nextToLast, 0)) {
1314 if (!n || src->y() != dest->y() || src->left() > r.right()) {
1315 QRect *prev = dest - 1;
1316 prev->setBottom(dest->bottom());
1317 updateInnerRect(*prev);
1318 continue;
1319 }
1320 }
1321 }
1322 updateInnerRect(*dest);
1323 ++dest;
1324 ++numRects;
1325 }
1326#ifdef QT_REGION_DEBUG
1327 selfTest();
1328#endif
1329}
1330
1331void QRegionPrivate::append(const QRect *r)
1332{
1333 Q_ASSERT(!r->isEmpty());
1334
1335 QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
1336 if (mergeFromRight(myLast, r)) {
1337 if (numRects > 1) {
1338 const QRect *nextToTop = (numRects > 2 ? myLast - 2 : 0);
1339 if (mergeFromBelow(myLast - 1, myLast, nextToTop, 0))
1340 --numRects;
1341 }
1342 } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : 0), 0)) {
1343 // nothing
1344 } else {
1345 vectorize();
1346 ++numRects;
1347 updateInnerRect(*r);
1348 if (rects.size() < numRects)
1349 rects.resize(numRects);
1350 rects[numRects - 1] = *r;
1351 }
1352 extents.setCoords(qMin(extents.left(), r->left()),
1353 qMin(extents.top(), r->top()),
1354 qMax(extents.right(), r->right()),
1355 qMax(extents.bottom(), r->bottom()));
1356
1357#ifdef QT_REGION_DEBUG
1358 selfTest();
1359#endif
1360}
1361
1362void QRegionPrivate::append(const QRegionPrivate *r)
1363{
1364 Q_ASSERT(!isEmptyHelper(r));
1365
1366 if (r->numRects == 1) {
1367 append(&r->extents);
1368 return;
1369 }
1370
1371 vectorize();
1372
1373 QRect *destRect = rects.data() + numRects;
1374 const QRect *srcRect = r->rects.constData();
1375 int numAppend = r->numRects;
1376
1377 // try merging
1378 {
1379 const QRect *rFirst = srcRect;
1380 QRect *myLast = destRect - 1;
1381 const QRect *nextToLast = (numRects > 1 ? myLast - 1 : 0);
1382 if (mergeFromRight(myLast, rFirst)) {
1383 ++srcRect;
1384 --numAppend;
1385 const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : 0);
1386 if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) {
1387 ++srcRect;
1388 --numAppend;
1389 }
1390 if (numRects > 1) {
1391 nextToLast = (numRects > 2 ? myLast - 2 : 0);
1392 rNextToFirst = (numAppend > 0 ? srcRect : 0);
1393 if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) {
1394 --destRect;
1395 --numRects;
1396 }
1397 }
1398 } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) {
1399 ++srcRect;
1400 --numAppend;
1401 }
1402 }
1403
1404 // append rectangles
1405 if (numAppend > 0) {
1406 const int newNumRects = numRects + numAppend;
1407 if (newNumRects > rects.size()) {
1408 rects.resize(newNumRects);
1409 destRect = rects.data() + numRects;
1410 }
1411 memcpy(destRect, srcRect, numAppend * sizeof(QRect));
1412
1413 numRects = newNumRects;
1414 }
1415
1416 // update inner rectangle
1417 if (innerArea < r->innerArea) {
1418 innerArea = r->innerArea;
1419 innerRect = r->innerRect;
1420 }
1421
1422 // update extents
1423 destRect = &extents;
1424 srcRect = &r->extents;
1425 extents.setCoords(qMin(destRect->left(), srcRect->left()),
1426 qMin(destRect->top(), srcRect->top()),
1427 qMax(destRect->right(), srcRect->right()),
1428 qMax(destRect->bottom(), srcRect->bottom()));
1429
1430#ifdef QT_REGION_DEBUG
1431 selfTest();
1432#endif
1433}
1434
1435void QRegionPrivate::prepend(const QRegionPrivate *r)
1436{
1437 Q_ASSERT(!isEmptyHelper(r));
1438
1439 if (r->numRects == 1) {
1440 prepend(&r->extents);
1441 return;
1442 }
1443
1444 vectorize();
1445
1446 int numPrepend = r->numRects;
1447 int numSkip = 0;
1448
1449 // try merging
1450 {
1451 QRect *myFirst = rects.data();
1452 const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : 0);
1453 const QRect *rLast = r->rects.constData() + r->numRects - 1;
1454 const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : 0);
1455 if (mergeFromLeft(myFirst, rLast)) {
1456 --numPrepend;
1457 --rLast;
1458 rNextToLast = (numPrepend > 1 ? rLast - 1 : 0);
1459 if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1460 --numPrepend;
1461 --rLast;
1462 }
1463 if (numRects > 1) {
1464 nextToFirst = (numRects > 2? myFirst + 2 : 0);
1465 rNextToLast = (numPrepend > 0 ? rLast : 0);
1466 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) {
1467 --numRects;
1468 ++numSkip;
1469 }
1470 }
1471 } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1472 --numPrepend;
1473 }
1474 }
1475
1476 if (numPrepend > 0) {
1477 const int newNumRects = numRects + numPrepend;
1478 if (newNumRects > rects.size())
1479 rects.resize(newNumRects);
1480
1481 // move existing rectangles
1482 memmove(rects.data() + numPrepend, rects.constData() + numSkip,
1483 numRects * sizeof(QRect));
1484
1485 // prepend new rectangles
1486 memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect));
1487
1488 numRects = newNumRects;
1489 }
1490
1491 // update inner rectangle
1492 if (innerArea < r->innerArea) {
1493 innerArea = r->innerArea;
1494 innerRect = r->innerRect;
1495 }
1496
1497 // update extents
1498 extents.setCoords(qMin(extents.left(), r->extents.left()),
1499 qMin(extents.top(), r->extents.top()),
1500 qMax(extents.right(), r->extents.right()),
1501 qMax(extents.bottom(), r->extents.bottom()));
1502
1503#ifdef QT_REGION_DEBUG
1504 selfTest();
1505#endif
1506}
1507
1508void QRegionPrivate::prepend(const QRect *r)
1509{
1510 Q_ASSERT(!r->isEmpty());
1511
1512 QRect *myFirst = (numRects == 1 ? &extents : rects.data());
1513 if (mergeFromLeft(myFirst, r)) {
1514 if (numRects > 1) {
1515 const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : 0);
1516 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, 0)) {
1517 --numRects;
1518 memmove(rects.data(), rects.constData() + 1,
1519 numRects * sizeof(QRect));
1520 }
1521 }
1522 } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : 0), 0)) {
1523 // nothing
1524 } else {
1525 vectorize();
1526 ++numRects;
1527 updateInnerRect(*r);
1528 rects.prepend(*r);
1529 }
1530 extents.setCoords(qMin(extents.left(), r->left()),
1531 qMin(extents.top(), r->top()),
1532 qMax(extents.right(), r->right()),
1533 qMax(extents.bottom(), r->bottom()));
1534
1535#ifdef QT_REGION_DEBUG
1536 selfTest();
1537#endif
1538}
1539
1540bool QRegionPrivate::canAppend(const QRect *r) const
1541{
1542 Q_ASSERT(!r->isEmpty());
1543
1544 const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
1545 if (r->top() > myLast->bottom())
1546 return true;
1547 if (r->top() == myLast->top()
1548 && r->height() == myLast->height()
1549 && r->left() > myLast->right())
1550 {
1551 return true;
1552 }
1553
1554 return false;
1555}
1556
1557bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
1558{
1559 return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
1560}
1561
1562bool QRegionPrivate::canPrepend(const QRect *r) const
1563{
1564 Q_ASSERT(!r->isEmpty());
1565
1566 const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
1567 if (r->bottom() < myFirst->top()) // not overlapping
1568 return true;
1569 if (r->top() == myFirst->top()
1570 && r->height() == myFirst->height()
1571 && r->right() < myFirst->left())
1572 {
1573 return true;
1574 }
1575
1576 return false;
1577}
1578
1579bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
1580{
1581 return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1);
1582}
1583
1584#ifdef QT_REGION_DEBUG
1585void QRegionPrivate::selfTest() const
1586{
1587 if (numRects == 0) {
1588 Q_ASSERT(extents.isEmpty());
1589 Q_ASSERT(innerRect.isEmpty());
1590 return;
1591 }
1592
1593 Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
1594
1595 if (numRects == 1) {
1596 Q_ASSERT(innerRect == extents);
1597 Q_ASSERT(!innerRect.isEmpty());
1598 return;
1599 }
1600
1601 for (int i = 0; i < numRects; ++i) {
1602 const QRect r = rects.at(i);
1603 if ((r.width() * r.height()) > innerArea)
1604 qDebug() << "selfTest(): innerRect" << innerRect << "<" << r;
1605 }
1606
1607 QRect r = rects.first();
1608 for (int i = 1; i < numRects; ++i) {
1609 const QRect r2 = rects.at(i);
1610 Q_ASSERT(!r2.isEmpty());
1611 if (r2.y() == r.y()) {
1612 Q_ASSERT(r.bottom() == r2.bottom());
1613 Q_ASSERT(r.right() < (r2.left() + 1));
1614 } else {
1615 Q_ASSERT(r2.y() >= r.bottom());
1616 }
1617 r = r2;
1618 }
1619}
1620#endif // QT_REGION_DEBUG
1621
1622#if defined(Q_WS_X11)
1623QT_BEGIN_INCLUDE_NAMESPACE
1624# include "qregion_x11.cpp"
1625QT_END_INCLUDE_NAMESPACE
1626#elif defined(Q_WS_MAC)
1627QT_BEGIN_INCLUDE_NAMESPACE
1628# include "qregion_mac.cpp"
1629QT_END_INCLUDE_NAMESPACE
1630#elif defined(Q_OS_WINCE)
1631QT_BEGIN_INCLUDE_NAMESPACE
1632# include "qregion_wince.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 BOXs overlap.
1714 * 0 if two BOXs 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 1000000
3134#define SMALL_COORDINATE -LARGE_COORDINATE
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 (*SLLBlock)->next = tmpSLLBlock;
3171 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
3172 *SLLBlock = tmpSLLBlock;
3173 *iSLLBlock = 0;
3174 }
3175 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3176
3177 pSLL->next = pPrevSLL->next;
3178 pSLL->edgelist = (EdgeTableEntry *)NULL;
3179 pPrevSLL->next = pSLL;
3180 }
3181 pSLL->scanline = scanline;
3182
3183 /*
3184 * now insert the edge in the right bucket
3185 */
3186 prev = 0;
3187 start = pSLL->edgelist;
3188 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3189 prev = start;
3190 start = start->next;
3191 }
3192 ETE->next = start;
3193
3194 if (prev)
3195 prev->next = ETE;
3196 else
3197 pSLL->edgelist = ETE;
3198}
3199
3200/*
3201 * CreateEdgeTable
3202 *
3203 * This routine creates the edge table for
3204 * scan converting polygons.
3205 * The Edge Table (ET) looks like:
3206 *
3207 * EdgeTable
3208 * --------
3209 * | ymax | ScanLineLists
3210 * |scanline|-->------------>-------------->...
3211 * -------- |scanline| |scanline|
3212 * |edgelist| |edgelist|
3213 * --------- ---------
3214 * | |
3215 * | |
3216 * V V
3217 * list of ETEs list of ETEs
3218 *
3219 * where ETE is an EdgeTableEntry data structure,
3220 * and there is one ScanLineList per scanline at
3221 * which an edge is initially entered.
3222 *
3223 */
3224
3225static void CreateETandAET(register int count, register const QPoint *pts,
3226 EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
3227 ScanLineListBlock *pSLLBlock)
3228{
3229 register const QPoint *top,
3230 *bottom,
3231 *PrevPt,
3232 *CurrPt;
3233 int iSLLBlock = 0;
3234 int dy;
3235
3236 if (count < 2)
3237 return;
3238
3239 /*
3240 * initialize the Active Edge Table
3241 */
3242 AET->next = 0;
3243 AET->back = 0;
3244 AET->nextWETE = 0;
3245 AET->bres.minor_axis = SMALL_COORDINATE;
3246
3247 /*
3248 * initialize the Edge Table.
3249 */
3250 ET->scanlines.next = 0;
3251 ET->ymax = SMALL_COORDINATE;
3252 ET->ymin = LARGE_COORDINATE;
3253 pSLLBlock->next = 0;
3254
3255 PrevPt = &pts[count - 1];
3256
3257 /*
3258 * for each vertex in the array of points.
3259 * In this loop we are dealing with two vertices at
3260 * a time -- these make up one edge of the polygon.
3261 */
3262 while (count--) {
3263 CurrPt = pts++;
3264
3265 /*
3266 * find out which point is above and which is below.
3267 */
3268 if (PrevPt->y() > CurrPt->y()) {
3269 bottom = PrevPt;
3270 top = CurrPt;
3271 pETEs->ClockWise = 0;
3272 } else {
3273 bottom = CurrPt;
3274 top = PrevPt;
3275 pETEs->ClockWise = 1;
3276 }
3277
3278 /*
3279 * don't add horizontal edges to the Edge table.
3280 */
3281 if (bottom->y() != top->y()) {
3282 pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */
3283
3284 /*
3285 * initialize integer edge algorithm
3286 */
3287 dy = bottom->y() - top->y();
3288 BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
3289
3290 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3291
3292 if (PrevPt->y() > ET->ymax)
3293 ET->ymax = PrevPt->y();
3294 if (PrevPt->y() < ET->ymin)
3295 ET->ymin = PrevPt->y();
3296 ++pETEs;
3297 }
3298
3299 PrevPt = CurrPt;
3300 }
3301}
3302
3303/*
3304 * loadAET
3305 *
3306 * This routine moves EdgeTableEntries from the
3307 * EdgeTable into the Active Edge Table,
3308 * leaving them sorted by smaller x coordinate.
3309 *
3310 */
3311
3312static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
3313{
3314 register EdgeTableEntry *pPrevAET;
3315 register EdgeTableEntry *tmp;
3316
3317 pPrevAET = AET;
3318 AET = AET->next;
3319 while (ETEs) {
3320 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3321 pPrevAET = AET;
3322 AET = AET->next;
3323 }
3324 tmp = ETEs->next;
3325 ETEs->next = AET;
3326 if (AET)
3327 AET->back = ETEs;
3328 ETEs->back = pPrevAET;
3329 pPrevAET->next = ETEs;
3330 pPrevAET = ETEs;
3331
3332 ETEs = tmp;
3333 }
3334}
3335
3336/*
3337 * computeWAET
3338 *
3339 * This routine links the AET by the
3340 * nextWETE (winding EdgeTableEntry) link for
3341 * use by the winding number rule. The final
3342 * Active Edge Table (AET) might look something
3343 * like:
3344 *
3345 * AET
3346 * ---------- --------- ---------
3347 * |ymax | |ymax | |ymax |
3348 * | ... | |... | |... |
3349 * |next |->|next |->|next |->...
3350 * |nextWETE| |nextWETE| |nextWETE|
3351 * --------- --------- ^--------
3352 * | | |
3353 * V-------------------> V---> ...
3354 *
3355 */
3356static void computeWAET(register EdgeTableEntry *AET)
3357{
3358 register EdgeTableEntry *pWETE;
3359 register int inside = 1;
3360 register int isInside = 0;
3361
3362 AET->nextWETE = 0;
3363 pWETE = AET;
3364 AET = AET->next;
3365 while (AET) {
3366 if (AET->ClockWise)
3367 ++isInside;
3368 else
3369 --isInside;
3370
3371 if ((!inside && !isInside) || (inside && isInside)) {
3372 pWETE->nextWETE = AET;
3373 pWETE = AET;
3374 inside = !inside;
3375 }
3376 AET = AET->next;
3377 }
3378 pWETE->nextWETE = 0;
3379}
3380
3381/*
3382 * InsertionSort
3383 *
3384 * Just a simple insertion sort using
3385 * pointers and back pointers to sort the Active
3386 * Edge Table.
3387 *
3388 */
3389
3390static int InsertionSort(register EdgeTableEntry *AET)
3391{
3392 register EdgeTableEntry *pETEchase;
3393 register EdgeTableEntry *pETEinsert;
3394 register EdgeTableEntry *pETEchaseBackTMP;
3395 register int changed = 0;
3396
3397 AET = AET->next;
3398 while (AET) {
3399 pETEinsert = AET;
3400 pETEchase = AET;
3401 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3402 pETEchase = pETEchase->back;
3403
3404 AET = AET->next;
3405 if (pETEchase != pETEinsert) {
3406 pETEchaseBackTMP = pETEchase->back;
3407 pETEinsert->back->next = AET;
3408 if (AET)
3409 AET->back = pETEinsert->back;
3410 pETEinsert->next = pETEchase;
3411 pETEchase->back->next = pETEinsert;
3412 pETEchase->back = pETEinsert;
3413 pETEinsert->back = pETEchaseBackTMP;
3414 changed = 1;
3415 }
3416 }
3417 return changed;
3418}
3419
3420/*
3421 * Clean up our act.
3422 */
3423static void FreeStorage(register ScanLineListBlock *pSLLBlock)
3424{
3425 register ScanLineListBlock *tmpSLLBlock;
3426
3427 while (pSLLBlock) {
3428 tmpSLLBlock = pSLLBlock->next;
3429 free(pSLLBlock);
3430 pSLLBlock = tmpSLLBlock;
3431 }
3432}
3433
3434struct QRegionSpan {
3435 QRegionSpan() {}
3436 QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {}
3437
3438 int x1;
3439 int x2;
3440 int width() const { return x2 - x1; }
3441};
3442
3443Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3444
3445static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend)
3446{
3447 QRect *regRects = reg->rects.data() + *lastRow;
3448 bool canExtend = reg->rects.size() - *lastRow == numSpans
3449 && !(*needsExtend && *extendTo + 1 != y)
3450 && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
3451
3452 for (int i = 0; i < numSpans && canExtend; ++i) {
3453 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3454 canExtend = false;
3455 }
3456
3457 if (canExtend) {
3458 *extendTo = y;
3459 *needsExtend = true;
3460 } else {
3461 if (*needsExtend) {
3462 for (int i = 0; i < reg->rects.size() - *lastRow; ++i)
3463 regRects[i].setBottom(*extendTo);
3464 }
3465
3466 *lastRow = reg->rects.size();
3467 reg->rects.reserve(*lastRow + numSpans);
3468 for (int i = 0; i < numSpans; ++i)
3469 reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
3470
3471 if (spans[0].x1 < reg->extents.left())
3472 reg->extents.setLeft(spans[0].x1);
3473
3474 if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3475 reg->extents.setRight(spans[numSpans-1].x2 - 1);
3476
3477 *needsExtend = false;
3478 }
3479}
3480
3481/*
3482 * Create an array of rectangles from a list of points.
3483 * If indeed these things (POINTS, RECTS) are the same,
3484 * then this proc is still needed, because it allocates
3485 * storage for the array, which was allocated on the
3486 * stack by the calling procedure.
3487 *
3488 */
3489static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
3490 POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
3491{
3492 int lastRow = 0;
3493 int extendTo = 0;
3494 bool needsExtend = false;
3495 QVarLengthArray<QRegionSpan> row;
3496 int rowSize = 0;
3497
3498 reg->extents.setLeft(INT_MAX);
3499 reg->extents.setRight(INT_MIN);
3500 reg->innerArea = -1;
3501
3502 POINTBLOCK *CurPtBlock = FirstPtBlock;
3503 for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3504 /* the loop uses 2 points per iteration */
3505 int i = NUMPTSTOBUFFER >> 1;
3506 if (!numFullPtBlocks)
3507 i = iCurPtBlock >> 1;
3508 if(i) {
3509 row.resize(qMax(row.size(), rowSize + i));
3510 for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) {
3511 const int width = pts[1].x() - pts[0].x();
3512 if (width) {
3513 if (rowSize && row[rowSize-1].x2 == pts[0].x())
3514 row[rowSize-1].x2 = pts[1].x();
3515 else
3516 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3517 }
3518
3519 if (rowSize) {
3520 QPoint *next = i ? &pts[2] : (numFullPtBlocks ? CurPtBlock->next->pts : 0);
3521
3522 if (!next || next->y() != pts[0].y()) {
3523 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3524 rowSize = 0;
3525 }
3526 }
3527 }
3528 }
3529 CurPtBlock = CurPtBlock->next;
3530 }
3531
3532 if (needsExtend) {
3533 for (int i = lastRow; i < reg->rects.size(); ++i)
3534 reg->rects[i].setBottom(extendTo);
3535 }
3536
3537 reg->numRects = reg->rects.size();
3538
3539 if (reg->numRects) {
3540 reg->extents.setTop(reg->rects[0].top());
3541 reg->extents.setBottom(reg->rects[lastRow].bottom());
3542
3543 for (int i = 0; i < reg->rects.size(); ++i)
3544 reg->updateInnerRect(reg->rects[i]);
3545 } else {
3546 reg->extents.setCoords(0, 0, 0, 0);
3547 }
3548}
3549
3550/*
3551 * polytoregion
3552 *
3553 * Scan converts a polygon by returning a run-length
3554 * encoding of the resultant bitmap -- the run-length
3555 * encoding is in the form of an array of rectangles.
3556 */
3557static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
3558 //Point *Pts; /* the pts */
3559 //int Count; /* number of pts */
3560 //int rule; /* winding rule */
3561{
3562 QRegionPrivate *region;
3563 register EdgeTableEntry *pAET; /* Active Edge Table */
3564 register int y; /* current scanline */
3565 register int iPts = 0; /* number of pts in buffer */
3566 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
3567 register ScanLineList *pSLL; /* current scanLineList */
3568 register QPoint *pts; /* output buffer */
3569 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
3570 EdgeTable ET; /* header node for ET */
3571 EdgeTableEntry AET; /* header node for AET */
3572 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
3573 ScanLineListBlock SLLBlock; /* header for scanlinelist */
3574 int fixWAET = false;
3575 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
3576 FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
3577 POINTBLOCK *tmpPtBlock;
3578 int numFullPtBlocks = 0;
3579
3580 if (!(region = new QRegionPrivate))
3581 return 0;
3582
3583 /* special case a rectangle */
3584 if (((Count == 4) ||
3585 ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
3586 && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
3587 && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
3588 && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
3589 && (Pts[3].y() == Pts[0].y())))) {
3590 int x = qMin(Pts[0].x(), Pts[2].x());
3591 region->extents.setLeft(x);
3592 int y = qMin(Pts[0].y(), Pts[2].y());
3593 region->extents.setTop(y);
3594 region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
3595 region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
3596 if ((region->extents.left() <= region->extents.right()) &&
3597 (region->extents.top() <= region->extents.bottom())) {
3598 region->numRects = 1;
3599 region->innerRect = region->extents;
3600 region->innerArea = region->innerRect.width() * region->innerRect.height();
3601 }
3602 return region;
3603 }
3604
3605 if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
3606 return 0;
3607
3608 region->vectorize();
3609
3610 pts = FirstPtBlock.pts;
3611 CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
3612
3613 pSLL = ET.scanlines.next;
3614 curPtBlock = &FirstPtBlock;
3615
3616 // sanity check that the region won't become too big...
3617 if (ET.ymax - ET.ymin > 100000) {
3618 // clean up region ptr
3619#ifndef QT_NO_DEBUG
3620 qWarning("QRegion: creating region from big polygon failed...!");
3621#endif
3622 delete region;
3623 return 0;
3624 }
3625
3626
3627 if (rule == EvenOddRule) {
3628 /*
3629 * for each scanline
3630 */
3631 for (y = ET.ymin; y < ET.ymax; ++y) {
3632
3633 /*
3634 * Add a new edge to the active edge table when we
3635 * get to the next edge.
3636 */
3637 if (pSLL && y == pSLL->scanline) {
3638 loadAET(&AET, pSLL->edgelist);
3639 pSLL = pSLL->next;
3640 }
3641 pPrevAET = &AET;
3642 pAET = AET.next;
3643
3644 /*
3645 * for each active edge
3646 */
3647 while (pAET) {
3648 pts->setX(pAET->bres.minor_axis);
3649 pts->setY(y);
3650 ++pts;
3651 ++iPts;
3652
3653 /*
3654 * send out the buffer
3655 */
3656 if (iPts == NUMPTSTOBUFFER) {
3657 tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
3658 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3659 curPtBlock->next = tmpPtBlock;
3660 curPtBlock = tmpPtBlock;
3661 pts = curPtBlock->pts;
3662 ++numFullPtBlocks;
3663 iPts = 0;
3664 }
3665 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
3666 }
3667 InsertionSort(&AET);
3668 }
3669 } else {
3670 /*
3671 * for each scanline
3672 */
3673 for (y = ET.ymin; y < ET.ymax; ++y) {
3674 /*
3675 * Add a new edge to the active edge table when we
3676 * get to the next edge.
3677 */
3678 if (pSLL && y == pSLL->scanline) {
3679 loadAET(&AET, pSLL->edgelist);
3680 computeWAET(&AET);
3681 pSLL = pSLL->next;
3682 }
3683 pPrevAET = &AET;
3684 pAET = AET.next;
3685 pWETE = pAET;
3686
3687 /*
3688 * for each active edge
3689 */
3690 while (pAET) {
3691 /*
3692 * add to the buffer only those edges that
3693 * are in the Winding active edge table.
3694 */
3695 if (pWETE == pAET) {
3696 pts->setX(pAET->bres.minor_axis);
3697 pts->setY(y);
3698 ++pts;
3699 ++iPts;
3700
3701 /*
3702 * send out the buffer
3703 */
3704 if (iPts == NUMPTSTOBUFFER) {
3705 tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
3706 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3707 curPtBlock->next = tmpPtBlock;
3708 curPtBlock = tmpPtBlock;
3709 pts = curPtBlock->pts;
3710 ++numFullPtBlocks;
3711 iPts = 0;
3712 }
3713 pWETE = pWETE->nextWETE;
3714 }
3715 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
3716 }
3717
3718 /*
3719 * recompute the winding active edge table if
3720 * we just resorted or have exited an edge.
3721 */
3722 if (InsertionSort(&AET) || fixWAET) {
3723 computeWAET(&AET);
3724 fixWAET = false;
3725 }
3726 }
3727 }
3728 FreeStorage(SLLBlock.next);
3729 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3730 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3731 tmpPtBlock = curPtBlock->next;
3732 free(curPtBlock);
3733 curPtBlock = tmpPtBlock;
3734 }
3735 free(pETEs);
3736 return region;
3737}
3738// END OF PolyReg.c extract
3739
3740QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
3741{
3742 QImage image = bitmap.toImage();
3743
3744 QRegionPrivate *region = new QRegionPrivate;
3745
3746 QRect xr;
3747
3748#define AddSpan \
3749 { \
3750 xr.setCoords(prev1, y, x-1, y); \
3751 UnionRectWithRegion(&xr, region, *region); \
3752 }
3753
3754 const uchar zero = 0;
3755 bool little = image.format() == QImage::Format_MonoLSB;
3756
3757 int x,
3758 y;
3759 for (y = 0; y < image.height(); ++y) {
3760 uchar *line = image.scanLine(y);
3761 int w = image.width();
3762 uchar all = zero;
3763 int prev1 = -1;
3764 for (x = 0; x < w;) {
3765 uchar byte = line[x / 8];
3766 if (x > w - 8 || byte!=all) {
3767 if (little) {
3768 for (int b = 8; b > 0 && x < w; --b) {
3769 if (!(byte & 0x01) == !all) {
3770 // More of the same
3771 } else {
3772 // A change.
3773 if (all!=zero) {
3774 AddSpan
3775 all = zero;
3776 } else {
3777 prev1 = x;
3778 all = ~zero;
3779 }
3780 }
3781 byte >>= 1;
3782 ++x;
3783 }
3784 } else {
3785 for (int b = 8; b > 0 && x < w; --b) {
3786 if (!(byte & 0x80) == !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 }
3802 } else {
3803 x += 8;
3804 }
3805 }
3806 if (all != zero) {
3807 AddSpan
3808 }
3809 }
3810#undef AddSpan
3811
3812 return region;
3813}
3814
3815QRegion::QRegion()
3816 : d(&shared_empty)
3817{
3818 d->ref.ref();
3819}
3820
3821QRegion::QRegion(const QRect &r, RegionType t)
3822{
3823 if (r.isEmpty()) {
3824 d = &shared_empty;
3825 d->ref.ref();
3826 } else {
3827 d = new QRegionData;
3828 d->ref = 1;
3829#if defined(Q_WS_X11)
3830 d->rgn = 0;
3831 d->xrectangles = 0;
3832#elif defined(Q_OS_WINCE)
3833 d->rgn = 0;
3834#endif
3835 if (t == Rectangle) {
3836 d->qt_rgn = new QRegionPrivate(r);
3837 } else if (t == Ellipse) {
3838 QPainterPath path;
3839 path.addEllipse(r.x(), r.y(), r.width(), r.height());
3840 QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
3841 d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
3842 }
3843 }
3844}
3845
3846QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
3847{
3848 if (a.count() > 2) {
3849 d = new QRegionData;
3850 d->ref = 1;
3851#if defined(Q_WS_X11)
3852 d->rgn = 0;
3853 d->xrectangles = 0;
3854#elif defined(Q_OS_WINCE)
3855 d->rgn = 0;
3856#endif
3857 d->qt_rgn = PolygonRegion(a.constData(), a.size(),
3858 fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
3859 } else {
3860 d = &shared_empty;
3861 d->ref.ref();
3862 }
3863}
3864
3865
3866QRegion::QRegion(const QRegion &r)
3867{
3868 d = r.d;
3869 d->ref.ref();
3870}
3871
3872
3873QRegion::QRegion(const QBitmap &bm)
3874{
3875 if (bm.isNull()) {
3876 d = &shared_empty;
3877 d->ref.ref();
3878 } else {
3879 d = new QRegionData;
3880 d->ref = 1;
3881#if defined(Q_WS_X11)
3882 d->rgn = 0;
3883 d->xrectangles = 0;
3884#elif defined(Q_OS_WINCE)
3885 d->rgn = 0;
3886#endif
3887 d->qt_rgn = qt_bitmapToRegion(bm);
3888 }
3889}
3890
3891void QRegion::cleanUp(QRegion::QRegionData *x)
3892{
3893 delete x->qt_rgn;
3894#if defined(Q_WS_X11)
3895 if (x->rgn)
3896 XDestroyRegion(x->rgn);
3897 if (x->xrectangles)
3898 free(x->xrectangles);
3899#elif defined(Q_OS_WINCE)
3900 if (x->rgn)
3901 qt_win_dispose_rgn(x->rgn);
3902#endif
3903 delete x;
3904}
3905
3906QRegion::~QRegion()
3907{
3908 if (!d->ref.deref())
3909 cleanUp(d);
3910}
3911
3912
3913QRegion &QRegion::operator=(const QRegion &r)
3914{
3915 r.d->ref.ref();
3916 if (!d->ref.deref())
3917 cleanUp(d);
3918 d = r.d;
3919 return *this;
3920}
3921
3922
3923/*!
3924 \internal
3925*/
3926
3927QRegion QRegion::copy() const
3928{
3929 QRegion r;
3930 QRegionData *x = new QRegionData;
3931 x->ref = 1;
3932#if defined(Q_WS_X11)
3933 x->rgn = 0;
3934 x->xrectangles = 0;
3935#elif defined(Q_OS_WINCE)
3936 x->rgn = 0;
3937#endif
3938 if (d->qt_rgn)
3939 x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
3940 else
3941 x->qt_rgn = new QRegionPrivate;
3942 if (!r.d->ref.deref())
3943 cleanUp(r.d);
3944 r.d = x;
3945 return r;
3946}
3947
3948bool QRegion::isEmpty() const
3949{
3950 return d == &shared_empty || d->qt_rgn->numRects == 0;
3951}
3952
3953
3954bool QRegion::contains(const QPoint &p) const
3955{
3956 return PointInRegion(d->qt_rgn, p.x(), p.y());
3957}
3958
3959bool QRegion::contains(const QRect &r) const
3960{
3961 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
3962}
3963
3964
3965
3966void QRegion::translate(int dx, int dy)
3967{
3968 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
3969 return;
3970
3971 detach();
3972 OffsetRegion(*d->qt_rgn, dx, dy);
3973}
3974
3975QRegion QRegion::unite(const QRegion &r) const
3976{
3977 if (isEmptyHelper(d->qt_rgn))
3978 return r;
3979 if (isEmptyHelper(r.d->qt_rgn))
3980 return *this;
3981 if (d == r.d)
3982 return *this;
3983
3984 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3985 return *this;
3986 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3987 return r;
3988 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3989 QRegion result(*this);
3990 result.detach();
3991 result.d->qt_rgn->append(r.d->qt_rgn);
3992 return result;
3993 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3994 QRegion result(*this);
3995 result.detach();
3996 result.d->qt_rgn->prepend(r.d->qt_rgn);
3997 return result;
3998 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3999 return *this;
4000 } else {
4001 QRegion result;
4002 result.detach();
4003 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4004 return result;
4005 }
4006}
4007
4008QRegion& QRegion::operator+=(const QRegion &r)
4009{
4010 if (isEmptyHelper(d->qt_rgn))
4011 return *this = r;
4012 if (isEmptyHelper(r.d->qt_rgn))
4013 return *this;
4014 if (d == r.d)
4015 return *this;
4016
4017 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
4018 return *this;
4019 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
4020 return *this = r;
4021 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
4022 detach();
4023 d->qt_rgn->append(r.d->qt_rgn);
4024 return *this;
4025 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
4026 detach();
4027 d->qt_rgn->prepend(r.d->qt_rgn);
4028 return *this;
4029 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4030 return *this;
4031 } else {
4032 detach();
4033 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
4034 return *this;
4035 }
4036}
4037
4038QRegion QRegion::unite(const QRect &r) const
4039{
4040 if (isEmptyHelper(d->qt_rgn))
4041 return r;
4042 if (r.isEmpty())
4043 return *this;
4044
4045 if (d->qt_rgn->contains(r)) {
4046 return *this;
4047 } else if (d->qt_rgn->within(r)) {
4048 return r;
4049 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4050 return *this;
4051 } else if (d->qt_rgn->canAppend(&r)) {
4052 QRegion result(*this);
4053 result.detach();
4054 result.d->qt_rgn->append(&r);
4055 return result;
4056 } else if (d->qt_rgn->canPrepend(&r)) {
4057 QRegion result(*this);
4058 result.detach();
4059 result.d->qt_rgn->prepend(&r);
4060 return result;
4061 } else {
4062 QRegion result;
4063 result.detach();
4064 QRegionPrivate rp(r);
4065 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4066 return result;
4067 }
4068}
4069
4070QRegion& QRegion::operator+=(const QRect &r)
4071{
4072 if (isEmptyHelper(d->qt_rgn))
4073 return *this = r;
4074 if (r.isEmpty())
4075 return *this;
4076
4077 if (d->qt_rgn->contains(r)) {
4078 return *this;
4079 } else if (d->qt_rgn->within(r)) {
4080 return *this = r;
4081 } else if (d->qt_rgn->canAppend(&r)) {
4082 detach();
4083 d->qt_rgn->append(&r);
4084 return *this;
4085 } else if (d->qt_rgn->canPrepend(&r)) {
4086 detach();
4087 d->qt_rgn->prepend(&r);
4088 return *this;
4089 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4090 return *this;
4091 } else {
4092 detach();
4093 QRegionPrivate p(r);
4094 UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4095 return *this;
4096 }
4097}
4098
4099QRegion QRegion::intersect(const QRegion &r) const
4100{
4101 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4102 || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4103 return QRegion();
4104
4105 /* this is fully contained in r */
4106 if (r.d->qt_rgn->contains(*d->qt_rgn))
4107 return *this;
4108
4109 /* r is fully contained in this */
4110 if (d->qt_rgn->contains(*r.d->qt_rgn))
4111 return r;
4112
4113 if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
4114 const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
4115 d->qt_rgn->extents);
4116 return QRegion(rect);
4117 } else if (r.d->qt_rgn->numRects == 1) {
4118 QRegion result(*this);
4119 result.detach();
4120 result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4121 return result;
4122 } else if (d->qt_rgn->numRects == 1) {
4123 QRegion result(r);
4124 result.detach();
4125 result.d->qt_rgn->intersect(d->qt_rgn->extents);
4126 return result;
4127 }
4128
4129 QRegion result;
4130 result.detach();
4131 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
4132
4133 /*
4134 * Can't alter dest's extents before we call miRegionOp because
4135 * it might be one of the source regions and miRegionOp depends
4136 * on the extents of those regions being the same. Besides, this
4137 * way there's no checking against rectangles that will be nuked
4138 * due to coalescing, so we have to examine fewer rectangles.
4139 */
4140 miSetExtents(*result.d->qt_rgn);
4141 return result;
4142}
4143
4144QRegion QRegion::intersect(const QRect &r) const
4145{
4146 if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4147 || !EXTENTCHECK(&d->qt_rgn->extents, &r))
4148 return QRegion();
4149
4150 /* this is fully contained in r */
4151 if (d->qt_rgn->within(r))
4152 return *this;
4153
4154 /* r is fully contained in this */
4155 if (d->qt_rgn->contains(r))
4156 return r;
4157
4158 if (d->qt_rgn->numRects == 1) {
4159 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4160 r.normalized());
4161 return QRegion(rect);
4162 }
4163
4164 QRegion result(*this);
4165 result.detach();
4166 result.d->qt_rgn->intersect(r);
4167 return result;
4168}
4169
4170QRegion QRegion::subtract(const QRegion &r) const
4171{
4172 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4173 return *this;
4174 if (r.d->qt_rgn->contains(*d->qt_rgn))
4175 return QRegion();
4176 if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4177 return *this;
4178 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4179 return QRegion();
4180
4181#ifdef QT_REGION_DEBUG
4182 d->qt_rgn->selfTest();
4183 r.d->qt_rgn->selfTest();
4184#endif
4185
4186 QRegion result;
4187 result.detach();
4188 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4189#ifdef QT_REGION_DEBUG
4190 result.d->qt_rgn->selfTest();
4191#endif
4192 return result;
4193}
4194
4195QRegion QRegion::eor(const QRegion &r) const
4196{
4197 if (isEmptyHelper(d->qt_rgn)) {
4198 return r;
4199 } else if (isEmptyHelper(r.d->qt_rgn)) {
4200 return *this;
4201 } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4202 return (*this + r);
4203 } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4204 return QRegion();
4205 } else {
4206 QRegion result;
4207 result.detach();
4208 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4209 return result;
4210 }
4211}
4212
4213QRect QRegion::boundingRect() const
4214{
4215 if (isEmpty())
4216 return QRect();
4217 return d->qt_rgn->extents;
4218}
4219
4220/*! \internal
4221 Returns true if \a rect is guaranteed to be fully contained in \a region.
4222 A false return value does not guarantee the opposite.
4223*/
4224#ifdef Q_WS_QWS
4225Q_GUI_EXPORT
4226#endif
4227bool qt_region_strictContains(const QRegion &region, const QRect &rect)
4228{
4229 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4230 return false;
4231
4232#if 0 // TEST_INNERRECT
4233 static bool guard = false;
4234 if (guard)
4235 return false;
4236 guard = true;
4237 QRegion inner = region.d->qt_rgn->innerRect;
4238 Q_ASSERT((inner - region).isEmpty());
4239 guard = false;
4240
4241 int maxArea = 0;
4242 for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
4243 const QRect r = region.d->qt_rgn->rects.at(i);
4244 if (r.width() * r.height() > maxArea)
4245 maxArea = r.width() * r.height();
4246 }
4247
4248 if (maxArea > region.d->qt_rgn->innerArea) {
4249 qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
4250 }
4251 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
4252#endif
4253
4254 const QRect r1 = region.d->qt_rgn->innerRect;
4255 return (rect.left() >= r1.left() && rect.right() <= r1.right()
4256 && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
4257}
4258
4259QVector<QRect> QRegion::rects() const
4260{
4261 if (d->qt_rgn) {
4262 d->qt_rgn->vectorize();
4263 // hw: modify the vector size directly to avoid reallocation
4264 d->qt_rgn->rects.d->size = d->qt_rgn->numRects;
4265 return d->qt_rgn->rects;
4266 } else {
4267 return QVector<QRect>();
4268 }
4269}
4270
4271void QRegion::setRects(const QRect *rects, int num)
4272{
4273 *this = QRegion();
4274 if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
4275 return;
4276
4277 detach();
4278
4279 d->qt_rgn->numRects = num;
4280 if (num == 1) {
4281 d->qt_rgn->extents = *rects;
4282 d->qt_rgn->innerRect = *rects;
4283 } else {
4284 d->qt_rgn->rects.resize(num);
4285
4286 int left = INT_MAX,
4287 right = INT_MIN,
4288 top = INT_MAX,
4289 bottom = INT_MIN;
4290 for (int i = 0; i < num; ++i) {
4291 const QRect &rect = rects[i];
4292 d->qt_rgn->rects[i] = rect;
4293 left = qMin(rect.left(), left);
4294 right = qMax(rect.right(), right);
4295 top = qMin(rect.top(), top);
4296 bottom = qMax(rect.bottom(), bottom);
4297 d->qt_rgn->updateInnerRect(rect);
4298 }
4299 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4300 }
4301}
4302
4303int QRegion::numRects() const
4304{
4305 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4306}
4307
4308bool QRegion::operator==(const QRegion &r) const
4309{
4310 if (!d->qt_rgn)
4311 return r.isEmpty();
4312 if (!r.d->qt_rgn)
4313 return isEmpty();
4314
4315 if (d == r.d)
4316 return true;
4317 else
4318 return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4319}
4320
4321#endif
4322QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.