/src/qt/qtbase/src/gui/painting/qregion.cpp
C++ | 1742 lines | 837 code | 202 blank | 703 comment | 198 complexity | e0ef414cbef23183955023a02efb7560 MD5 | raw file
- /****************************************************************************
- **
- ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
- ** Contact: http://www.qt-project.org/legal
- **
- ** This file is part of the QtGui module of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:LGPL$
- ** Commercial License Usage
- ** Licensees holding valid commercial Qt licenses may use this file in
- ** accordance with the commercial license agreement provided with the
- ** Software or, alternatively, in accordance with the terms contained in
- ** a written agreement between you and Digia. For licensing terms and
- ** conditions see http://qt.digia.com/licensing. For further information
- ** use the contact form at http://qt.digia.com/contact-us.
- **
- ** GNU Lesser General Public License Usage
- ** Alternatively, this file may be used under the terms of the GNU Lesser
- ** General Public License version 2.1 as published by the Free Software
- ** Foundation and appearing in the file LICENSE.LGPL included in the
- ** packaging of this file. Please review the following information to
- ** ensure the GNU Lesser General Public License version 2.1 requirements
- ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- **
- ** In addition, as a special exception, Digia gives you certain additional
- ** rights. These rights are described in the Digia Qt LGPL Exception
- ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
- **
- ** GNU General Public License Usage
- ** Alternatively, this file may be used under the terms of the GNU
- ** General Public License version 3.0 as published by the Free Software
- ** Foundation and appearing in the file LICENSE.GPL included in the
- ** packaging of this file. Please review the following information to
- ** ensure the GNU General Public License version 3.0 requirements will be
- ** met: http://www.gnu.org/copyleft/gpl.html.
- **
- **
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
- #include "qregion.h"
- #include "qpainterpath.h"
- #include "qpolygon.h"
- #include "qbuffer.h"
- #include "qdatastream.h"
- #include "qvariant.h"
- #include "qvarlengtharray.h"
- #include "qimage.h"
- #include "qbitmap.h"
- #include <qdebug.h>
- QT_BEGIN_NAMESPACE
- /*!
- \class QRegion
- \brief The QRegion class specifies a clip region for a painter.
- \inmodule QtGui
- \ingroup painting
- \ingroup shared
- QRegion is used with QPainter::setClipRegion() to limit the paint
- area to what needs to be painted. There is also a QWidget::repaint()
- function that takes a QRegion parameter. QRegion is the best tool for
- minimizing the amount of screen area to be updated by a repaint.
- This class is not suitable for constructing shapes for rendering, especially
- as outlines. Use QPainterPath to create paths and shapes for use with
- QPainter.
- QRegion is an \l{implicitly shared} class.
- \section1 Creating and Using Regions
- A region can be created from a rectangle, an ellipse, a polygon or
- a bitmap. Complex regions may be created by combining simple
- regions using united(), intersected(), subtracted(), or xored() (exclusive
- or). You can move a region using translate().
- You can test whether a region isEmpty() or if it
- contains() a QPoint or QRect. The bounding rectangle can be found
- with boundingRect().
- The function rects() gives a decomposition of the region into
- rectangles.
- Example of using complex regions:
- \snippet code/src_gui_painting_qregion.cpp 0
- \section1 Additional License Information
- On Embedded Linux, Windows CE and X11 platforms, parts of this class rely on
- code obtained under the following licenses:
- \legalese
- Copyright (c) 1987 X Consortium
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of the X Consortium shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from the X Consortium.
- \endlegalese
- \br
- \legalese
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- \endlegalese
- \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
- */
- /*!
- \enum QRegion::RegionType
- Specifies the shape of the region to be created.
- \value Rectangle the region covers the entire rectangle.
- \value Ellipse the region is an ellipse inside the rectangle.
- */
- /*!
- \fn void QRegion::translate(const QPoint &point)
- \overload
- Translates the region \a{point}\e{.x()} along the x axis and
- \a{point}\e{.y()} along the y axis, relative to the current
- position. Positive values move the region to the right and down.
- Translates to the given \a point.
- */
- /*****************************************************************************
- QRegion member functions
- *****************************************************************************/
- /*!
- \fn QRegion::QRegion()
- Constructs an empty region.
- \sa isEmpty()
- */
- /*!
- \fn QRegion::QRegion(const QRect &r, RegionType t)
- \overload
- Create a region based on the rectange \a r with region type \a t.
- If the rectangle is invalid a null region will be created.
- \sa QRegion::RegionType
- */
- /*!
- \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
- Constructs a polygon region from the point array \a a with the fill rule
- specified by \a fillRule.
- If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
- using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
- algorithm is used.
- \warning This constructor can be used to create complex regions that will
- slow down painting when used.
- */
- /*!
- \fn QRegion::QRegion(const QRegion &r)
- Constructs a new region which is equal to region \a r.
- */
- /*!
- \fn QRegion::QRegion(const QBitmap &bm)
- Constructs a region from the bitmap \a bm.
- The resulting region consists of the pixels in bitmap \a bm that
- are Qt::color1, as if each pixel was a 1 by 1 rectangle.
- This constructor may create complex regions that will slow down
- painting when used. Note that drawing masked pixmaps can be done
- much faster using QPixmap::setMask().
- */
- /*!
- Constructs a rectangular or elliptic region.
- If \a t is \c Rectangle, the region is the filled rectangle (\a x,
- \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled
- ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size
- (\a w ,\a h).
- */
- QRegion::QRegion(int x, int y, int w, int h, RegionType t)
- {
- QRegion tmp(QRect(x, y, w, h), t);
- tmp.d->ref.ref();
- d = tmp.d;
- }
- /*!
- \fn QRegion::~QRegion()
- \internal
- Destroys the region.
- */
- void QRegion::detach()
- {
- if (d->ref.load() != 1)
- *this = copy();
- }
- // duplicates in qregion_win.cpp and qregion_wce.cpp
- #define QRGN_SETRECT 1 // region stream commands
- #define QRGN_SETELLIPSE 2 // (these are internal)
- #define QRGN_SETPTARRAY_ALT 3
- #define QRGN_SETPTARRAY_WIND 4
- #define QRGN_TRANSLATE 5
- #define QRGN_OR 6
- #define QRGN_AND 7
- #define QRGN_SUB 8
- #define QRGN_XOR 9
- #define QRGN_RECTS 10
- #ifndef QT_NO_DATASTREAM
- /*
- Executes region commands in the internal buffer and rebuilds the
- original region.
- We do this when we read a region from the data stream.
- If \a ver is non-0, uses the format version \a ver on reading the
- byte array.
- */
- void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
- {
- QByteArray copy = buffer;
- QDataStream s(©, QIODevice::ReadOnly);
- if (ver)
- s.setVersion(ver);
- s.setByteOrder(byteOrder);
- QRegion rgn;
- #ifndef QT_NO_DEBUG
- int test_cnt = 0;
- #endif
- while (!s.atEnd()) {
- qint32 id;
- if (s.version() == 1) {
- int id_int;
- s >> id_int;
- id = id_int;
- } else {
- s >> id;
- }
- #ifndef QT_NO_DEBUG
- if (test_cnt > 0 && id != QRGN_TRANSLATE)
- qWarning("QRegion::exec: Internal error");
- test_cnt++;
- #endif
- if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
- QRect r;
- s >> r;
- rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
- } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
- QPolygon a;
- s >> a;
- rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
- } else if (id == QRGN_TRANSLATE) {
- QPoint p;
- s >> p;
- rgn.translate(p.x(), p.y());
- } else if (id >= QRGN_OR && id <= QRGN_XOR) {
- QByteArray bop1, bop2;
- QRegion r1, r2;
- s >> bop1;
- r1.exec(bop1);
- s >> bop2;
- r2.exec(bop2);
- switch (id) {
- case QRGN_OR:
- rgn = r1.united(r2);
- break;
- case QRGN_AND:
- rgn = r1.intersected(r2);
- break;
- case QRGN_SUB:
- rgn = r1.subtracted(r2);
- break;
- case QRGN_XOR:
- rgn = r1.xored(r2);
- break;
- }
- } else if (id == QRGN_RECTS) {
- // (This is the only form used in Qt 2.0)
- quint32 n;
- s >> n;
- QRect r;
- for (int i=0; i<(int)n; i++) {
- s >> r;
- rgn = rgn.united(QRegion(r));
- }
- }
- }
- *this = rgn;
- }
- /*****************************************************************************
- QRegion stream functions
- *****************************************************************************/
- /*!
- \fn QRegion &QRegion::operator=(const QRegion &r)
- Assigns \a r to this region and returns a reference to the region.
- */
- /*!
- \fn QRegion &QRegion::operator=(QRegion &&other)
- Move-assigns \a other to this QRegion instance.
- \since 5.2
- */
- /*!
- \fn void QRegion::swap(QRegion &other)
- \since 4.8
- Swaps region \a other with this region. This operation is very
- fast and never fails.
- */
- /*!
- \relates QRegion
- Writes the region \a r to the stream \a s and returns a reference
- to the stream.
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
- */
- QDataStream &operator<<(QDataStream &s, const QRegion &r)
- {
- QVector<QRect> a = r.rects();
- if (a.isEmpty()) {
- s << (quint32)0;
- } else {
- if (s.version() == 1) {
- int i;
- for (i = a.size() - 1; i > 0; --i) {
- s << (quint32)(12 + i * 24);
- s << (int)QRGN_OR;
- }
- for (i = 0; i < a.size(); ++i) {
- s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i];
- }
- } else {
- s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect
- s << (qint32)QRGN_RECTS;
- s << a;
- }
- }
- return s;
- }
- /*!
- \relates QRegion
- Reads a region from the stream \a s into \a r and returns a
- reference to the stream.
- \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
- */
- QDataStream &operator>>(QDataStream &s, QRegion &r)
- {
- QByteArray b;
- s >> b;
- r.exec(b, s.version(), s.byteOrder());
- return s;
- }
- #endif //QT_NO_DATASTREAM
- #ifndef QT_NO_DEBUG_STREAM
- QDebug operator<<(QDebug s, const QRegion &r)
- {
- QVector<QRect> rects = r.rects();
- s.nospace() << "QRegion(size=" << rects.size() << "), "
- << "bounds = " << r.boundingRect() << '\n';
- for (int i=0; i<rects.size(); ++i)
- s << "- " << i << rects.at(i) << '\n';
- return s;
- }
- #endif
- // These are not inline - they can be implemented better on some platforms
- // (eg. Windows at least provides 3-variable operations). For now, simple.
- /*!
- Applies the united() function to this region and \a r. \c r1|r2 is
- equivalent to \c r1.united(r2).
- \sa united(), operator+()
- */
- const QRegion QRegion::operator|(const QRegion &r) const
- { return united(r); }
- /*!
- Applies the united() function to this region and \a r. \c r1+r2 is
- equivalent to \c r1.united(r2).
- \sa united(), operator|()
- */
- const QRegion QRegion::operator+(const QRegion &r) const
- { return united(r); }
- /*!
- \overload
- \since 4.4
- */
- const QRegion QRegion::operator+(const QRect &r) const
- { return united(r); }
- /*!
- Applies the intersected() function to this region and \a r. \c r1&r2
- is equivalent to \c r1.intersected(r2).
- \sa intersected()
- */
- const QRegion QRegion::operator&(const QRegion &r) const
- { return intersected(r); }
- /*!
- \overload
- \since 4.4
- */
- const QRegion QRegion::operator&(const QRect &r) const
- {
- return intersected(r);
- }
- /*!
- Applies the subtracted() function to this region and \a r. \c r1-r2
- is equivalent to \c r1.subtracted(r2).
- \sa subtracted()
- */
- const QRegion QRegion::operator-(const QRegion &r) const
- { return subtracted(r); }
- /*!
- Applies the xored() function to this region and \a r. \c r1^r2 is
- equivalent to \c r1.xored(r2).
- \sa xored()
- */
- const QRegion QRegion::operator^(const QRegion &r) const
- { return xored(r); }
- /*!
- Applies the united() function to this region and \a r and assigns
- the result to this region. \c r1|=r2 is equivalent to \c
- {r1 = r1.united(r2)}.
- \sa united()
- */
- QRegion& QRegion::operator|=(const QRegion &r)
- { return *this = *this | r; }
- /*!
- \fn QRegion& QRegion::operator+=(const QRect &rect)
- Returns a region that is the union of this region with the specified \a rect.
- \sa united()
- */
- /*!
- \fn QRegion& QRegion::operator+=(const QRegion &r)
- Applies the united() function to this region and \a r and assigns
- the result to this region. \c r1+=r2 is equivalent to \c
- {r1 = r1.united(r2)}.
- \sa intersected()
- */
- #if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN)
- QRegion& QRegion::operator+=(const QRect &r)
- {
- return operator+=(QRegion(r));
- }
- #endif
- /*!
- \fn QRegion& QRegion::operator&=(const QRegion &r)
- Applies the intersected() function to this region and \a r and
- assigns the result to this region. \c r1&=r2 is equivalent to \c
- r1 = r1.intersected(r2).
- \sa intersected()
- */
- QRegion& QRegion::operator&=(const QRegion &r)
- { return *this = *this & r; }
- /*!
- \overload
- \since 4.4
- */
- #if defined (Q_OS_UNIX) || defined (Q_OS_WIN)
- QRegion& QRegion::operator&=(const QRect &r)
- {
- return *this = *this & r;
- }
- #else
- QRegion& QRegion::operator&=(const QRect &r)
- {
- return *this &= (QRegion(r));
- }
- #endif
- /*!
- \fn QRegion& QRegion::operator-=(const QRegion &r)
- Applies the subtracted() function to this region and \a r and
- assigns the result to this region. \c r1-=r2 is equivalent to \c
- {r1 = r1.subtracted(r2)}.
- \sa subtracted()
- */
- QRegion& QRegion::operator-=(const QRegion &r)
- { return *this = *this - r; }
- /*!
- Applies the xored() function to this region and \a r and
- assigns the result to this region. \c r1^=r2 is equivalent to \c
- {r1 = r1.xored(r2)}.
- \sa xored()
- */
- QRegion& QRegion::operator^=(const QRegion &r)
- { return *this = *this ^ r; }
- /*!
- \fn bool QRegion::operator!=(const QRegion &other) const
- Returns \c true if this region is different from the \a other region;
- otherwise returns \c false.
- */
- /*!
- Returns the region as a QVariant
- */
- QRegion::operator QVariant() const
- {
- return QVariant(QVariant::Region, this);
- }
- /*!
- \fn bool QRegion::operator==(const QRegion &r) const
- Returns \c true if the region is equal to \a r; otherwise returns
- false.
- */
- /*!
- \fn void QRegion::translate(int dx, int dy)
- Translates (moves) the region \a dx along the X axis and \a dy
- along the Y axis.
- */
- /*!
- \fn QRegion QRegion::translated(const QPoint &p) const
- \overload
- \since 4.1
- Returns a copy of the regtion that is translated \a{p}\e{.x()}
- along the x axis and \a{p}\e{.y()} along the y axis, relative to
- the current position. Positive values move the rectangle to the
- right and down.
- \sa translate()
- */
- /*!
- \since 4.1
- Returns a copy of the region that is translated \a dx along the
- x axis and \a dy along the y axis, relative to the current
- position. Positive values move the region to the right and
- down.
- \sa translate()
- */
- QRegion
- QRegion::translated(int dx, int dy) const
- {
- QRegion ret(*this);
- ret.translate(dx, dy);
- return ret;
- }
- inline bool rect_intersects(const QRect &r1, const QRect &r2)
- {
- return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
- r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
- }
- /*!
- \since 4.2
- Returns \c true if this region intersects with \a region, otherwise
- returns \c false.
- */
- bool QRegion::intersects(const QRegion ®ion) const
- {
- if (isEmpty() || region.isEmpty())
- return false;
- if (!rect_intersects(boundingRect(), region.boundingRect()))
- return false;
- if (rectCount() == 1 && region.rectCount() == 1)
- return true;
- const QVector<QRect> myRects = rects();
- const QVector<QRect> otherRects = region.rects();
- for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1)
- for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2)
- if (rect_intersects(*i1, *i2))
- return true;
- return false;
- }
- /*!
- \fn bool QRegion::intersects(const QRect &rect) const
- \since 4.2
- Returns \c true if this region intersects with \a rect, otherwise
- returns \c false.
- */
- #if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN)
- /*!
- \overload
- \since 4.4
- */
- QRegion QRegion::intersect(const QRect &r) const
- {
- return intersect(QRegion(r));
- }
- #endif
- /*!
- \fn int QRegion::rectCount() const
- \since 4.6
- Returns the number of rectangles that will be returned in rects().
- */
- /*!
- \fn bool QRegion::isEmpty() const
- Returns \c true if the region is empty; otherwise returns \c false. An
- empty region is a region that contains no points.
- Example:
- \snippet code/src_gui_painting_qregion_unix.cpp 0
- */
- /*!
- \fn bool QRegion::isNull() const
- \since 5.0
- Returns \c true if the region is empty; otherwise returns \c false. An
- empty region is a region that contains no points. This function is
- the same as isEmpty
- \sa isEmpty()
- */
- /*!
- \fn bool QRegion::contains(const QPoint &p) const
- Returns \c true if the region contains the point \a p; otherwise
- returns \c false.
- */
- /*!
- \fn bool QRegion::contains(const QRect &r) const
- \overload
- Returns \c true if the region overlaps the rectangle \a r; otherwise
- returns \c false.
- */
- /*!
- \fn QRegion QRegion::unite(const QRegion &r) const
- \obsolete
- Use united(\a r) instead.
- */
- /*!
- \fn QRegion QRegion::unite(const QRect &rect) const
- \since 4.4
- \obsolete
- Use united(\a rect) instead.
- */
- /*!
- \fn QRegion QRegion::united(const QRect &rect) const
- \since 4.4
- Returns a region which is the union of this region and the given \a rect.
- \sa intersected(), subtracted(), xored()
- */
- /*!
- \fn QRegion QRegion::united(const QRegion &r) const
- \since 4.2
- Returns a region which is the union of this region and \a r.
- \image runion.png Region Union
- The figure shows the union of two elliptical regions.
- \sa intersected(), subtracted(), xored()
- */
- /*!
- \fn QRegion QRegion::intersect(const QRegion &r) const
- \obsolete
- Use intersected(\a r) instead.
- */
- /*!
- \fn QRegion QRegion::intersect(const QRect &rect) const
- \since 4.4
- \obsolete
- Use intersected(\a rect) instead.
- */
- /*!
- \fn QRegion QRegion::intersected(const QRect &rect) const
- \since 4.4
- Returns a region which is the intersection of this region and the given \a rect.
- \sa subtracted(), united(), xored()
- */
- /*!
- \fn QRegion QRegion::intersected(const QRegion &r) const
- \since 4.2
- Returns a region which is the intersection of this region and \a r.
- \image rintersect.png Region Intersection
- The figure shows the intersection of two elliptical regions.
- \sa subtracted(), united(), xored()
- */
- /*!
- \fn QRegion QRegion::subtract(const QRegion &r) const
- \obsolete
- Use subtracted(\a r) instead.
- */
- /*!
- \fn QRegion QRegion::subtracted(const QRegion &r) const
- \since 4.2
- Returns a region which is \a r subtracted from this region.
- \image rsubtract.png Region Subtraction
- The figure shows the result when the ellipse on the right is
- subtracted from the ellipse on the left (\c {left - right}).
- \sa intersected(), united(), xored()
- */
- /*!
- \fn QRegion QRegion::eor(const QRegion &r) const
- \obsolete
- Use xored(\a r) instead.
- */
- /*!
- \fn QRegion QRegion::xored(const QRegion &r) const
- \since 4.2
- Returns a region which is the exclusive or (XOR) of this region
- and \a r.
- \image rxor.png Region XORed
- The figure shows the exclusive or of two elliptical regions.
- \sa intersected(), united(), subtracted()
- */
- /*!
- \fn QRect QRegion::boundingRect() const
- Returns the bounding rectangle of this region. An empty region
- gives a rectangle that is QRect::isNull().
- */
- /*!
- \fn QVector<QRect> QRegion::rects() const
- Returns an array of non-overlapping rectangles that make up the
- region.
- The union of all the rectangles is equal to the original region.
- */
- /*!
- \fn void QRegion::setRects(const QRect *rects, int number)
- Sets the region using the array of rectangles specified by \a rects and
- \a number.
- The rectangles \e must be optimally Y-X sorted and follow these restrictions:
- \list
- \li The rectangles must not intersect.
- \li All rectangles with a given top coordinate must have the same height.
- \li No two rectangles may abut horizontally (they should be combined
- into a single wider rectangle in that case).
- \li The rectangles must be sorted in ascending order, with Y as the major
- sort key and X as the minor sort key.
- \endlist
- \omit
- Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X).
- \endomit
- */
- namespace {
- struct Segment
- {
- Segment() {}
- Segment(const QPoint &p)
- : added(false)
- , point(p)
- {
- }
- int left() const
- {
- return qMin(point.x(), next->point.x());
- }
- int right() const
- {
- return qMax(point.x(), next->point.x());
- }
- bool overlaps(const Segment &other) const
- {
- return left() < other.right() && other.left() < right();
- }
- void connect(Segment &other)
- {
- next = &other;
- other.prev = this;
- horizontal = (point.y() == other.point.y());
- }
- void merge(Segment &other)
- {
- if (right() <= other.right()) {
- QPoint p = other.point;
- Segment *oprev = other.prev;
- other.point = point;
- other.prev = prev;
- prev->next = &other;
- point = p;
- prev = oprev;
- oprev->next = this;
- } else {
- Segment *onext = other.next;
- other.next = next;
- next->prev = &other;
- next = onext;
- next->prev = this;
- }
- }
- int horizontal : 1;
- int added : 1;
- QPoint point;
- Segment *prev;
- Segment *next;
- };
- void mergeSegments(Segment *a, int na, Segment *b, int nb)
- {
- int i = 0;
- int j = 0;
- while (i != na && j != nb) {
- Segment &sa = a[i];
- Segment &sb = b[j];
- const int ra = sa.right();
- const int rb = sb.right();
- if (sa.overlaps(sb))
- sa.merge(sb);
- i += (rb >= ra);
- j += (ra >= rb);
- }
- }
- void addSegmentsToPath(Segment *segment, QPainterPath &path)
- {
- Segment *current = segment;
- path.moveTo(current->point);
- current->added = true;
- Segment *last = current;
- current = current->next;
- while (current != segment) {
- if (current->horizontal != last->horizontal)
- path.lineTo(current->point);
- current->added = true;
- last = current;
- current = current->next;
- }
- }
- }
- Q_GUI_EXPORT QPainterPath qt_regionToPath(const QRegion ®ion)
- {
- QPainterPath result;
- if (region.rectCount() == 1) {
- result.addRect(region.boundingRect());
- return result;
- }
- const QVector<QRect> rects = region.rects();
- QVarLengthArray<Segment> segments;
- segments.resize(4 * rects.size());
- const QRect *rect = rects.constData();
- const QRect *end = rect + rects.size();
- int lastRowSegmentCount = 0;
- Segment *lastRowSegments = 0;
- int lastSegment = 0;
- int lastY = 0;
- while (rect != end) {
- const int y = rect[0].y();
- int count = 0;
- while (&rect[count] != end && rect[count].y() == y)
- ++count;
- for (int i = 0; i < count; ++i) {
- int offset = lastSegment + i;
- segments[offset] = Segment(rect[i].topLeft());
- segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
- segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
- segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
- offset = lastSegment + i;
- for (int j = 0; j < 4; ++j)
- segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
- }
- if (lastRowSegments && lastY == y)
- mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
- lastRowSegments = &segments[lastSegment + 2 * count];
- lastRowSegmentCount = count;
- lastSegment += 4 * count;
- lastY = y + rect[0].height();
- rect += count;
- }
- for (int i = 0; i < lastSegment; ++i) {
- Segment *segment = &segments[i];
- if (!segment->added)
- addSegmentsToPath(segment, result);
- }
- return result;
- }
- #if defined(Q_OS_UNIX) || defined(Q_OS_WIN)
- //#define QT_REGION_DEBUG
- /*
- * clip region
- */
- struct QRegionPrivate {
- int numRects;
- QVector<QRect> rects;
- QRect extents;
- QRect innerRect;
- int innerArea;
- inline QRegionPrivate() : numRects(0), innerArea(-1) {}
- inline QRegionPrivate(const QRect &r) {
- numRects = 1;
- extents = r;
- innerRect = r;
- innerArea = r.width() * r.height();
- }
- inline QRegionPrivate(const QRegionPrivate &r) {
- rects = r.rects;
- numRects = r.numRects;
- extents = r.extents;
- innerRect = r.innerRect;
- innerArea = r.innerArea;
- }
- inline QRegionPrivate &operator=(const QRegionPrivate &r) {
- rects = r.rects;
- numRects = r.numRects;
- extents = r.extents;
- innerRect = r.innerRect;
- innerArea = r.innerArea;
- return *this;
- }
- void intersect(const QRect &r);
- /*
- * Returns \c true if r is guaranteed to be fully contained in this region.
- * A false return value does not guarantee the opposite.
- */
- inline bool contains(const QRegionPrivate &r) const {
- return contains(r.extents);
- }
- inline bool contains(const QRect &r2) const {
- const QRect &r1 = innerRect;
- return r2.left() >= r1.left() && r2.right() <= r1.right()
- && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
- }
- /*
- * Returns \c true if this region is guaranteed to be fully contained in r.
- */
- inline bool within(const QRect &r1) const {
- const QRect &r2 = extents;
- return r2.left() >= r1.left() && r2.right() <= r1.right()
- && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
- }
- inline void updateInnerRect(const QRect &rect) {
- const int area = rect.width() * rect.height();
- if (area > innerArea) {
- innerArea = area;
- innerRect = rect;
- }
- }
- inline void vectorize() {
- if (numRects == 1) {
- if (!rects.size())
- rects.resize(1);
- rects[0] = extents;
- }
- }
- inline void append(const QRect *r);
- void append(const QRegionPrivate *r);
- void prepend(const QRect *r);
- void prepend(const QRegionPrivate *r);
- inline bool canAppend(const QRect *r) const;
- inline bool canAppend(const QRegionPrivate *r) const;
- inline bool canPrepend(const QRect *r) const;
- inline bool canPrepend(const QRegionPrivate *r) const;
- inline bool mergeFromRight(QRect *left, const QRect *right);
- inline bool mergeFromLeft(QRect *left, const QRect *right);
- inline bool mergeFromBelow(QRect *top, const QRect *bottom,
- const QRect *nextToTop,
- const QRect *nextToBottom);
- inline bool mergeFromAbove(QRect *bottom, const QRect *top,
- const QRect *nextToBottom,
- const QRect *nextToTop);
- #ifdef QT_REGION_DEBUG
- void selfTest() const;
- #endif
- };
- static inline bool isEmptyHelper(const QRegionPrivate *preg)
- {
- return !preg || preg->numRects == 0;
- }
- static inline bool canMergeFromRight(const QRect *left, const QRect *right)
- {
- return (right->top() == left->top()
- && right->bottom() == left->bottom()
- && right->left() <= (left->right() + 1));
- }
- static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
- {
- return canMergeFromRight(left, right);
- }
- bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right)
- {
- if (canMergeFromRight(left, right)) {
- left->setRight(right->right());
- updateInnerRect(*left);
- return true;
- }
- return false;
- }
- bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left)
- {
- if (canMergeFromLeft(right, left)) {
- right->setLeft(left->left());
- updateInnerRect(*right);
- return true;
- }
- return false;
- }
- static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom,
- const QRect *nextToTop,
- const QRect *nextToBottom)
- {
- if (nextToTop && nextToTop->y() == top->y())
- return false;
- if (nextToBottom && nextToBottom->y() == bottom->y())
- return false;
- return ((top->bottom() >= (bottom->top() - 1))
- && top->left() == bottom->left()
- && top->right() == bottom->right());
- }
- bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom,
- const QRect *nextToTop,
- const QRect *nextToBottom)
- {
- if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
- top->setBottom(bottom->bottom());
- updateInnerRect(*top);
- return true;
- }
- return false;
- }
- bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top,
- const QRect *nextToBottom,
- const QRect *nextToTop)
- {
- if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
- bottom->setTop(top->top());
- updateInnerRect(*bottom);
- return true;
- }
- return false;
- }
- static inline QRect qt_rect_intersect_normalized(const QRect &r1,
- const QRect &r2)
- {
- QRect r;
- r.setLeft(qMax(r1.left(), r2.left()));
- r.setRight(qMin(r1.right(), r2.right()));
- r.setTop(qMax(r1.top(), r2.top()));
- r.setBottom(qMin(r1.bottom(), r2.bottom()));
- return r;
- }
- void QRegionPrivate::intersect(const QRect &rect)
- {
- Q_ASSERT(extents.intersects(rect));
- Q_ASSERT(numRects > 1);
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- const QRect r = rect.normalized();
- extents = QRect();
- innerRect = QRect();
- innerArea = -1;
- QRect *dest = rects.data();
- const QRect *src = dest;
- int n = numRects;
- numRects = 0;
- while (n--) {
- *dest = qt_rect_intersect_normalized(*src++, r);
- if (dest->isEmpty())
- continue;
- if (numRects == 0) {
- extents = *dest;
- } else {
- extents.setLeft(qMin(extents.left(), dest->left()));
- // hw: extents.top() will never change after initialization
- //extents.setTop(qMin(extents.top(), dest->top()));
- extents.setRight(qMax(extents.right(), dest->right()));
- extents.setBottom(qMax(extents.bottom(), dest->bottom()));
- const QRect *nextToLast = (numRects > 1 ? dest - 2 : 0);
- // mergeFromBelow inlined and optimized
- if (canMergeFromBelow(dest - 1, dest, nextToLast, 0)) {
- if (!n || src->y() != dest->y() || src->left() > r.right()) {
- QRect *prev = dest - 1;
- prev->setBottom(dest->bottom());
- updateInnerRect(*prev);
- continue;
- }
- }
- }
- updateInnerRect(*dest);
- ++dest;
- ++numRects;
- }
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- }
- void QRegionPrivate::append(const QRect *r)
- {
- Q_ASSERT(!r->isEmpty());
- QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
- if (mergeFromRight(myLast, r)) {
- if (numRects > 1) {
- const QRect *nextToTop = (numRects > 2 ? myLast - 2 : 0);
- if (mergeFromBelow(myLast - 1, myLast, nextToTop, 0))
- --numRects;
- }
- } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : 0), 0)) {
- // nothing
- } else {
- vectorize();
- ++numRects;
- updateInnerRect(*r);
- if (rects.size() < numRects)
- rects.resize(numRects);
- rects[numRects - 1] = *r;
- }
- extents.setCoords(qMin(extents.left(), r->left()),
- qMin(extents.top(), r->top()),
- qMax(extents.right(), r->right()),
- qMax(extents.bottom(), r->bottom()));
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- }
- void QRegionPrivate::append(const QRegionPrivate *r)
- {
- Q_ASSERT(!isEmptyHelper(r));
- if (r->numRects == 1) {
- append(&r->extents);
- return;
- }
- vectorize();
- QRect *destRect = rects.data() + numRects;
- const QRect *srcRect = r->rects.constData();
- int numAppend = r->numRects;
- // try merging
- {
- const QRect *rFirst = srcRect;
- QRect *myLast = destRect - 1;
- const QRect *nextToLast = (numRects > 1 ? myLast - 1 : 0);
- if (mergeFromRight(myLast, rFirst)) {
- ++srcRect;
- --numAppend;
- const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : 0);
- if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) {
- ++srcRect;
- --numAppend;
- }
- if (numRects > 1) {
- nextToLast = (numRects > 2 ? myLast - 2 : 0);
- rNextToFirst = (numAppend > 0 ? srcRect : 0);
- if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) {
- --destRect;
- --numRects;
- }
- }
- } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) {
- ++srcRect;
- --numAppend;
- }
- }
- // append rectangles
- if (numAppend > 0) {
- const int newNumRects = numRects + numAppend;
- if (newNumRects > rects.size()) {
- rects.resize(newNumRects);
- destRect = rects.data() + numRects;
- }
- memcpy(destRect, srcRect, numAppend * sizeof(QRect));
- numRects = newNumRects;
- }
- // update inner rectangle
- if (innerArea < r->innerArea) {
- innerArea = r->innerArea;
- innerRect = r->innerRect;
- }
- // update extents
- destRect = &extents;
- srcRect = &r->extents;
- extents.setCoords(qMin(destRect->left(), srcRect->left()),
- qMin(destRect->top(), srcRect->top()),
- qMax(destRect->right(), srcRect->right()),
- qMax(destRect->bottom(), srcRect->bottom()));
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- }
- void QRegionPrivate::prepend(const QRegionPrivate *r)
- {
- Q_ASSERT(!isEmptyHelper(r));
- if (r->numRects == 1) {
- prepend(&r->extents);
- return;
- }
- vectorize();
- int numPrepend = r->numRects;
- int numSkip = 0;
- // try merging
- {
- QRect *myFirst = rects.data();
- const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : 0);
- const QRect *rLast = r->rects.constData() + r->numRects - 1;
- const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : 0);
- if (mergeFromLeft(myFirst, rLast)) {
- --numPrepend;
- --rLast;
- rNextToLast = (numPrepend > 1 ? rLast - 1 : 0);
- if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
- --numPrepend;
- --rLast;
- }
- if (numRects > 1) {
- nextToFirst = (numRects > 2? myFirst + 2 : 0);
- rNextToLast = (numPrepend > 0 ? rLast : 0);
- if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) {
- --numRects;
- ++numSkip;
- }
- }
- } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
- --numPrepend;
- }
- }
- if (numPrepend > 0) {
- const int newNumRects = numRects + numPrepend;
- if (newNumRects > rects.size())
- rects.resize(newNumRects);
- // move existing rectangles
- memmove(rects.data() + numPrepend, rects.constData() + numSkip,
- numRects * sizeof(QRect));
- // prepend new rectangles
- memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect));
- numRects = newNumRects;
- }
- // update inner rectangle
- if (innerArea < r->innerArea) {
- innerArea = r->innerArea;
- innerRect = r->innerRect;
- }
- // update extents
- extents.setCoords(qMin(extents.left(), r->extents.left()),
- qMin(extents.top(), r->extents.top()),
- qMax(extents.right(), r->extents.right()),
- qMax(extents.bottom(), r->extents.bottom()));
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- }
- void QRegionPrivate::prepend(const QRect *r)
- {
- Q_ASSERT(!r->isEmpty());
- QRect *myFirst = (numRects == 1 ? &extents : rects.data());
- if (mergeFromLeft(myFirst, r)) {
- if (numRects > 1) {
- const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : 0);
- if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, 0)) {
- --numRects;
- memmove(rects.data(), rects.constData() + 1,
- numRects * sizeof(QRect));
- }
- }
- } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : 0), 0)) {
- // nothing
- } else {
- vectorize();
- ++numRects;
- updateInnerRect(*r);
- rects.prepend(*r);
- }
- extents.setCoords(qMin(extents.left(), r->left()),
- qMin(extents.top(), r->top()),
- qMax(extents.right(), r->right()),
- qMax(extents.bottom(), r->bottom()));
- #ifdef QT_REGION_DEBUG
- selfTest();
- #endif
- }
- bool QRegionPrivate::canAppend(const QRect *r) const
- {
- Q_ASSERT(!r->isEmpty());
- const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
- if (r->top() > myLast->bottom())
- return true;
- if (r->top() == myLast->top()
- && r->height() == myLast->height()
- && r->left() > myLast->right())
- {
- return true;
- }
- return false;
- }
- bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
- {
- return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
- }
- bool QRegionPrivate::canPrepend(const QRect *r) const
- {
- Q_ASSERT(!r->isEmpty());
- const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
- if (r->bottom() < myFirst->top()) // not overlapping
- return true;
- if (r->top() == myFirst->top()
- && r->height() == myFirst->height()
- && r->right() < myFirst->left())
- {
- return true;
- }
- return false;
- }
- bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
- {
- return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1);
- }
- #ifdef QT_REGION_DEBUG
- void QRegionPrivate::selfTest() const
- {
- if (numRects == 0) {
- Q_ASSERT(extents.isEmpty());
- Q_ASSERT(innerRect.isEmpty());
- return;
- }
- Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
- if (numRects == 1) {
- Q_ASSERT(innerRect == extents);
- Q_ASSERT(!innerRect.isEmpty());
- return;
- }
- for (int i = 0; i < numRects; ++i) {
- const QRect r = rects.at(i);
- if ((r.width() * r.height()) > innerArea)
- qDebug() << "selfTest(): innerRect" << innerRect << '<' << r;
- }
- QRect r = rects.first();
- for (int i = 1; i < numRects; ++i) {
- const QRect r2 = rects.at(i);
- Q_ASSERT(!r2.isEmpty());
- if (r2.y() == r.y()) {
- Q_ASSERT(r.bottom() == r2.bottom());
- Q_ASSERT(r.right() < (r2.left() + 1));
- } else {
- Q_ASSERT(r2.y() >= r.bottom());
- }
- r = r2;
- }
- }
- #endif // QT_REGION_DEBUG
- static QRegionPrivate qrp;
- QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp};
- typedef void (*OverlapFunc)(QRegionPrivate &dest, const QRect *r1, const QRect *r1End,
- const QRect *r2, const QRect *r2End, int y1, int y2);
- typedef void (*NonOverlapFunc)(QRegionPrivate &dest, const QRect *r, const QRect *rEnd,
- int y1, int y2);
- static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
- static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
- static void miRegionOp(QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
- OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
- NonOverlapFunc nonOverlap2Func);
- #define RectangleOut 0
- #define RectangleIn 1
- #define RectanglePart 2
- #define EvenOddRule 0
- #define WindingRule 1
- // START OF region.h extract
- /* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
- /************************************************************************
- Copyright (c) 1987 X Consortium
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of the X Consortium shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from the X Consortium.
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- ************************************************************************/
- #ifndef _XREGION_H
- #define _XREGION_H
- QT_BEGIN_INCLUDE_NAMESPACE
- #include <limits.h>
- QT_END_INCLUDE_NAMESPACE
- /* 1 if two BOXes overlap.
- * 0 if two BOXes do not overlap.
- * Remember, x2 and y2 are not in the region
- */
- #define EXTENTCHECK(r1, r2) \
- ((r1)->right() >= (r2)->left() && \
- (r1)->left() <= (r2)->right() && \
- (r1)->bottom() >= (r2)->top() && \
- (r1)->top() <= (r2)->bottom())
- /*
- * update region extents
- */
- #define EXTENTS(r,idRect){\
- if((r)->left() < (idRect)->extents.left())\
- (idRect)->extents.setLeft((r)->left());\
- if((r)->top() < (idRect)->extents.top())\
- (idRect)->extents.setTop((r)->top());\
- if((r)->right() > (idRect)->extents.right())\
- (idRect)->extents.setRight((r)->right());\
- if((r)->bottom() > (idRect)->extents.bottom())\
- (idRect)->extents.setBottom((r)->bottom());\
- }
- /*
- * Check to see if there is enough memory in the present region.
- */
- #define MEMCHECK(dest, rect, firstrect){\
- if ((dest).numRects >= ((dest).rects.size()-1)){\
- firstrect.resize(firstrect.size() * 2); \
- (rect) = (firstrect).data() + (dest).numRects;\
- }\
- }
- /*
- * number of points to buffer before sending them off
- * to scanlines(): Must be an even number
- */
- #define NUMPTSTOBUFFER 200
- /*
- * used to allocate buffers for points and link
- * the buffers together
- */
- typedef struct _POINTBLOCK {
- char data[NUMPTSTOBUFFER * sizeof(QPoint)];
- QPoint *pts;
- struct _POINTBLOCK *next;
- } POINTBLOCK;
- #endif
- // END OF region.h extract
- // START OF Region.c extract
- /* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
- /************************************************************************
- Copyright (c) 1987, 1988 X Consortium
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PAR