1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include "qpainterpath.h"
46 #include "qdatastream.h"
48 #include "qvarlengtharray.h"
58 \brief The QRegion class specifies a clip region for a painter.
63 QRegion is used with QPainter::setClipRegion() to limit the paint
64 area to what needs to be painted. There is also a QWidget::repaint()
65 function that takes a QRegion parameter. QRegion is the best tool for
66 minimizing the amount of screen area to be updated by a repaint.
68 This class is not suitable for constructing shapes for rendering, especially
69 as outlines. Use QPainterPath to create paths and shapes for use with
72 QRegion is an \l{implicitly shared} class.
74 \section1 Creating and Using Regions
76 A region can be created from a rectangle, an ellipse, a polygon or
77 a bitmap. Complex regions may be created by combining simple
78 regions using united(), intersected(), subtracted(), or xored() (exclusive
79 or). You can move a region using translate().
81 You can test whether a region isEmpty() or if it
82 contains() a QPoint or QRect. The bounding rectangle can be found
85 The function rects() gives a decomposition of the region into
88 Example of using complex regions:
89 \snippet doc/src/snippets/code/src_gui_painting_qregion.cpp 0
91 \section1 Additional License Information
93 On Embedded Linux, Windows CE and X11 platforms, parts of this class rely on
94 code obtained under the following licenses:
97 Copyright (c) 1987 X Consortium
99 Permission is hereby granted, free of charge, to any person obtaining a copy
100 of this software and associated documentation files (the "Software"), to deal
101 in the Software without restriction, including without limitation the rights
102 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
103 copies of the Software, and to permit persons to whom the Software is
104 furnished to do so, subject to the following conditions:
106 The above copyright notice and this permission notice shall be included in
107 all copies or substantial portions of the Software.
109 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
110 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
112 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
113 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
114 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
116 Except as contained in this notice, the name of the X Consortium shall not be
117 used in advertising or otherwise to promote the sale, use or other dealings
118 in this Software without prior written authorization from the X Consortium.
124 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
128 Permission to use, copy, modify, and distribute this software and its
129 documentation for any purpose and without fee is hereby granted,
130 provided that the above copyright notice appear in all copies and that
131 both that copyright notice and this permission notice appear in
132 supporting documentation, and that the name of Digital not be
133 used in advertising or publicity pertaining to distribution of the
134 software without specific, written prior permission.
136 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
137 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
138 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
139 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
140 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
141 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
145 \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
150 \enum QRegion::RegionType
152 Specifies the shape of the region to be created.
154 \value Rectangle the region covers the entire rectangle.
155 \value Ellipse the region is an ellipse inside the rectangle.
159 \fn void QRegion::translate(const QPoint &point)
163 Translates the region \a{point}\e{.x()} along the x axis and
164 \a{point}\e{.y()} along the y axis, relative to the current
165 position. Positive values move the region to the right and down.
167 Translates to the given \a point.
171 \fn Handle QRegion::handle() const
173 Returns a platform-specific region handle. The \c Handle type is
174 \c HRGN on Windows, \c Region on X11, and \c RgnHandle on Mac OS
175 X. On \l{Qt for Embedded Linux} it is \c {void *}.
177 \warning This function is not portable.
180 /*****************************************************************************
181 QRegion member functions
182 *****************************************************************************/
185 \fn QRegion::QRegion()
187 Constructs an empty region.
193 \fn QRegion::QRegion(const QRect &r, RegionType t)
196 Create a region based on the rectange \a r with region type \a t.
198 If the rectangle is invalid a null region will be created.
200 \sa QRegion::RegionType
204 \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
206 Constructs a polygon region from the point array \a a with the fill rule
207 specified by \a fillRule.
209 If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
210 using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
213 \warning This constructor can be used to create complex regions that will
214 slow down painting when used.
218 \fn QRegion::QRegion(const QRegion &r)
220 Constructs a new region which is equal to region \a r.
224 \fn QRegion::QRegion(const QBitmap &bm)
226 Constructs a region from the bitmap \a bm.
228 The resulting region consists of the pixels in bitmap \a bm that
229 are Qt::color1, as if each pixel was a 1 by 1 rectangle.
231 This constructor may create complex regions that will slow down
232 painting when used. Note that drawing masked pixmaps can be done
233 much faster using QPixmap::setMask().
237 Constructs a rectangular or elliptic region.
239 If \a t is \c Rectangle, the region is the filled rectangle (\a x,
240 \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled
241 ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size
244 QRegion::QRegion(int x, int y, int w, int h, RegionType t)
246 QRegion tmp(QRect(x, y, w, h), t);
252 \fn QRegion::~QRegion()
258 void QRegion::detach()
260 if (d->ref.load() != 1)
264 // duplicates in qregion_win.cpp and qregion_wce.cpp
265 #define QRGN_SETRECT 1 // region stream commands
266 #define QRGN_SETELLIPSE 2 // (these are internal)
267 #define QRGN_SETPTARRAY_ALT 3
268 #define QRGN_SETPTARRAY_WIND 4
269 #define QRGN_TRANSLATE 5
274 #define QRGN_RECTS 10
277 #ifndef QT_NO_DATASTREAM
280 Executes region commands in the internal buffer and rebuilds the
283 We do this when we read a region from the data stream.
285 If \a ver is non-0, uses the format version \a ver on reading the
288 void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
290 QByteArray copy = buffer;
291 QDataStream s(©, QIODevice::ReadOnly);
294 s.setByteOrder(byteOrder);
301 if (s.version() == 1) {
309 if (test_cnt > 0 && id != QRGN_TRANSLATE)
310 qWarning("QRegion::exec: Internal error");
313 if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
316 rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
317 } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
320 rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
321 } else if (id == QRGN_TRANSLATE) {
324 rgn.translate(p.x(), p.y());
325 } else if (id >= QRGN_OR && id <= QRGN_XOR) {
326 QByteArray bop1, bop2;
338 rgn = r1.intersected(r2);
341 rgn = r1.subtracted(r2);
347 } else if (id == QRGN_RECTS) {
348 // (This is the only form used in Qt 2.0)
352 for (int i=0; i<(int)n; i++) {
354 rgn = rgn.united(QRegion(r));
362 /*****************************************************************************
363 QRegion stream functions
364 *****************************************************************************/
367 \fn QRegion &QRegion::operator=(const QRegion &r)
369 Assigns \a r to this region and returns a reference to the region.
373 \fn void QRegion::swap(QRegion &other)
376 Swaps region \a other with this region. This operation is very
377 fast and never fails.
383 Writes the region \a r to the stream \a s and returns a reference
386 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
389 QDataStream &operator<<(QDataStream &s, const QRegion &r)
391 QVector<QRect> a = r.rects();
395 if (s.version() == 1) {
397 for (i = a.size() - 1; i > 0; --i) {
398 s << (quint32)(12 + i * 24);
401 for (i = 0; i < a.size(); ++i) {
402 s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i];
405 s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect
406 s << (qint32)QRGN_RECTS;
416 Reads a region from the stream \a s into \a r and returns a
417 reference to the stream.
419 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
422 QDataStream &operator>>(QDataStream &s, QRegion &r)
426 r.exec(b, s.version(), s.byteOrder());
429 #endif //QT_NO_DATASTREAM
431 #ifndef QT_NO_DEBUG_STREAM
432 QDebug operator<<(QDebug s, const QRegion &r)
434 QVector<QRect> rects = r.rects();
435 s.nospace() << "QRegion(size=" << rects.size() << "), "
436 << "bounds = " << r.boundingRect() << '\n';
437 for (int i=0; i<rects.size(); ++i)
438 s << "- " << i << rects.at(i) << '\n';
444 // These are not inline - they can be implemented better on some platforms
445 // (eg. Windows at least provides 3-variable operations). For now, simple.
449 Applies the united() function to this region and \a r. \c r1|r2 is
450 equivalent to \c r1.united(r2).
452 \sa united(), operator+()
454 const QRegion QRegion::operator|(const QRegion &r) const
455 { return united(r); }
458 Applies the united() function to this region and \a r. \c r1+r2 is
459 equivalent to \c r1.united(r2).
461 \sa united(), operator|()
463 const QRegion QRegion::operator+(const QRegion &r) const
464 { return united(r); }
470 const QRegion QRegion::operator+(const QRect &r) const
471 { return united(r); }
474 Applies the intersected() function to this region and \a r. \c r1&r2
475 is equivalent to \c r1.intersected(r2).
479 const QRegion QRegion::operator&(const QRegion &r) const
480 { return intersected(r); }
486 const QRegion QRegion::operator&(const QRect &r) const
488 return intersected(r);
492 Applies the subtracted() function to this region and \a r. \c r1-r2
493 is equivalent to \c r1.subtracted(r2).
497 const QRegion QRegion::operator-(const QRegion &r) const
498 { return subtracted(r); }
501 Applies the xored() function to this region and \a r. \c r1^r2 is
502 equivalent to \c r1.xored(r2).
506 const QRegion QRegion::operator^(const QRegion &r) const
510 Applies the united() function to this region and \a r and assigns
511 the result to this region. \c r1|=r2 is equivalent to \c
512 {r1 = r1.united(r2)}.
516 QRegion& QRegion::operator|=(const QRegion &r)
517 { return *this = *this | r; }
520 \fn QRegion& QRegion::operator+=(const QRect &rect)
522 Returns a region that is the union of this region with the specified \a rect.
527 \fn QRegion& QRegion::operator+=(const QRegion &r)
529 Applies the united() function to this region and \a r and assigns
530 the result to this region. \c r1+=r2 is equivalent to \c
531 {r1 = r1.united(r2)}.
535 #if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN)
536 QRegion& QRegion::operator+=(const QRect &r)
538 return operator+=(QRegion(r));
543 \fn QRegion& QRegion::operator&=(const QRegion &r)
545 Applies the intersected() function to this region and \a r and
546 assigns the result to this region. \c r1&=r2 is equivalent to \c
547 r1 = r1.intersected(r2).
551 QRegion& QRegion::operator&=(const QRegion &r)
552 { return *this = *this & r; }
558 #if defined (Q_OS_UNIX) || defined (Q_OS_WIN)
559 QRegion& QRegion::operator&=(const QRect &r)
561 return *this = *this & r;
564 QRegion& QRegion::operator&=(const QRect &r)
566 return *this &= (QRegion(r));
571 \fn QRegion& QRegion::operator-=(const QRegion &r)
573 Applies the subtracted() function to this region and \a r and
574 assigns the result to this region. \c r1-=r2 is equivalent to \c
575 {r1 = r1.subtracted(r2)}.
579 QRegion& QRegion::operator-=(const QRegion &r)
580 { return *this = *this - r; }
583 Applies the xored() function to this region and \a r and
584 assigns the result to this region. \c r1^=r2 is equivalent to \c
589 QRegion& QRegion::operator^=(const QRegion &r)
590 { return *this = *this ^ r; }
593 \fn bool QRegion::operator!=(const QRegion &other) const
595 Returns true if this region is different from the \a other region;
596 otherwise returns false.
600 Returns the region as a QVariant
602 QRegion::operator QVariant() const
604 return QVariant(QVariant::Region, this);
608 \fn bool QRegion::operator==(const QRegion &r) const
610 Returns true if the region is equal to \a r; otherwise returns
615 \fn void QRegion::translate(int dx, int dy)
617 Translates (moves) the region \a dx along the X axis and \a dy
622 \fn QRegion QRegion::translated(const QPoint &p) const
626 Returns a copy of the regtion that is translated \a{p}\e{.x()}
627 along the x axis and \a{p}\e{.y()} along the y axis, relative to
628 the current position. Positive values move the rectangle to the
637 Returns a copy of the region that is translated \a dx along the
638 x axis and \a dy along the y axis, relative to the current
639 position. Positive values move the region to the right and
646 QRegion::translated(int dx, int dy) const
649 ret.translate(dx, dy);
654 inline bool rect_intersects(const QRect &r1, const QRect &r2)
656 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
657 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
663 Returns true if this region intersects with \a region, otherwise
666 bool QRegion::intersects(const QRegion ®ion) const
668 if (isEmpty() || region.isEmpty())
671 if (!rect_intersects(boundingRect(), region.boundingRect()))
673 if (rectCount() == 1 && region.rectCount() == 1)
676 const QVector<QRect> myRects = rects();
677 const QVector<QRect> otherRects = region.rects();
679 for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1)
680 for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2)
681 if (rect_intersects(*i1, *i2))
687 \fn bool QRegion::intersects(const QRect &rect) const
690 Returns true if this region intersects with \a rect, otherwise
695 #if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN)
700 QRegion QRegion::intersect(const QRect &r) const
702 return intersect(QRegion(r));
708 \fn int QRegion::numRects() const
711 Returns the number of rectangles that will be returned in rects().
715 \fn int QRegion::rectCount() const
718 Returns the number of rectangles that will be returned in rects().
722 \fn bool QRegion::isEmpty() const
724 Returns true if the region is empty; otherwise returns false. An
725 empty region is a region that contains no points.
728 \snippet doc/src/snippets/code/src_gui_painting_qregion_unix.cpp 0
732 \fn bool QRegion::isNull() const
735 Returns true if the region is empty; otherwise returns false. An
736 empty region is a region that contains no points. This function is
743 \fn bool QRegion::contains(const QPoint &p) const
745 Returns true if the region contains the point \a p; otherwise
750 \fn bool QRegion::contains(const QRect &r) const
753 Returns true if the region overlaps the rectangle \a r; otherwise
758 \fn QRegion QRegion::unite(const QRegion &r) const
761 Use united(\a r) instead.
765 \fn QRegion QRegion::unite(const QRect &rect) const
769 Use united(\a rect) instead.
773 \fn QRegion QRegion::united(const QRect &rect) const
776 Returns a region which is the union of this region and the given \a rect.
778 \sa intersected(), subtracted(), xored()
782 \fn QRegion QRegion::united(const QRegion &r) const
785 Returns a region which is the union of this region and \a r.
787 \img runion.png Region Union
789 The figure shows the union of two elliptical regions.
791 \sa intersected(), subtracted(), xored()
795 \fn QRegion QRegion::intersect(const QRegion &r) const
798 Use intersected(\a r) instead.
802 \fn QRegion QRegion::intersect(const QRect &rect) const
806 Use intersected(\a rect) instead.
810 \fn QRegion QRegion::intersected(const QRect &rect) const
813 Returns a region which is the intersection of this region and the given \a rect.
815 \sa subtracted(), united(), xored()
819 \fn QRegion QRegion::intersected(const QRegion &r) const
822 Returns a region which is the intersection of this region and \a r.
824 \img rintersect.png Region Intersection
826 The figure shows the intersection of two elliptical regions.
828 \sa subtracted(), united(), xored()
832 \fn QRegion QRegion::subtract(const QRegion &r) const
835 Use subtracted(\a r) instead.
839 \fn QRegion QRegion::subtracted(const QRegion &r) const
842 Returns a region which is \a r subtracted from this region.
844 \img rsubtract.png Region Subtraction
846 The figure shows the result when the ellipse on the right is
847 subtracted from the ellipse on the left (\c {left - right}).
849 \sa intersected(), united(), xored()
853 \fn QRegion QRegion::eor(const QRegion &r) const
856 Use xored(\a r) instead.
860 \fn QRegion QRegion::xored(const QRegion &r) const
863 Returns a region which is the exclusive or (XOR) of this region
866 \img rxor.png Region XORed
868 The figure shows the exclusive or of two elliptical regions.
870 \sa intersected(), united(), subtracted()
874 \fn QRect QRegion::boundingRect() const
876 Returns the bounding rectangle of this region. An empty region
877 gives a rectangle that is QRect::isNull().
881 \fn QVector<QRect> QRegion::rects() const
883 Returns an array of non-overlapping rectangles that make up the
886 The union of all the rectangles is equal to the original region.
890 \fn void QRegion::setRects(const QRect *rects, int number)
892 Sets the region using the array of rectangles specified by \a rects and
894 The rectangles \e must be optimally Y-X sorted and follow these restrictions:
897 \o The rectangles must not intersect.
898 \o All rectangles with a given top coordinate must have the same height.
899 \o No two rectangles may abut horizontally (they should be combined
900 into a single wider rectangle in that case).
901 \o The rectangles must be sorted in ascending order, with Y as the major
902 sort key and X as the minor sort key.
905 Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X).
914 Segment(const QPoint &p)
922 return qMin(point.x(), next->point.x());
927 return qMax(point.x(), next->point.x());
930 bool overlaps(const Segment &other) const
932 return left() < other.right() && other.left() < right();
935 void connect(Segment &other)
940 horizontal = (point.y() == other.point.y());
943 void merge(Segment &other)
945 if (right() <= other.right()) {
946 QPoint p = other.point;
947 Segment *oprev = other.prev;
957 Segment *onext = other.next;
974 void mergeSegments(Segment *a, int na, Segment *b, int nb)
979 while (i != na && j != nb) {
982 const int ra = sa.right();
983 const int rb = sb.right();
991 void addSegmentsToPath(Segment *segment, QPainterPath &path)
993 Segment *current = segment;
994 path.moveTo(current->point);
996 current->added = true;
998 Segment *last = current;
999 current = current->next;
1000 while (current != segment) {
1001 if (current->horizontal != last->horizontal)
1002 path.lineTo(current->point);
1003 current->added = true;
1005 current = current->next;
1011 Q_GUI_EXPORT QPainterPath qt_regionToPath(const QRegion ®ion)
1013 QPainterPath result;
1014 if (region.rectCount() == 1) {
1015 result.addRect(region.boundingRect());
1019 const QVector<QRect> rects = region.rects();
1021 QVarLengthArray<Segment> segments;
1022 segments.resize(4 * rects.size());
1024 const QRect *rect = rects.constData();
1025 const QRect *end = rect + rects.size();
1027 int lastRowSegmentCount = 0;
1028 Segment *lastRowSegments = 0;
1030 int lastSegment = 0;
1032 while (rect != end) {
1033 const int y = rect[0].y();
1035 while (&rect[count] != end && rect[count].y() == y)
1038 for (int i = 0; i < count; ++i) {
1039 int offset = lastSegment + i;
1040 segments[offset] = Segment(rect[i].topLeft());
1041 segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
1042 segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
1043 segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
1045 offset = lastSegment + i;
1046 for (int j = 0; j < 4; ++j)
1047 segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
1050 if (lastRowSegments && lastY == y)
1051 mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
1053 lastRowSegments = &segments[lastSegment + 2 * count];
1054 lastRowSegmentCount = count;
1055 lastSegment += 4 * count;
1056 lastY = y + rect[0].height();
1060 for (int i = 0; i < lastSegment; ++i) {
1061 Segment *segment = &segments[i];
1062 if (!segment->added)
1063 addSegmentsToPath(segment, result);
1069 #if defined(Q_OS_UNIX) || defined(Q_OS_WIN)
1071 //#define QT_REGION_DEBUG
1076 struct QRegionPrivate {
1078 QVector<QRect> rects;
1083 inline QRegionPrivate() : numRects(0), innerArea(-1) {}
1084 inline QRegionPrivate(const QRect &r) {
1088 innerArea = r.width() * r.height();
1091 inline QRegionPrivate(const QRegionPrivate &r) {
1093 numRects = r.numRects;
1094 extents = r.extents;
1095 innerRect = r.innerRect;
1096 innerArea = r.innerArea;
1099 inline QRegionPrivate &operator=(const QRegionPrivate &r) {
1101 numRects = r.numRects;
1102 extents = r.extents;
1103 innerRect = r.innerRect;
1104 innerArea = r.innerArea;
1108 void intersect(const QRect &r);
1111 * Returns true if r is guaranteed to be fully contained in this region.
1112 * A false return value does not guarantee the opposite.
1114 inline bool contains(const QRegionPrivate &r) const {
1115 return contains(r.extents);
1118 inline bool contains(const QRect &r2) const {
1119 const QRect &r1 = innerRect;
1120 return r2.left() >= r1.left() && r2.right() <= r1.right()
1121 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1125 * Returns true if this region is guaranteed to be fully contained in r.
1127 inline bool within(const QRect &r1) const {
1128 const QRect &r2 = extents;
1129 return r2.left() >= r1.left() && r2.right() <= r1.right()
1130 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1133 inline void updateInnerRect(const QRect &rect) {
1134 const int area = rect.width() * rect.height();
1135 if (area > innerArea) {
1141 inline void vectorize() {
1142 if (numRects == 1) {
1149 inline void append(const QRect *r);
1150 void append(const QRegionPrivate *r);
1151 void prepend(const QRect *r);
1152 void prepend(const QRegionPrivate *r);
1153 inline bool canAppend(const QRect *r) const;
1154 inline bool canAppend(const QRegionPrivate *r) const;
1155 inline bool canPrepend(const QRect *r) const;
1156 inline bool canPrepend(const QRegionPrivate *r) const;
1158 inline bool mergeFromRight(QRect *left, const QRect *right);
1159 inline bool mergeFromLeft(QRect *left, const QRect *right);
1160 inline bool mergeFromBelow(QRect *top, const QRect *bottom,
1161 const QRect *nextToTop,
1162 const QRect *nextToBottom);
1163 inline bool mergeFromAbove(QRect *bottom, const QRect *top,
1164 const QRect *nextToBottom,
1165 const QRect *nextToTop);
1167 #ifdef QT_REGION_DEBUG
1168 void selfTest() const;
1172 static inline bool isEmptyHelper(const QRegionPrivate *preg)
1174 return !preg || preg->numRects == 0;
1177 static inline bool canMergeFromRight(const QRect *left, const QRect *right)
1179 return (right->top() == left->top()
1180 && right->bottom() == left->bottom()
1181 && right->left() <= (left->right() + 1));
1184 static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
1186 return canMergeFromRight(left, right);
1189 bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right)
1191 if (canMergeFromRight(left, right)) {
1192 left->setRight(right->right());
1193 updateInnerRect(*left);
1199 bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left)
1201 if (canMergeFromLeft(right, left)) {
1202 right->setLeft(left->left());
1203 updateInnerRect(*right);
1209 static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom,
1210 const QRect *nextToTop,
1211 const QRect *nextToBottom)
1213 if (nextToTop && nextToTop->y() == top->y())
1215 if (nextToBottom && nextToBottom->y() == bottom->y())
1218 return ((top->bottom() >= (bottom->top() - 1))
1219 && top->left() == bottom->left()
1220 && top->right() == bottom->right());
1223 bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom,
1224 const QRect *nextToTop,
1225 const QRect *nextToBottom)
1227 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1228 top->setBottom(bottom->bottom());
1229 updateInnerRect(*top);
1235 bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top,
1236 const QRect *nextToBottom,
1237 const QRect *nextToTop)
1239 if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1240 bottom->setTop(top->top());
1241 updateInnerRect(*bottom);
1247 static inline QRect qt_rect_intersect_normalized(const QRect &r1,
1251 r.setLeft(qMax(r1.left(), r2.left()));
1252 r.setRight(qMin(r1.right(), r2.right()));
1253 r.setTop(qMax(r1.top(), r2.top()));
1254 r.setBottom(qMin(r1.bottom(), r2.bottom()));
1258 void QRegionPrivate::intersect(const QRect &rect)
1260 Q_ASSERT(extents.intersects(rect));
1261 Q_ASSERT(numRects > 1);
1263 #ifdef QT_REGION_DEBUG
1267 const QRect r = rect.normalized();
1269 innerRect = QRect();
1272 QRect *dest = rects.data();
1273 const QRect *src = dest;
1277 *dest = qt_rect_intersect_normalized(*src++, r);
1278 if (dest->isEmpty())
1281 if (numRects == 0) {
1284 extents.setLeft(qMin(extents.left(), dest->left()));
1285 // hw: extents.top() will never change after initialization
1286 //extents.setTop(qMin(extents.top(), dest->top()));
1287 extents.setRight(qMax(extents.right(), dest->right()));
1288 extents.setBottom(qMax(extents.bottom(), dest->bottom()));
1290 const QRect *nextToLast = (numRects > 1 ? dest - 2 : 0);
1292 // mergeFromBelow inlined and optimized
1293 if (canMergeFromBelow(dest - 1, dest, nextToLast, 0)) {
1294 if (!n || src->y() != dest->y() || src->left() > r.right()) {
1295 QRect *prev = dest - 1;
1296 prev->setBottom(dest->bottom());
1297 updateInnerRect(*prev);
1302 updateInnerRect(*dest);
1306 #ifdef QT_REGION_DEBUG
1311 void QRegionPrivate::append(const QRect *r)
1313 Q_ASSERT(!r->isEmpty());
1315 QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
1316 if (mergeFromRight(myLast, r)) {
1318 const QRect *nextToTop = (numRects > 2 ? myLast - 2 : 0);
1319 if (mergeFromBelow(myLast - 1, myLast, nextToTop, 0))
1322 } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : 0), 0)) {
1327 updateInnerRect(*r);
1328 if (rects.size() < numRects)
1329 rects.resize(numRects);
1330 rects[numRects - 1] = *r;
1332 extents.setCoords(qMin(extents.left(), r->left()),
1333 qMin(extents.top(), r->top()),
1334 qMax(extents.right(), r->right()),
1335 qMax(extents.bottom(), r->bottom()));
1337 #ifdef QT_REGION_DEBUG
1342 void QRegionPrivate::append(const QRegionPrivate *r)
1344 Q_ASSERT(!isEmptyHelper(r));
1346 if (r->numRects == 1) {
1347 append(&r->extents);
1353 QRect *destRect = rects.data() + numRects;
1354 const QRect *srcRect = r->rects.constData();
1355 int numAppend = r->numRects;
1359 const QRect *rFirst = srcRect;
1360 QRect *myLast = destRect - 1;
1361 const QRect *nextToLast = (numRects > 1 ? myLast - 1 : 0);
1362 if (mergeFromRight(myLast, rFirst)) {
1365 const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : 0);
1366 if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) {
1371 nextToLast = (numRects > 2 ? myLast - 2 : 0);
1372 rNextToFirst = (numAppend > 0 ? srcRect : 0);
1373 if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) {
1378 } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) {
1384 // append rectangles
1385 if (numAppend > 0) {
1386 const int newNumRects = numRects + numAppend;
1387 if (newNumRects > rects.size()) {
1388 rects.resize(newNumRects);
1389 destRect = rects.data() + numRects;
1391 memcpy(destRect, srcRect, numAppend * sizeof(QRect));
1393 numRects = newNumRects;
1396 // update inner rectangle
1397 if (innerArea < r->innerArea) {
1398 innerArea = r->innerArea;
1399 innerRect = r->innerRect;
1403 destRect = &extents;
1404 srcRect = &r->extents;
1405 extents.setCoords(qMin(destRect->left(), srcRect->left()),
1406 qMin(destRect->top(), srcRect->top()),
1407 qMax(destRect->right(), srcRect->right()),
1408 qMax(destRect->bottom(), srcRect->bottom()));
1410 #ifdef QT_REGION_DEBUG
1415 void QRegionPrivate::prepend(const QRegionPrivate *r)
1417 Q_ASSERT(!isEmptyHelper(r));
1419 if (r->numRects == 1) {
1420 prepend(&r->extents);
1426 int numPrepend = r->numRects;
1431 QRect *myFirst = rects.data();
1432 const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : 0);
1433 const QRect *rLast = r->rects.constData() + r->numRects - 1;
1434 const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : 0);
1435 if (mergeFromLeft(myFirst, rLast)) {
1438 rNextToLast = (numPrepend > 1 ? rLast - 1 : 0);
1439 if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1444 nextToFirst = (numRects > 2? myFirst + 2 : 0);
1445 rNextToLast = (numPrepend > 0 ? rLast : 0);
1446 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) {
1451 } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1456 if (numPrepend > 0) {
1457 const int newNumRects = numRects + numPrepend;
1458 if (newNumRects > rects.size())
1459 rects.resize(newNumRects);
1461 // move existing rectangles
1462 memmove(rects.data() + numPrepend, rects.constData() + numSkip,
1463 numRects * sizeof(QRect));
1465 // prepend new rectangles
1466 memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect));
1468 numRects = newNumRects;
1471 // update inner rectangle
1472 if (innerArea < r->innerArea) {
1473 innerArea = r->innerArea;
1474 innerRect = r->innerRect;
1478 extents.setCoords(qMin(extents.left(), r->extents.left()),
1479 qMin(extents.top(), r->extents.top()),
1480 qMax(extents.right(), r->extents.right()),
1481 qMax(extents.bottom(), r->extents.bottom()));
1483 #ifdef QT_REGION_DEBUG
1488 void QRegionPrivate::prepend(const QRect *r)
1490 Q_ASSERT(!r->isEmpty());
1492 QRect *myFirst = (numRects == 1 ? &extents : rects.data());
1493 if (mergeFromLeft(myFirst, r)) {
1495 const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : 0);
1496 if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, 0)) {
1498 memmove(rects.data(), rects.constData() + 1,
1499 numRects * sizeof(QRect));
1502 } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : 0), 0)) {
1507 updateInnerRect(*r);
1510 extents.setCoords(qMin(extents.left(), r->left()),
1511 qMin(extents.top(), r->top()),
1512 qMax(extents.right(), r->right()),
1513 qMax(extents.bottom(), r->bottom()));
1515 #ifdef QT_REGION_DEBUG
1520 bool QRegionPrivate::canAppend(const QRect *r) const
1522 Q_ASSERT(!r->isEmpty());
1524 const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
1525 if (r->top() > myLast->bottom())
1527 if (r->top() == myLast->top()
1528 && r->height() == myLast->height()
1529 && r->left() > myLast->right())
1537 bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
1539 return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
1542 bool QRegionPrivate::canPrepend(const QRect *r) const
1544 Q_ASSERT(!r->isEmpty());
1546 const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
1547 if (r->bottom() < myFirst->top()) // not overlapping
1549 if (r->top() == myFirst->top()
1550 && r->height() == myFirst->height()
1551 && r->right() < myFirst->left())
1559 bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
1561 return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1);
1564 #ifdef QT_REGION_DEBUG
1565 void QRegionPrivate::selfTest() const
1567 if (numRects == 0) {
1568 Q_ASSERT(extents.isEmpty());
1569 Q_ASSERT(innerRect.isEmpty());
1573 Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
1575 if (numRects == 1) {
1576 Q_ASSERT(innerRect == extents);
1577 Q_ASSERT(!innerRect.isEmpty());
1581 for (int i = 0; i < numRects; ++i) {
1582 const QRect r = rects.at(i);
1583 if ((r.width() * r.height()) > innerArea)
1584 qDebug() << "selfTest(): innerRect" << innerRect << '<' << r;
1587 QRect r = rects.first();
1588 for (int i = 1; i < numRects; ++i) {
1589 const QRect r2 = rects.at(i);
1590 Q_ASSERT(!r2.isEmpty());
1591 if (r2.y() == r.y()) {
1592 Q_ASSERT(r.bottom() == r2.bottom());
1593 Q_ASSERT(r.right() < (r2.left() + 1));
1595 Q_ASSERT(r2.y() >= r.bottom());
1600 #endif // QT_REGION_DEBUG
1602 static QRegionPrivate qrp;
1603 QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp};
1605 typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
1606 register const QRect *r2, const QRect *r2End, register int y1, register int y2);
1607 typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
1608 register int y1, register int y2);
1610 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
1611 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
1612 static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
1613 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
1614 NonOverlapFunc nonOverlap2Func);
1616 #define RectangleOut 0
1617 #define RectangleIn 1
1618 #define RectanglePart 2
1619 #define EvenOddRule 0
1620 #define WindingRule 1
1622 // START OF region.h extract
1623 /* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
1624 /************************************************************************
1626 Copyright (c) 1987 X Consortium
1628 Permission is hereby granted, free of charge, to any person obtaining a copy
1629 of this software and associated documentation files (the "Software"), to deal
1630 in the Software without restriction, including without limitation the rights
1631 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1632 copies of the Software, and to permit persons to whom the Software is
1633 furnished to do so, subject to the following conditions:
1635 The above copyright notice and this permission notice shall be included in
1636 all copies or substantial portions of the Software.
1638 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1639 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1640 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1641 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1642 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1643 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1645 Except as contained in this notice, the name of the X Consortium shall not be
1646 used in advertising or otherwise to promote the sale, use or other dealings
1647 in this Software without prior written authorization from the X Consortium.
1650 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
1654 Permission to use, copy, modify, and distribute this software and its
1655 documentation for any purpose and without fee is hereby granted,
1656 provided that the above copyright notice appear in all copies and that
1657 both that copyright notice and this permission notice appear in
1658 supporting documentation, and that the name of Digital not be
1659 used in advertising or publicity pertaining to distribution of the
1660 software without specific, written prior permission.
1662 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1663 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1664 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1665 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1666 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1667 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1670 ************************************************************************/
1675 QT_BEGIN_INCLUDE_NAMESPACE
1677 QT_END_INCLUDE_NAMESPACE
1679 /* 1 if two BOXes overlap.
1680 * 0 if two BOXes do not overlap.
1681 * Remember, x2 and y2 are not in the region
1683 #define EXTENTCHECK(r1, r2) \
1684 ((r1)->right() >= (r2)->left() && \
1685 (r1)->left() <= (r2)->right() && \
1686 (r1)->bottom() >= (r2)->top() && \
1687 (r1)->top() <= (r2)->bottom())
1690 * update region extents
1692 #define EXTENTS(r,idRect){\
1693 if((r)->left() < (idRect)->extents.left())\
1694 (idRect)->extents.setLeft((r)->left());\
1695 if((r)->top() < (idRect)->extents.top())\
1696 (idRect)->extents.setTop((r)->top());\
1697 if((r)->right() > (idRect)->extents.right())\
1698 (idRect)->extents.setRight((r)->right());\
1699 if((r)->bottom() > (idRect)->extents.bottom())\
1700 (idRect)->extents.setBottom((r)->bottom());\
1704 * Check to see if there is enough memory in the present region.
1706 #define MEMCHECK(dest, rect, firstrect){\
1707 if ((dest).numRects >= ((dest).rects.size()-1)){\
1708 firstrect.resize(firstrect.size() * 2); \
1709 (rect) = (firstrect).data() + (dest).numRects;\
1715 * number of points to buffer before sending them off
1716 * to scanlines(): Must be an even number
1718 #define NUMPTSTOBUFFER 200
1721 * used to allocate buffers for points and link
1722 * the buffers together
1724 typedef struct _POINTBLOCK {
1725 int data[NUMPTSTOBUFFER * sizeof(QPoint)];
1727 struct _POINTBLOCK *next;
1731 // END OF region.h extract
1733 // START OF Region.c extract
1734 /* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
1735 /************************************************************************
1737 Copyright (c) 1987, 1988 X Consortium
1739 Permission is hereby granted, free of charge, to any person obtaining a copy
1740 of this software and associated documentation files (the "Software"), to deal
1741 in the Software without restriction, including without limitation the rights
1742 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1743 copies of the Software, and to permit persons to whom the Software is
1744 furnished to do so, subject to the following conditions:
1746 The above copyright notice and this permission notice shall be included in
1747 all copies or substantial portions of the Software.
1749 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1750 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1751 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1752 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1753 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1754 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1756 Except as contained in this notice, the name of the X Consortium shall not be
1757 used in advertising or otherwise to promote the sale, use or other dealings
1758 in this Software without prior written authorization from the X Consortium.
1761 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
1765 Permission to use, copy, modify, and distribute this software and its
1766 documentation for any purpose and without fee is hereby granted,
1767 provided that the above copyright notice appear in all copies and that
1768 both that copyright notice and this permission notice appear in
1769 supporting documentation, and that the name of Digital not be
1770 used in advertising or publicity pertaining to distribution of the
1771 software without specific, written prior permission.
1773 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1774 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1775 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1776 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1777 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1778 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1781 ************************************************************************/
1783 * The functions in this file implement the Region abstraction, similar to one
1784 * used in the X11 sample server. A Region is simply an area, as the name
1785 * implies, and is implemented as a "y-x-banded" array of rectangles. To
1786 * explain: Each Region is made up of a certain number of rectangles sorted
1787 * by y coordinate first, and then by x coordinate.
1789 * Furthermore, the rectangles are banded such that every rectangle with a
1790 * given upper-left y coordinate (y1) will have the same lower-right y
1791 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
1792 * will span the entire vertical distance of the band. This means that some
1793 * areas that could be merged into a taller rectangle will be represented as
1794 * several shorter rectangles to account for shorter rectangles to its left
1795 * or right but within its "vertical scope".
1797 * An added constraint on the rectangles is that they must cover as much
1798 * horizontal area as possible. E.g. no two rectangles in a band are allowed
1801 * Whenever possible, bands will be merged together to cover a greater vertical
1802 * distance (and thus reduce the number of rectangles). Two bands can be merged
1803 * only if the bottom of one touches the top of the other and they have
1804 * rectangles in the same places (of the same width, of course). This maintains
1805 * the y-x-banding that's so nice to have...
1807 /* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
1809 static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source,
1810 QRegionPrivate &dest)
1812 if (rect->isEmpty())
1815 Q_ASSERT(EqualRegion(source, &dest));
1817 if (dest.numRects == 0) {
1818 dest = QRegionPrivate(*rect);
1819 } else if (dest.canAppend(rect)) {
1822 QRegionPrivate p(*rect);
1823 UnionRegion(&p, source, dest);
1828 *-----------------------------------------------------------------------
1830 * Reset the extents and innerRect of a region to what they should be.
1831 * Called by miSubtract and miIntersect b/c they can't figure it out
1832 * along the way or do so easily, as miUnion can.
1838 * The region's 'extents' and 'innerRect' structure is overwritten.
1840 *-----------------------------------------------------------------------
1842 static void miSetExtents(QRegionPrivate &dest)
1844 register const QRect *pBox,
1846 register QRect *pExtents;
1848 dest.innerRect.setCoords(0, 0, -1, -1);
1849 dest.innerArea = -1;
1850 if (dest.numRects == 0) {
1851 dest.extents.setCoords(0, 0, -1, -1);
1855 pExtents = &dest.extents;
1856 if (dest.rects.isEmpty())
1857 pBox = &dest.extents;
1859 pBox = dest.rects.constData();
1860 pBoxEnd = pBox + dest.numRects - 1;
1863 * Since pBox is the first rectangle in the region, it must have the
1864 * smallest y1 and since pBoxEnd is the last rectangle in the region,
1865 * it must have the largest y2, because of banding. Initialize x1 and
1866 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
1869 pExtents->setLeft(pBox->left());
1870 pExtents->setTop(pBox->top());
1871 pExtents->setRight(pBoxEnd->right());
1872 pExtents->setBottom(pBoxEnd->bottom());
1874 Q_ASSERT(pExtents->top() <= pExtents->bottom());
1875 while (pBox <= pBoxEnd) {
1876 if (pBox->left() < pExtents->left())
1877 pExtents->setLeft(pBox->left());
1878 if (pBox->right() > pExtents->right())
1879 pExtents->setRight(pBox->right());
1880 dest.updateInnerRect(*pBox);
1883 Q_ASSERT(pExtents->left() <= pExtents->right());
1886 /* TranslateRegion(pRegion, x, y)
1891 static void OffsetRegion(register QRegionPrivate ®ion, register int x, register int y)
1893 if (region.rects.size()) {
1894 register QRect *pbox = region.rects.data();
1895 register int nbox = region.numRects;
1898 pbox->translate(x, y);
1902 region.extents.translate(x, y);
1903 region.innerRect.translate(x, y);
1906 /*======================================================================
1907 * Region Intersection
1908 *====================================================================*/
1910 *-----------------------------------------------------------------------
1912 * Handle an overlapping band for miIntersect.
1918 * Rectangles may be added to the region.
1920 *-----------------------------------------------------------------------
1922 static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
1923 register const QRect *r2, const QRect *r2End, int y1, int y2)
1927 register QRect *pNextRect;
1929 pNextRect = dest.rects.data() + dest.numRects;
1931 while (r1 != r1End && r2 != r2End) {
1932 x1 = qMax(r1->left(), r2->left());
1933 x2 = qMin(r1->right(), r2->right());
1936 * If there's any overlap between the two rectangles, add that
1937 * overlap to the new region.
1938 * There's no need to check for subsumption because the only way
1939 * such a need could arise is if some region has two rectangles
1940 * right next to each other. Since that should never happen...
1944 MEMCHECK(dest, pNextRect, dest.rects)
1945 pNextRect->setCoords(x1, y1, x2, y2);
1951 * Need to advance the pointers. Shift the one that extends
1952 * to the right the least, since the other still has a chance to
1953 * overlap with that region's next rectangle, if you see what I mean.
1955 if (r1->right() < r2->right()) {
1957 } else if (r2->right() < r1->right()) {
1966 /*======================================================================
1967 * Generic Region Operator
1968 *====================================================================*/
1971 *-----------------------------------------------------------------------
1973 * Attempt to merge the boxes in the current band with those in the
1974 * previous one. Used only by miRegionOp.
1977 * The new index for the previous band.
1980 * If coalescing takes place:
1981 * - rectangles in the previous band will have their y2 fields
1983 * - dest.numRects will be decreased.
1985 *-----------------------------------------------------------------------
1987 static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart)
1989 register QRect *pPrevBox; /* Current box in previous band */
1990 register QRect *pCurBox; /* Current box in current band */
1991 register QRect *pRegEnd; /* End of region */
1992 int curNumRects; /* Number of rectangles in current band */
1993 int prevNumRects; /* Number of rectangles in previous band */
1994 int bandY1; /* Y1 coordinate for current band */
1995 QRect *rData = dest.rects.data();
1997 pRegEnd = rData + dest.numRects;
1999 pPrevBox = rData + prevStart;
2000 prevNumRects = curStart - prevStart;
2003 * Figure out how many rectangles are in the current band. Have to do
2004 * this because multiple bands could have been added in miRegionOp
2005 * at the end when one region has been exhausted.
2007 pCurBox = rData + curStart;
2008 bandY1 = pCurBox->top();
2009 for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
2013 if (pCurBox != pRegEnd) {
2015 * If more than one band was added, we have to find the start
2016 * of the last band added so the next coalescing job can start
2017 * at the right place... (given when multiple bands are added,
2018 * this may be pointless -- see above).
2021 while ((pRegEnd - 1)->top() == pRegEnd->top())
2023 curStart = pRegEnd - rData;
2024 pRegEnd = rData + dest.numRects;
2027 if (curNumRects == prevNumRects && curNumRects != 0) {
2028 pCurBox -= curNumRects;
2030 * The bands may only be coalesced if the bottom of the previous
2031 * matches the top scanline of the current.
2033 if (pPrevBox->bottom() == pCurBox->top() - 1) {
2035 * Make sure the bands have boxes in the same places. This
2036 * assumes that boxes have been added in such a way that they
2037 * cover the most area possible. I.e. two boxes in a band must
2038 * have some horizontal space between them.
2041 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
2042 // The bands don't line up so they can't be coalesced.
2048 } while (prevNumRects != 0);
2050 dest.numRects -= curNumRects;
2051 pCurBox -= curNumRects;
2052 pPrevBox -= curNumRects;
2055 * The bands may be merged, so set the bottom y of each box
2056 * in the previous band to that of the corresponding box in
2060 pPrevBox->setBottom(pCurBox->bottom());
2061 dest.updateInnerRect(*pPrevBox);
2065 } while (curNumRects != 0);
2068 * If only one band was added to the region, we have to backup
2069 * curStart to the start of the previous band.
2071 * If more than one band was added to the region, copy the
2072 * other bands down. The assumption here is that the other bands
2073 * came from the same region as the current one and no further
2074 * coalescing can be done on them since it's all been done
2075 * already... curStart is already in the right place.
2077 if (pCurBox == pRegEnd) {
2078 curStart = prevStart;
2081 *pPrevBox++ = *pCurBox++;
2082 dest.updateInnerRect(*pPrevBox);
2083 } while (pCurBox != pRegEnd);
2091 *-----------------------------------------------------------------------
2093 * Apply an operation to two regions. Called by miUnion, miInverse,
2094 * miSubtract, miIntersect...
2100 * The new region is overwritten.
2103 * The idea behind this function is to view the two regions as sets.
2104 * Together they cover a rectangle of area that this function divides
2105 * into horizontal bands where points are covered only by one region
2106 * or by both. For the first case, the nonOverlapFunc is called with
2107 * each the band and the band's upper and lower extents. For the
2108 * second, the overlapFunc is called to process the entire band. It
2109 * is responsible for clipping the rectangles in the band, though
2110 * this function provides the boundaries.
2111 * At the end of each band, the new region is coalesced, if possible,
2112 * to reduce the number of rectangles in the region.
2114 *-----------------------------------------------------------------------
2116 static void miRegionOp(register QRegionPrivate &dest,
2117 const QRegionPrivate *reg1, const QRegionPrivate *reg2,
2118 OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
2119 NonOverlapFunc nonOverlap2Func)
2121 register const QRect *r1; // Pointer into first region
2122 register const QRect *r2; // Pointer into 2d region
2123 const QRect *r1End; // End of 1st region
2124 const QRect *r2End; // End of 2d region
2125 register int ybot; // Bottom of intersection
2126 register int ytop; // Top of intersection
2127 int prevBand; // Index of start of previous band in dest
2128 int curBand; // Index of start of current band in dest
2129 register const QRect *r1BandEnd; // End of current band in r1
2130 register const QRect *r2BandEnd; // End of current band in r2
2131 int top; // Top of non-overlapping band
2132 int bot; // Bottom of non-overlapping band
2136 * set r1, r2, r1End and r2End appropriately, preserve the important
2137 * parts of the destination region until the end in case it's one of
2138 * the two source regions, then mark the "new" region empty, allocating
2139 * another array of rectangles for it to use.
2141 if (reg1->numRects == 1)
2142 r1 = ®1->extents;
2144 r1 = reg1->rects.constData();
2145 if (reg2->numRects == 1)
2146 r2 = ®2->extents;
2148 r2 = reg2->rects.constData();
2150 r1End = r1 + reg1->numRects;
2151 r2End = r2 + reg2->numRects;
2155 QVector<QRect> oldRects = dest.rects;
2160 * Allocate a reasonable number of rectangles for the new region. The idea
2161 * is to allocate enough so the individual functions don't need to
2162 * reallocate and copy the array, which is time consuming, yet we don't
2163 * have to worry about using too much memory. I hope to be able to
2164 * nuke the realloc() at the end of this function eventually.
2166 dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
2169 * Initialize ybot and ytop.
2170 * In the upcoming loop, ybot and ytop serve different functions depending
2171 * on whether the band being handled is an overlapping or non-overlapping
2173 * In the case of a non-overlapping band (only one of the regions
2174 * has points in the band), ybot is the bottom of the most recent
2175 * intersection and thus clips the top of the rectangles in that band.
2176 * ytop is the top of the next intersection between the two regions and
2177 * serves to clip the bottom of the rectangles in the current band.
2178 * For an overlapping band (where the two regions intersect), ytop clips
2179 * the top of the rectangles of both regions and ybot clips the bottoms.
2181 if (reg1->extents.top() < reg2->extents.top())
2182 ybot = reg1->extents.top() - 1;
2184 ybot = reg2->extents.top() - 1;
2187 * prevBand serves to mark the start of the previous band so rectangles
2188 * can be coalesced into larger rectangles. qv. miCoalesce, above.
2189 * In the beginning, there is no previous band, so prevBand == curBand
2190 * (curBand is set later on, of course, but the first band will always
2191 * start at index 0). prevBand and curBand must be indices because of
2192 * the possible expansion, and resultant moving, of the new region's
2193 * array of rectangles.
2198 curBand = dest.numRects;
2201 * This algorithm proceeds one source-band (as opposed to a
2202 * destination band, which is determined by where the two regions
2203 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
2204 * rectangle after the last one in the current band for their
2205 * respective regions.
2208 while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
2212 while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
2216 * First handle the band that doesn't intersect, if any.
2218 * Note that attention is restricted to one band in the
2219 * non-intersecting region at once, so if a region has n
2220 * bands between the current position and the next place it overlaps
2221 * the other, this entire loop will be passed through n times.
2223 if (r1->top() < r2->top()) {
2224 top = qMax(r1->top(), ybot + 1);
2225 bot = qMin(r1->bottom(), r2->top() - 1);
2227 if (nonOverlap1Func != 0 && bot >= top)
2228 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
2230 } else if (r2->top() < r1->top()) {
2231 top = qMax(r2->top(), ybot + 1);
2232 bot = qMin(r2->bottom(), r1->top() - 1);
2234 if (nonOverlap2Func != 0 && bot >= top)
2235 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
2242 * If any rectangles got added to the region, try and coalesce them
2243 * with rectangles from the previous band. Note we could just do
2244 * this test in miCoalesce, but some machines incur a not
2245 * inconsiderable cost for function calls, so...
2247 if (dest.numRects != curBand)
2248 prevBand = miCoalesce(dest, prevBand, curBand);
2251 * Now see if we've hit an intersecting band. The two bands only
2252 * intersect if ybot >= ytop
2254 ybot = qMin(r1->bottom(), r2->bottom());
2255 curBand = dest.numRects;
2257 (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
2259 if (dest.numRects != curBand)
2260 prevBand = miCoalesce(dest, prevBand, curBand);
2263 * If we've finished with a band (y2 == ybot) we skip forward
2264 * in the region to the next band.
2266 if (r1->bottom() == ybot)
2268 if (r2->bottom() == ybot)
2270 } while (r1 != r1End && r2 != r2End);
2273 * Deal with whichever region still has rectangles left.
2275 curBand = dest.numRects;
2277 if (nonOverlap1Func != 0) {
2280 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
2282 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
2284 } while (r1 != r1End);
2286 } else if ((r2 != r2End) && (nonOverlap2Func != 0)) {
2289 while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
2291 (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
2293 } while (r2 != r2End);
2296 if (dest.numRects != curBand)
2297 (void)miCoalesce(dest, prevBand, curBand);
2300 * A bit of cleanup. To keep regions from growing without bound,
2301 * we shrink the array of rectangles to match the new number of
2302 * rectangles in the region.
2304 * Only do this stuff if the number of rectangles allocated is more than
2305 * twice the number of rectangles in the region (a simple optimization).
2307 if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
2308 dest.rects.resize(dest.numRects);
2311 /*======================================================================
2313 *====================================================================*/
2316 *-----------------------------------------------------------------------
2318 * Handle a non-overlapping band for the union operation. Just
2319 * Adds the rectangles into the region. Doesn't have to check for
2320 * subsumption or anything.
2326 * dest.numRects is incremented and the final rectangles overwritten
2327 * with the rectangles we're passed.
2329 *-----------------------------------------------------------------------
2332 static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
2333 register int y1, register int y2)
2335 register QRect *pNextRect;
2337 pNextRect = dest.rects.data() + dest.numRects;
2342 Q_ASSERT(r->left() <= r->right());
2343 MEMCHECK(dest, pNextRect, dest.rects)
2344 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2353 *-----------------------------------------------------------------------
2355 * Handle an overlapping band for the union operation. Picks the
2356 * left-most rectangle each time and merges it into the region.
2362 * Rectangles are overwritten in dest.rects and dest.numRects will
2365 *-----------------------------------------------------------------------
2368 static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
2369 register const QRect *r2, const QRect *r2End, register int y1, register int y2)
2371 register QRect *pNextRect;
2373 pNextRect = dest.rects.data() + dest.numRects;
2375 #define MERGERECT(r) \
2376 if ((dest.numRects != 0) && \
2377 (pNextRect[-1].top() == y1) && \
2378 (pNextRect[-1].bottom() == y2) && \
2379 (pNextRect[-1].right() >= r->left()-1)) { \
2380 if (pNextRect[-1].right() < r->right()) { \
2381 pNextRect[-1].setRight(r->right()); \
2382 dest.updateInnerRect(pNextRect[-1]); \
2383 Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
2386 MEMCHECK(dest, pNextRect, dest.rects) \
2387 pNextRect->setCoords(r->left(), y1, r->right(), y2); \
2388 dest.updateInnerRect(*pNextRect); \
2395 while (r1 != r1End && r2 != r2End) {
2396 if (r1->left() < r2->left()) {
2406 } while (r1 != r1End);
2408 while (r2 != r2End) {
2414 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
2416 Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2));
2417 Q_ASSERT(!reg1->contains(*reg2));
2418 Q_ASSERT(!reg2->contains(*reg1));
2419 Q_ASSERT(!EqualRegion(reg1, reg2));
2420 Q_ASSERT(!reg1->canAppend(reg2));
2421 Q_ASSERT(!reg2->canAppend(reg1));
2423 if (reg1->innerArea > reg2->innerArea) {
2424 dest.innerArea = reg1->innerArea;
2425 dest.innerRect = reg1->innerRect;
2427 dest.innerArea = reg2->innerArea;
2428 dest.innerRect = reg2->innerRect;
2430 miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
2432 dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
2433 qMin(reg1->extents.top(), reg2->extents.top()),
2434 qMax(reg1->extents.right(), reg2->extents.right()),
2435 qMax(reg1->extents.bottom(), reg2->extents.bottom()));
2438 /*======================================================================
2439 * Region Subtraction
2440 *====================================================================*/
2443 *-----------------------------------------------------------------------
2445 * Deal with non-overlapping band for subtraction. Any parts from
2446 * region 2 we discard. Anything from region 1 we add to the region.
2452 * dest may be affected.
2454 *-----------------------------------------------------------------------
2457 static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r,
2458 const QRect *rEnd, register int y1, register int y2)
2460 register QRect *pNextRect;
2462 pNextRect = dest.rects.data() + dest.numRects;
2467 Q_ASSERT(r->left() <= r->right());
2468 MEMCHECK(dest, pNextRect, dest.rects)
2469 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2477 *-----------------------------------------------------------------------
2479 * Overlapping band subtraction. x1 is the left-most point not yet
2486 * dest may have rectangles added to it.
2488 *-----------------------------------------------------------------------
2491 static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
2492 register const QRect *r2, const QRect *r2End, register int y1, register int y2)
2494 register QRect *pNextRect;
2500 pNextRect = dest.rects.data() + dest.numRects;
2502 while (r1 != r1End && r2 != r2End) {
2503 if (r2->right() < x1) {
2505 * Subtrahend missed the boat: go to next subtrahend.
2508 } else if (r2->left() <= x1) {
2510 * Subtrahend precedes minuend: nuke left edge of minuend.
2512 x1 = r2->right() + 1;
2513 if (x1 > r1->right()) {
2515 * Minuend completely covered: advance to next minuend and
2516 * reset left fence to edge of new minuend.
2522 // Subtrahend now used up since it doesn't extend beyond minuend
2525 } else if (r2->left() <= r1->right()) {
2527 * Left part of subtrahend covers part of minuend: add uncovered
2528 * part of minuend to region and skip to next subtrahend.
2530 Q_ASSERT(x1 < r2->left());
2531 MEMCHECK(dest, pNextRect, dest.rects)
2532 pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
2536 x1 = r2->right() + 1;
2537 if (x1 > r1->right()) {
2539 * Minuend used up: advance to new...
2545 // Subtrahend used up
2550 * Minuend used up: add any remaining piece before advancing.
2552 if (r1->right() >= x1) {
2553 MEMCHECK(dest, pNextRect, dest.rects)
2554 pNextRect->setCoords(x1, y1, r1->right(), y2);
2565 * Add remaining minuend rectangles to region.
2567 while (r1 != r1End) {
2568 Q_ASSERT(x1 <= r1->right());
2569 MEMCHECK(dest, pNextRect, dest.rects)
2570 pNextRect->setCoords(x1, y1, r1->right(), y2);
2581 *-----------------------------------------------------------------------
2583 * Subtract regS from regM and leave the result in regD.
2584 * S stands for subtrahend, M for minuend and D for difference.
2587 * regD is overwritten.
2589 *-----------------------------------------------------------------------
2592 static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
2593 register QRegionPrivate &dest)
2595 Q_ASSERT(!isEmptyHelper(regM));
2596 Q_ASSERT(!isEmptyHelper(regS));
2597 Q_ASSERT(EXTENTCHECK(®M->extents, ®S->extents));
2598 Q_ASSERT(!regS->contains(*regM));
2599 Q_ASSERT(!EqualRegion(regM, regS));
2601 miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0);
2604 * Can't alter dest's extents before we call miRegionOp because
2605 * it might be one of the source regions and miRegionOp depends
2606 * on the extents of those regions being the unaltered. Besides, this
2607 * way there's no checking against rectangles that will be nuked
2608 * due to coalescing, so we have to examine fewer rectangles.
2613 static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
2615 Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb));
2616 Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents));
2617 Q_ASSERT(!EqualRegion(sra, srb));
2619 QRegionPrivate tra, trb;
2621 if (!srb->contains(*sra))
2622 SubtractRegion(sra, srb, tra);
2623 if (!sra->contains(*srb))
2624 SubtractRegion(srb, sra, trb);
2626 Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb));
2627 Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra));
2629 if (isEmptyHelper(&tra)) {
2631 } else if (isEmptyHelper(&trb)) {
2633 } else if (tra.canAppend(&trb)) {
2636 } else if (trb.canAppend(&tra)) {
2640 UnionRegion(&tra, &trb, dest);
2645 * Check to see if two regions are equal
2647 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
2649 if (r1->numRects != r2->numRects) {
2651 } else if (r1->numRects == 0) {
2653 } else if (r1->extents != r2->extents) {
2655 } else if (r1->numRects == 1 && r2->numRects == 1) {
2656 return true; // equality tested in previous if-statement
2658 const QRect *rr1 = (r1->numRects == 1) ? &r1->extents : r1->rects.constData();
2659 const QRect *rr2 = (r2->numRects == 1) ? &r2->extents : r2->rects.constData();
2660 for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
2669 static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
2673 if (isEmptyHelper(pRegion))
2675 if (!pRegion->extents.contains(x, y))
2677 if (pRegion->numRects == 1)
2678 return pRegion->extents.contains(x, y);
2679 if (pRegion->innerRect.contains(x, y))
2681 for (i = 0; i < pRegion->numRects; ++i) {
2682 if (pRegion->rects[i].contains(x, y))
2688 static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
2690 register const QRect *pbox;
2691 register const QRect *pboxEnd;
2692 QRect rect(rx, ry, rwidth, rheight);
2693 register QRect *prect = ▭
2694 int partIn, partOut;
2696 if (!region || region->numRects == 0 || !EXTENTCHECK(®ion->extents, prect))
2697 return RectangleOut;
2702 /* can stop when both partOut and partIn are true, or we reach prect->y2 */
2703 pbox = (region->numRects == 1) ? ®ion->extents : region->rects.constData();
2704 pboxEnd = pbox + region->numRects;
2705 for (; pbox < pboxEnd; ++pbox) {
2706 if (pbox->bottom() < ry)
2709 if (pbox->top() > ry) {
2711 if (partIn || pbox->top() > prect->bottom())
2716 if (pbox->right() < rx)
2717 continue; /* not far enough over yet */
2719 if (pbox->left() > rx) {
2720 partOut = true; /* missed part of rectangle to left */
2725 if (pbox->left() <= prect->right()) {
2726 partIn = true; /* definitely overlap */
2731 if (pbox->right() >= prect->right()) {
2732 ry = pbox->bottom() + 1; /* finished with this band */
2733 if (ry > prect->bottom())
2735 rx = prect->left(); /* reset x out to left again */
2738 * Because boxes in a band are maximal width, if the first box
2739 * to overlap the rectangle doesn't completely cover it in that
2740 * band, the rectangle must be partially out, since some of it
2741 * will be uncovered in that band. partIn will have been set true
2747 return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
2749 // END OF Region.c extract
2750 // START OF poly.h extract
2751 /* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
2752 /************************************************************************
2754 Copyright (c) 1987 X Consortium
2756 Permission is hereby granted, free of charge, to any person obtaining a copy
2757 of this software and associated documentation files (the "Software"), to deal
2758 in the Software without restriction, including without limitation the rights
2759 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2760 copies of the Software, and to permit persons to whom the Software is
2761 furnished to do so, subject to the following conditions:
2763 The above copyright notice and this permission notice shall be included in
2764 all copies or substantial portions of the Software.
2766 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2767 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2768 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2769 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2770 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2771 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2773 Except as contained in this notice, the name of the X Consortium shall not be
2774 used in advertising or otherwise to promote the sale, use or other dealings
2775 in this Software without prior written authorization from the X Consortium.
2778 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2782 Permission to use, copy, modify, and distribute this software and its
2783 documentation for any purpose and without fee is hereby granted,
2784 provided that the above copyright notice appear in all copies and that
2785 both that copyright notice and this permission notice appear in
2786 supporting documentation, and that the name of Digital not be
2787 used in advertising or publicity pertaining to distribution of the
2788 software without specific, written prior permission.
2790 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2791 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2792 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2793 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2794 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2795 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2798 ************************************************************************/
2801 * This file contains a few macros to help track
2802 * the edge of a filled object. The object is assumed
2803 * to be filled in scanline order, and thus the
2804 * algorithm used is an extension of Bresenham's line
2805 * drawing algorithm which assumes that y is always the
2807 * Since these pieces of code are the same for any filled shape,
2808 * it is more convenient to gather the library in one
2809 * place, but since these pieces of code are also in
2810 * the inner loops of output primitives, procedure call
2811 * overhead is out of the question.
2812 * See the author for a derivation if needed.
2817 * In scan converting polygons, we want to choose those pixels
2818 * which are inside the polygon. Thus, we add .5 to the starting
2819 * x coordinate for both left and right edges. Now we choose the
2820 * first pixel which is inside the pgon for the left edge and the
2821 * first pixel which is outside the pgon for the right edge.
2822 * Draw the left pixel, but not the right.
2824 * How to add .5 to the starting x coordinate:
2825 * If the edge is moving to the right, then subtract dy from the
2826 * error term from the general form of the algorithm.
2827 * If the edge is moving to the left, then add dy to the error term.
2829 * The reason for the difference between edges moving to the left
2830 * and edges moving to the right is simple: If an edge is moving
2831 * to the right, then we want the algorithm to flip immediately.
2832 * If it is moving to the left, then we don't want it to flip until
2833 * we traverse an entire pixel.
2835 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
2836 int dx; /* local storage */ \
2839 * if the edge is horizontal, then it is ignored \
2840 * and assumed not to be processed. Otherwise, do this stuff. \
2844 dx = (x2) - xStart; \
2848 incr1 = -2 * dx + 2 * (dy) * m1; \
2849 incr2 = -2 * dx + 2 * (dy) * m; \
2850 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
2854 incr1 = 2 * dx - 2 * (dy) * m1; \
2855 incr2 = 2 * dx - 2 * (dy) * m; \
2856 d = -2 * m * (dy) + 2 * dx; \
2861 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
2885 * This structure contains all of the information needed
2886 * to run the bresenham algorithm.
2887 * The variables may be hardcoded into the declarations
2888 * instead of using this structure to make use of
2889 * register declarations.
2892 int minor_axis; /* minor axis */
2893 int d; /* decision variable */
2894 int m, m1; /* slope and slope+1 */
2895 int incr1, incr2; /* error increments */
2899 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
2900 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
2901 bres.m, bres.m1, bres.incr1, bres.incr2)
2903 #define BRESINCRPGONSTRUCT(bres) \
2904 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
2909 * These are the data structures needed to scan
2910 * convert regions. Two different scan conversion
2911 * methods are available -- the even-odd method, and
2912 * the winding number method.
2913 * The even-odd rule states that a point is inside
2914 * the polygon if a ray drawn from that point in any
2915 * direction will pass through an odd number of
2917 * By the winding number rule, a point is decided
2918 * to be inside the polygon if a ray drawn from that
2919 * point in any direction passes through a different
2920 * number of clockwise and counter-clockwise path
2923 * These data structures are adapted somewhat from
2924 * the algorithm in (Foley/Van Dam) for scan converting
2926 * The basic algorithm is to start at the top (smallest y)
2927 * of the polygon, stepping down to the bottom of
2928 * the polygon by incrementing the y coordinate. We
2929 * keep a list of edges which the current scanline crosses,
2930 * sorted by x. This list is called the Active Edge Table (AET)
2931 * As we change the y-coordinate, we update each entry in
2932 * in the active edge table to reflect the edges new xcoord.
2933 * This list must be sorted at each scanline in case
2934 * two edges intersect.
2935 * We also keep a data structure known as the Edge Table (ET),
2936 * which keeps track of all the edges which the current
2937 * scanline has not yet reached. The ET is basically a
2938 * list of ScanLineList structures containing a list of
2939 * edges which are entered at a given scanline. There is one
2940 * ScanLineList per scanline at which an edge is entered.
2941 * When we enter a new edge, we move it from the ET to the AET.
2943 * From the AET, we can implement the even-odd rule as in
2945 * The winding number rule is a little trickier. We also
2946 * keep the EdgeTableEntries in the AET linked by the
2947 * nextWETE (winding EdgeTableEntry) link. This allows
2948 * the edges to be linked just as before for updating
2949 * purposes, but only uses the edges linked by the nextWETE
2950 * link as edges representing spans of the polygon to
2951 * drawn (as with the even-odd rule).
2955 * for the winding number rule
2958 #define COUNTERCLOCKWISE -1
2960 typedef struct _EdgeTableEntry {
2961 int ymax; /* ycoord at which we exit this edge. */
2962 BRESINFO bres; /* Bresenham info to run the edge */
2963 struct _EdgeTableEntry *next; /* next in the list */
2964 struct _EdgeTableEntry *back; /* for insertion sort */
2965 struct _EdgeTableEntry *nextWETE; /* for winding num rule */
2966 int ClockWise; /* flag for winding number rule */
2970 typedef struct _ScanLineList{
2971 int scanline; /* the scanline represented */
2972 EdgeTableEntry *edgelist; /* header node */
2973 struct _ScanLineList *next; /* next in the list */
2978 int ymax; /* ymax for the polygon */
2979 int ymin; /* ymin for the polygon */
2980 ScanLineList scanlines; /* header node */
2985 * Here is a struct to help with storage allocation
2986 * so we can allocate a big chunk at a time, and then take
2987 * pieces from this heap when we need to.
2989 #define SLLSPERBLOCK 25
2991 typedef struct _ScanLineListBlock {
2992 ScanLineList SLLs[SLLSPERBLOCK];
2993 struct _ScanLineListBlock *next;
2994 } ScanLineListBlock;
3000 * a few macros for the inner loops of the fill code where
3001 * performance considerations don't allow a procedure call.
3003 * Evaluate the given edge at the given scanline.
3004 * If the edge has expired, then we leave it and fix up
3005 * the active edge table; otherwise, we increment the
3006 * x value to be ready for the next scanline.
3007 * The winding number rule is in effect, so we must notify
3008 * the caller when the edge has been removed so he
3009 * can reorder the Winding Active Edge Table.
3011 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
3012 if (pAET->ymax == y) { /* leaving this edge */ \
3013 pPrevAET->next = pAET->next; \
3014 pAET = pPrevAET->next; \
3017 pAET->back = pPrevAET; \
3020 BRESINCRPGONSTRUCT(pAET->bres) \
3022 pAET = pAET->next; \
3028 * Evaluate the given edge at the given scanline.
3029 * If the edge has expired, then we leave it and fix up
3030 * the active edge table; otherwise, we increment the
3031 * x value to be ready for the next scanline.
3032 * The even-odd rule is in effect.
3034 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
3035 if (pAET->ymax == y) { /* leaving this edge */ \
3036 pPrevAET->next = pAET->next; \
3037 pAET = pPrevAET->next; \
3039 pAET->back = pPrevAET; \
3042 BRESINCRPGONSTRUCT(pAET->bres) \
3044 pAET = pAET->next; \
3047 // END OF poly.h extract
3048 // START OF PolyReg.c extract
3049 /* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
3050 /************************************************************************
3052 Copyright (c) 1987 X Consortium
3054 Permission is hereby granted, free of charge, to any person obtaining a copy
3055 of this software and associated documentation files (the "Software"), to deal
3056 in the Software without restriction, including without limitation the rights
3057 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3058 copies of the Software, and to permit persons to whom the Software is
3059 furnished to do so, subject to the following conditions:
3061 The above copyright notice and this permission notice shall be included in
3062 all copies or substantial portions of the Software.
3064 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3065 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3066 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3067 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
3068 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3069 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3071 Except as contained in this notice, the name of the X Consortium shall not be
3072 used in advertising or otherwise to promote the sale, use or other dealings
3073 in this Software without prior written authorization from the X Consortium.
3076 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3080 Permission to use, copy, modify, and distribute this software and its
3081 documentation for any purpose and without fee is hereby granted,
3082 provided that the above copyright notice appear in all copies and that
3083 both that copyright notice and this permission notice appear in
3084 supporting documentation, and that the name of Digital not be
3085 used in advertising or publicity pertaining to distribution of the
3086 software without specific, written prior permission.
3088 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3089 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3090 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
3091 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
3092 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
3093 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3096 ************************************************************************/
3097 /* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
3099 #define LARGE_COORDINATE INT_MAX
3100 #define SMALL_COORDINATE INT_MIN
3105 * Insert the given edge into the edge table.
3106 * First we must find the correct bucket in the
3107 * Edge table, then find the right slot in the
3108 * bucket. Finally, we can insert it.
3111 static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
3112 ScanLineListBlock **SLLBlock, int *iSLLBlock)
3114 register EdgeTableEntry *start, *prev;
3115 register ScanLineList *pSLL, *pPrevSLL;
3116 ScanLineListBlock *tmpSLLBlock;
3119 * find the right bucket to put the edge into
3121 pPrevSLL = &ET->scanlines;
3122 pSLL = pPrevSLL->next;
3123 while (pSLL && (pSLL->scanline < scanline)) {
3129 * reassign pSLL (pointer to ScanLineList) if necessary
3131 if ((!pSLL) || (pSLL->scanline > scanline)) {
3132 if (*iSLLBlock > SLLSPERBLOCK-1)
3135 (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
3136 Q_CHECK_PTR(tmpSLLBlock);
3137 (*SLLBlock)->next = tmpSLLBlock;
3138 tmpSLLBlock->next = (ScanLineListBlock *)NULL;
3139 *SLLBlock = tmpSLLBlock;
3142 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3144 pSLL->next = pPrevSLL->next;
3145 pSLL->edgelist = (EdgeTableEntry *)NULL;
3146 pPrevSLL->next = pSLL;
3148 pSLL->scanline = scanline;
3151 * now insert the edge in the right bucket
3154 start = pSLL->edgelist;
3155 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3157 start = start->next;
3164 pSLL->edgelist = ETE;
3170 * This routine creates the edge table for
3171 * scan converting polygons.
3172 * The Edge Table (ET) looks like:
3176 * | ymax | ScanLineLists
3177 * |scanline|-->------------>-------------->...
3178 * -------- |scanline| |scanline|
3179 * |edgelist| |edgelist|
3180 * --------- ---------
3184 * list of ETEs list of ETEs
3186 * where ETE is an EdgeTableEntry data structure,
3187 * and there is one ScanLineList per scanline at
3188 * which an edge is initially entered.
3192 static void CreateETandAET(register int count, register const QPoint *pts,
3193 EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
3194 ScanLineListBlock *pSLLBlock)
3196 register const QPoint *top,
3207 * initialize the Active Edge Table
3212 AET->bres.minor_axis = SMALL_COORDINATE;
3215 * initialize the Edge Table.
3217 ET->scanlines.next = 0;
3218 ET->ymax = SMALL_COORDINATE;
3219 ET->ymin = LARGE_COORDINATE;
3220 pSLLBlock->next = 0;
3222 PrevPt = &pts[count - 1];
3225 * for each vertex in the array of points.
3226 * In this loop we are dealing with two vertices at
3227 * a time -- these make up one edge of the polygon.
3233 * find out which point is above and which is below.
3235 if (PrevPt->y() > CurrPt->y()) {
3238 pETEs->ClockWise = 0;
3242 pETEs->ClockWise = 1;
3246 * don't add horizontal edges to the Edge table.
3248 if (bottom->y() != top->y()) {
3249 pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */
3252 * initialize integer edge algorithm
3254 dy = bottom->y() - top->y();
3255 BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
3257 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3259 if (PrevPt->y() > ET->ymax)
3260 ET->ymax = PrevPt->y();
3261 if (PrevPt->y() < ET->ymin)
3262 ET->ymin = PrevPt->y();
3273 * This routine moves EdgeTableEntries from the
3274 * EdgeTable into the Active Edge Table,
3275 * leaving them sorted by smaller x coordinate.
3279 static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
3281 register EdgeTableEntry *pPrevAET;
3282 register EdgeTableEntry *tmp;
3287 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3295 ETEs->back = pPrevAET;
3296 pPrevAET->next = ETEs;
3306 * This routine links the AET by the
3307 * nextWETE (winding EdgeTableEntry) link for
3308 * use by the winding number rule. The final
3309 * Active Edge Table (AET) might look something
3313 * ---------- --------- ---------
3314 * |ymax | |ymax | |ymax |
3315 * | ... | |... | |... |
3316 * |next |->|next |->|next |->...
3317 * |nextWETE| |nextWETE| |nextWETE|
3318 * --------- --------- ^--------
3320 * V-------------------> V---> ...
3323 static void computeWAET(register EdgeTableEntry *AET)
3325 register EdgeTableEntry *pWETE;
3326 register int inside = 1;
3327 register int isInside = 0;
3338 if ((!inside && !isInside) || (inside && isInside)) {
3339 pWETE->nextWETE = AET;
3345 pWETE->nextWETE = 0;
3351 * Just a simple insertion sort using
3352 * pointers and back pointers to sort the Active
3357 static int InsertionSort(register EdgeTableEntry *AET)
3359 register EdgeTableEntry *pETEchase;
3360 register EdgeTableEntry *pETEinsert;
3361 register EdgeTableEntry *pETEchaseBackTMP;
3362 register int changed = 0;
3368 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3369 pETEchase = pETEchase->back;
3372 if (pETEchase != pETEinsert) {
3373 pETEchaseBackTMP = pETEchase->back;
3374 pETEinsert->back->next = AET;
3376 AET->back = pETEinsert->back;
3377 pETEinsert->next = pETEchase;
3378 pETEchase->back->next = pETEinsert;
3379 pETEchase->back = pETEinsert;
3380 pETEinsert->back = pETEchaseBackTMP;
3390 static void FreeStorage(register ScanLineListBlock *pSLLBlock)
3392 register ScanLineListBlock *tmpSLLBlock;
3395 tmpSLLBlock = pSLLBlock->next;
3397 pSLLBlock = tmpSLLBlock;
3401 struct QRegionSpan {
3403 QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {}
3407 int width() const { return x2 - x1; }
3410 Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3412 static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend)
3414 QRect *regRects = reg->rects.data() + *lastRow;
3415 bool canExtend = reg->rects.size() - *lastRow == numSpans
3416 && !(*needsExtend && *extendTo + 1 != y)
3417 && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
3419 for (int i = 0; i < numSpans && canExtend; ++i) {
3420 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3426 *needsExtend = true;
3429 for (int i = 0; i < reg->rects.size() - *lastRow; ++i)
3430 regRects[i].setBottom(*extendTo);
3433 *lastRow = reg->rects.size();
3434 reg->rects.reserve(*lastRow + numSpans);
3435 for (int i = 0; i < numSpans; ++i)
3436 reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
3438 if (spans[0].x1 < reg->extents.left())
3439 reg->extents.setLeft(spans[0].x1);
3441 if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3442 reg->extents.setRight(spans[numSpans-1].x2 - 1);
3444 *needsExtend = false;
3449 * Create an array of rectangles from a list of points.
3450 * If indeed these things (POINTS, RECTS) are the same,
3451 * then this proc is still needed, because it allocates
3452 * storage for the array, which was allocated on the
3453 * stack by the calling procedure.
3456 static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
3457 POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
3461 bool needsExtend = false;
3462 QVarLengthArray<QRegionSpan> row;
3465 reg->extents.setLeft(INT_MAX);
3466 reg->extents.setRight(INT_MIN);
3467 reg->innerArea = -1;
3469 POINTBLOCK *CurPtBlock = FirstPtBlock;
3470 for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3471 /* the loop uses 2 points per iteration */
3472 int i = NUMPTSTOBUFFER >> 1;
3473 if (!numFullPtBlocks)
3474 i = iCurPtBlock >> 1;
3476 row.resize(qMax(row.size(), rowSize + i));
3477 for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) {
3478 const int width = pts[1].x() - pts[0].x();
3480 if (rowSize && row[rowSize-1].x2 == pts[0].x())
3481 row[rowSize-1].x2 = pts[1].x();
3483 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3487 QPoint *next = i ? &pts[2] : (numFullPtBlocks ? CurPtBlock->next->pts : 0);
3489 if (!next || next->y() != pts[0].y()) {
3490 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3496 CurPtBlock = CurPtBlock->next;
3500 for (int i = lastRow; i < reg->rects.size(); ++i)
3501 reg->rects[i].setBottom(extendTo);
3504 reg->numRects = reg->rects.size();
3506 if (reg->numRects) {
3507 reg->extents.setTop(reg->rects[0].top());
3508 reg->extents.setBottom(reg->rects[lastRow].bottom());
3510 for (int i = 0; i < reg->rects.size(); ++i)
3511 reg->updateInnerRect(reg->rects[i]);
3513 reg->extents.setCoords(0, 0, 0, 0);
3520 * Scan converts a polygon by returning a run-length
3521 * encoding of the resultant bitmap -- the run-length
3522 * encoding is in the form of an array of rectangles.
3524 * Can return 0 in case of errors.
3526 static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
3527 //Point *Pts; /* the pts */
3528 //int Count; /* number of pts */
3529 //int rule; /* winding rule */
3531 QRegionPrivate *region;
3532 register EdgeTableEntry *pAET; /* Active Edge Table */
3533 register int y; /* current scanline */
3534 register int iPts = 0; /* number of pts in buffer */
3535 register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
3536 register ScanLineList *pSLL; /* current scanLineList */
3537 register QPoint *pts; /* output buffer */
3538 EdgeTableEntry *pPrevAET; /* ptr to previous AET */
3539 EdgeTable ET; /* header node for ET */
3540 EdgeTableEntry AET; /* header node for AET */
3541 EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
3542 ScanLineListBlock SLLBlock; /* header for scanlinelist */
3543 int fixWAET = false;
3544 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
3545 FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
3546 POINTBLOCK *tmpPtBlock;
3547 int numFullPtBlocks = 0;
3549 if (!(region = new QRegionPrivate))
3552 /* special case a rectangle */
3553 if (((Count == 4) ||
3554 ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
3555 && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
3556 && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
3557 && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
3558 && (Pts[3].y() == Pts[0].y())))) {
3559 int x = qMin(Pts[0].x(), Pts[2].x());
3560 region->extents.setLeft(x);
3561 int y = qMin(Pts[0].y(), Pts[2].y());
3562 region->extents.setTop(y);
3563 region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
3564 region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
3565 if ((region->extents.left() <= region->extents.right()) &&
3566 (region->extents.top() <= region->extents.bottom())) {
3567 region->numRects = 1;
3568 region->innerRect = region->extents;
3569 region->innerArea = region->innerRect.width() * region->innerRect.height();
3574 if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
3577 region->vectorize();
3579 pts = FirstPtBlock.pts;
3580 CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
3582 pSLL = ET.scanlines.next;
3583 curPtBlock = &FirstPtBlock;
3585 // sanity check that the region won't become too big...
3586 if (ET.ymax - ET.ymin > 100000) {
3587 // clean up region ptr
3589 qWarning("QRegion: creating region from big polygon failed...!");
3597 if (rule == EvenOddRule) {
3601 for (y = ET.ymin; y < ET.ymax; ++y) {
3604 * Add a new edge to the active edge table when we
3605 * get to the next edge.
3607 if (pSLL && y == pSLL->scanline) {
3608 loadAET(&AET, pSLL->edgelist);
3615 * for each active edge
3618 pts->setX(pAET->bres.minor_axis);
3624 * send out the buffer
3626 if (iPts == NUMPTSTOBUFFER) {
3627 tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
3628 Q_CHECK_PTR(tmpPtBlock);
3629 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3630 curPtBlock->next = tmpPtBlock;
3631 curPtBlock = tmpPtBlock;
3632 pts = curPtBlock->pts;
3636 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
3638 InsertionSort(&AET);
3644 for (y = ET.ymin; y < ET.ymax; ++y) {
3646 * Add a new edge to the active edge table when we
3647 * get to the next edge.
3649 if (pSLL && y == pSLL->scanline) {
3650 loadAET(&AET, pSLL->edgelist);
3659 * for each active edge
3663 * add to the buffer only those edges that
3664 * are in the Winding active edge table.
3666 if (pWETE == pAET) {
3667 pts->setX(pAET->bres.minor_axis);
3673 * send out the buffer
3675 if (iPts == NUMPTSTOBUFFER) {
3676 tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
3677 tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3678 curPtBlock->next = tmpPtBlock;
3679 curPtBlock = tmpPtBlock;
3680 pts = curPtBlock->pts;
3684 pWETE = pWETE->nextWETE;
3686 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
3690 * recompute the winding active edge table if
3691 * we just resorted or have exited an edge.
3693 if (InsertionSort(&AET) || fixWAET) {
3700 FreeStorage(SLLBlock.next);
3701 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3702 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3703 tmpPtBlock = curPtBlock->next;
3705 curPtBlock = tmpPtBlock;
3708 return 0; // this function returns 0 in case of an error
3711 FreeStorage(SLLBlock.next);
3712 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3713 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3714 tmpPtBlock = curPtBlock->next;
3716 curPtBlock = tmpPtBlock;
3721 // END OF PolyReg.c extract
3723 QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
3725 QImage image = bitmap.toImage();
3727 QRegionPrivate *region = new QRegionPrivate;
3733 xr.setCoords(prev1, y, x-1, y); \
3734 UnionRectWithRegion(&xr, region, *region); \
3737 const uchar zero = 0;
3738 bool little = image.format() == QImage::Format_MonoLSB;
3742 for (y = 0; y < image.height(); ++y) {
3743 uchar *line = image.scanLine(y);
3744 int w = image.width();
3747 for (x = 0; x < w;) {
3748 uchar byte = line[x / 8];
3749 if (x > w - 8 || byte!=all) {
3751 for (int b = 8; b > 0 && x < w; --b) {
3752 if (!(byte & 0x01) == !all) {
3768 for (int b = 8; b > 0 && x < w; --b) {
3769 if (!(byte & 0x80) == !all) {
3804 QRegion::QRegion(const QRect &r, RegionType t)
3810 d = new QRegionData;
3812 if (t == Rectangle) {
3813 d->qt_rgn = new QRegionPrivate(r);
3814 } else if (t == Ellipse) {
3816 path.addEllipse(r.x(), r.y(), r.width(), r.height());
3817 QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
3818 d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
3823 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
3825 if (a.count() > 2) {
3826 QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
3827 fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
3829 d = new QRegionData;
3842 QRegion::QRegion(const QRegion &r)
3849 QRegion::QRegion(const QBitmap &bm)
3855 d = new QRegionData;
3857 d->qt_rgn = qt_bitmapToRegion(bm);
3861 void QRegion::cleanUp(QRegion::QRegionData *x)
3869 if (!d->ref.deref())
3874 QRegion &QRegion::operator=(const QRegion &r)
3877 if (!d->ref.deref())
3887 QRegion QRegion::copy() const
3890 QScopedPointer<QRegionData> x(new QRegionData);
3893 x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
3895 x->qt_rgn = new QRegionPrivate;
3896 if (!r.d->ref.deref())
3902 bool QRegion::isEmpty() const
3904 return d == &shared_empty || d->qt_rgn->numRects == 0;
3907 bool QRegion::isNull() const
3909 return d == &shared_empty || d->qt_rgn->numRects == 0;
3912 bool QRegion::contains(const QPoint &p) const
3914 return PointInRegion(d->qt_rgn, p.x(), p.y());
3917 bool QRegion::contains(const QRect &r) const
3919 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
3924 void QRegion::translate(int dx, int dy)
3926 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
3930 OffsetRegion(*d->qt_rgn, dx, dy);
3933 QRegion QRegion::united(const QRegion &r) const
3935 if (isEmptyHelper(d->qt_rgn))
3937 if (isEmptyHelper(r.d->qt_rgn))
3942 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3944 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3946 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3947 QRegion result(*this);
3949 result.d->qt_rgn->append(r.d->qt_rgn);
3951 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3952 QRegion result(*this);
3954 result.d->qt_rgn->prepend(r.d->qt_rgn);
3956 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3961 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
3966 QRegion& QRegion::operator+=(const QRegion &r)
3968 if (isEmptyHelper(d->qt_rgn))
3970 if (isEmptyHelper(r.d->qt_rgn))
3975 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3977 } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3979 } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3981 d->qt_rgn->append(r.d->qt_rgn);
3983 } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3985 d->qt_rgn->prepend(r.d->qt_rgn);
3987 } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3991 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
3996 QRegion QRegion::united(const QRect &r) const
3998 if (isEmptyHelper(d->qt_rgn))
4003 if (d->qt_rgn->contains(r)) {
4005 } else if (d->qt_rgn->within(r)) {
4007 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4009 } else if (d->qt_rgn->canAppend(&r)) {
4010 QRegion result(*this);
4012 result.d->qt_rgn->append(&r);
4014 } else if (d->qt_rgn->canPrepend(&r)) {
4015 QRegion result(*this);
4017 result.d->qt_rgn->prepend(&r);
4022 QRegionPrivate rp(r);
4023 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4028 QRegion& QRegion::operator+=(const QRect &r)
4030 if (isEmptyHelper(d->qt_rgn))
4035 if (d->qt_rgn->contains(r)) {
4037 } else if (d->qt_rgn->within(r)) {
4039 } else if (d->qt_rgn->canAppend(&r)) {
4041 d->qt_rgn->append(&r);
4043 } else if (d->qt_rgn->canPrepend(&r)) {
4045 d->qt_rgn->prepend(&r);
4047 } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4051 QRegionPrivate p(r);
4052 UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4057 QRegion QRegion::intersected(const QRegion &r) const
4059 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4060 || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4063 /* this is fully contained in r */
4064 if (r.d->qt_rgn->contains(*d->qt_rgn))
4067 /* r is fully contained in this */
4068 if (d->qt_rgn->contains(*r.d->qt_rgn))
4071 if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
4072 const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
4073 d->qt_rgn->extents);
4074 return QRegion(rect);
4075 } else if (r.d->qt_rgn->numRects == 1) {
4076 QRegion result(*this);
4078 result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4080 } else if (d->qt_rgn->numRects == 1) {
4083 result.d->qt_rgn->intersect(d->qt_rgn->extents);
4089 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
4092 * Can't alter dest's extents before we call miRegionOp because
4093 * it might be one of the source regions and miRegionOp depends
4094 * on the extents of those regions being the same. Besides, this
4095 * way there's no checking against rectangles that will be nuked
4096 * due to coalescing, so we have to examine fewer rectangles.
4098 miSetExtents(*result.d->qt_rgn);
4102 QRegion QRegion::intersected(const QRect &r) const
4104 if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4105 || !EXTENTCHECK(&d->qt_rgn->extents, &r))
4108 /* this is fully contained in r */
4109 if (d->qt_rgn->within(r))
4112 /* r is fully contained in this */
4113 if (d->qt_rgn->contains(r))
4116 if (d->qt_rgn->numRects == 1) {
4117 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4119 return QRegion(rect);
4122 QRegion result(*this);
4124 result.d->qt_rgn->intersect(r);
4128 QRegion QRegion::subtracted(const QRegion &r) const
4130 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4132 if (r.d->qt_rgn->contains(*d->qt_rgn))
4134 if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4136 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4139 #ifdef QT_REGION_DEBUG
4140 d->qt_rgn->selfTest();
4141 r.d->qt_rgn->selfTest();
4146 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4147 #ifdef QT_REGION_DEBUG
4148 result.d->qt_rgn->selfTest();
4153 QRegion QRegion::xored(const QRegion &r) const
4155 if (isEmptyHelper(d->qt_rgn)) {
4157 } else if (isEmptyHelper(r.d->qt_rgn)) {
4159 } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4161 } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4166 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4171 QRect QRegion::boundingRect() const
4175 return d->qt_rgn->extents;
4179 Returns true if \a rect is guaranteed to be fully contained in \a region.
4180 A false return value does not guarantee the opposite.
4183 bool qt_region_strictContains(const QRegion ®ion, const QRect &rect)
4185 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4188 #if 0 // TEST_INNERRECT
4189 static bool guard = false;
4193 QRegion inner = region.d->qt_rgn->innerRect;
4194 Q_ASSERT((inner - region).isEmpty());
4198 for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
4199 const QRect r = region.d->qt_rgn->rects.at(i);
4200 if (r.width() * r.height() > maxArea)
4201 maxArea = r.width() * r.height();
4204 if (maxArea > region.d->qt_rgn->innerArea) {
4205 qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
4207 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
4210 const QRect r1 = region.d->qt_rgn->innerRect;
4211 return (rect.left() >= r1.left() && rect.right() <= r1.right()
4212 && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
4215 QVector<QRect> QRegion::rects() const
4218 d->qt_rgn->vectorize();
4219 // hw: modify the vector size directly to avoid reallocation
4220 if (d->qt_rgn->rects.d != &QVectorData::shared_null)
4221 d->qt_rgn->rects.d->size = d->qt_rgn->numRects;
4222 return d->qt_rgn->rects;
4224 return QVector<QRect>();
4228 void QRegion::setRects(const QRect *rects, int num)
4231 if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
4236 d->qt_rgn->numRects = num;
4238 d->qt_rgn->extents = *rects;
4239 d->qt_rgn->innerRect = *rects;
4241 d->qt_rgn->rects.resize(num);
4247 for (int i = 0; i < num; ++i) {
4248 const QRect &rect = rects[i];
4249 d->qt_rgn->rects[i] = rect;
4250 left = qMin(rect.left(), left);
4251 right = qMax(rect.right(), right);
4252 top = qMin(rect.top(), top);
4253 bottom = qMax(rect.bottom(), bottom);
4254 d->qt_rgn->updateInnerRect(rect);
4256 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4260 int QRegion::rectCount() const
4262 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4266 bool QRegion::operator==(const QRegion &r) const
4276 return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4279 bool QRegion::intersects(const QRect &rect) const
4281 if (isEmptyHelper(d->qt_rgn) || rect.isNull())
4284 const QRect r = rect.normalized();
4285 if (!rect_intersects(d->qt_rgn->extents, r))
4287 if (d->qt_rgn->numRects == 1)
4290 const QVector<QRect> myRects = rects();
4291 for (QVector<QRect>::const_iterator it = myRects.constBegin(); it < myRects.constEnd(); ++it)
4292 if (rect_intersects(r, *it))