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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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