PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/gui/painting/qregion.cpp

https://bitbucket.org/kasimling/qt
C++ | 1768 lines | 866 code | 206 blank | 696 comment | 202 complexity | bbe97bc48561b593c7b3d58221a7d16b MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the QtGui module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qregion.h"
  42. #include "qpainterpath.h"
  43. #include "qpolygon.h"
  44. #include "qbuffer.h"
  45. #include "qdatastream.h"
  46. #include "qvariant.h"
  47. #include "qvarlengtharray.h"
  48. #include <qdebug.h>
  49. #if defined(Q_OS_UNIX) || defined(Q_WS_WIN)
  50. #include "qimage.h"
  51. #include "qbitmap.h"
  52. #include <stdlib.h>
  53. #endif
  54. QT_BEGIN_NAMESPACE
  55. /*!
  56. \class QRegion
  57. \brief The QRegion class specifies a clip region for a painter.
  58. \ingroup painting
  59. \ingroup shared
  60. QRegion is used with QPainter::setClipRegion() to limit the paint
  61. area to what needs to be painted. There is also a QWidget::repaint()
  62. function that takes a QRegion parameter. QRegion is the best tool for
  63. minimizing the amount of screen area to be updated by a repaint.
  64. This class is not suitable for constructing shapes for rendering, especially
  65. as outlines. Use QPainterPath to create paths and shapes for use with
  66. QPainter.
  67. QRegion is an \l{implicitly shared} class.
  68. \section1 Creating and Using Regions
  69. A region can be created from a rectangle, an ellipse, a polygon or
  70. a bitmap. Complex regions may be created by combining simple
  71. regions using united(), intersected(), subtracted(), or xored() (exclusive
  72. or). You can move a region using translate().
  73. You can test whether a region isEmpty() or if it
  74. contains() a QPoint or QRect. The bounding rectangle can be found
  75. with boundingRect().
  76. The function rects() gives a decomposition of the region into
  77. rectangles.
  78. Example of using complex regions:
  79. \snippet doc/src/snippets/code/src_gui_painting_qregion.cpp 0
  80. \section1 Additional License Information
  81. On Embedded Linux, Windows CE and X11 platforms, parts of this class rely on
  82. code obtained under the following licenses:
  83. \legalese
  84. Copyright (c) 1987 X Consortium
  85. Permission is hereby granted, free of charge, to any person obtaining a copy
  86. of this software and associated documentation files (the "Software"), to deal
  87. in the Software without restriction, including without limitation the rights
  88. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  89. copies of the Software, and to permit persons to whom the Software is
  90. furnished to do so, subject to the following conditions:
  91. The above copyright notice and this permission notice shall be included in
  92. all copies or substantial portions of the Software.
  93. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  94. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  95. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  96. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  97. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  98. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  99. Except as contained in this notice, the name of the X Consortium shall not be
  100. used in advertising or otherwise to promote the sale, use or other dealings
  101. in this Software without prior written authorization from the X Consortium.
  102. \endlegalese
  103. \br
  104. \legalese
  105. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  106. All Rights Reserved
  107. Permission to use, copy, modify, and distribute this software and its
  108. documentation for any purpose and without fee is hereby granted,
  109. provided that the above copyright notice appear in all copies and that
  110. both that copyright notice and this permission notice appear in
  111. supporting documentation, and that the name of Digital not be
  112. used in advertising or publicity pertaining to distribution of the
  113. software without specific, written prior permission.
  114. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  115. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  116. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  117. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  118. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  119. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  120. SOFTWARE.
  121. \endlegalese
  122. \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
  123. */
  124. /*!
  125. \enum QRegion::RegionType
  126. Specifies the shape of the region to be created.
  127. \value Rectangle the region covers the entire rectangle.
  128. \value Ellipse the region is an ellipse inside the rectangle.
  129. */
  130. /*!
  131. \fn void QRegion::translate(const QPoint &point)
  132. \overload
  133. Translates the region \a{point}\e{.x()} along the x axis and
  134. \a{point}\e{.y()} along the y axis, relative to the current
  135. position. Positive values move the region to the right and down.
  136. Translates to the given \a point.
  137. */
  138. /*!
  139. \fn Handle QRegion::handle() const
  140. Returns a platform-specific region handle. The \c Handle type is
  141. \c HRGN on Windows, \c Region on X11, and \c RgnHandle on Mac OS
  142. X. On \l{Qt for Embedded Linux} it is \c {void *}.
  143. \warning This function is not portable.
  144. */
  145. /*****************************************************************************
  146. QRegion member functions
  147. *****************************************************************************/
  148. /*!
  149. \fn QRegion::QRegion()
  150. Constructs an empty region.
  151. \sa isEmpty()
  152. */
  153. /*!
  154. \fn QRegion::QRegion(const QRect &r, RegionType t)
  155. \overload
  156. Create a region based on the rectange \a r with region type \a t.
  157. If the rectangle is invalid a null region will be created.
  158. \sa QRegion::RegionType
  159. */
  160. /*!
  161. \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
  162. Constructs a polygon region from the point array \a a with the fill rule
  163. specified by \a fillRule.
  164. If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
  165. using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
  166. algorithm is used.
  167. \warning This constructor can be used to create complex regions that will
  168. slow down painting when used.
  169. */
  170. /*!
  171. \fn QRegion::QRegion(const QRegion &r)
  172. Constructs a new region which is equal to region \a r.
  173. */
  174. /*!
  175. \fn QRegion::QRegion(const QBitmap &bm)
  176. Constructs a region from the bitmap \a bm.
  177. The resulting region consists of the pixels in bitmap \a bm that
  178. are Qt::color1, as if each pixel was a 1 by 1 rectangle.
  179. This constructor may create complex regions that will slow down
  180. painting when used. Note that drawing masked pixmaps can be done
  181. much faster using QPixmap::setMask().
  182. */
  183. /*!
  184. Constructs a rectangular or elliptic region.
  185. If \a t is \c Rectangle, the region is the filled rectangle (\a x,
  186. \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled
  187. ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size
  188. (\a w ,\a h).
  189. */
  190. QRegion::QRegion(int x, int y, int w, int h, RegionType t)
  191. {
  192. QRegion tmp(QRect(x, y, w, h), t);
  193. tmp.d->ref.ref();
  194. d = tmp.d;
  195. }
  196. #ifdef QT3_SUPPORT
  197. /*!
  198. Use the constructor tha takes a Qt::FillRule as the second
  199. argument instead.
  200. */
  201. QRegion::QRegion(const QPolygon &pa, bool winding)
  202. {
  203. new (this) QRegion(pa, winding ? Qt::WindingFill : Qt::OddEvenFill);
  204. }
  205. #endif
  206. /*!
  207. \fn QRegion::~QRegion()
  208. \internal
  209. Destroys the region.
  210. */
  211. void QRegion::detach()
  212. {
  213. if (d->ref != 1)
  214. *this = copy();
  215. #if defined(Q_WS_X11)
  216. else if (d->xrectangles) {
  217. free(d->xrectangles);
  218. d->xrectangles = 0;
  219. }
  220. #endif
  221. }
  222. // duplicates in qregion_win.cpp and qregion_wce.cpp
  223. #define QRGN_SETRECT 1 // region stream commands
  224. #define QRGN_SETELLIPSE 2 // (these are internal)
  225. #define QRGN_SETPTARRAY_ALT 3
  226. #define QRGN_SETPTARRAY_WIND 4
  227. #define QRGN_TRANSLATE 5
  228. #define QRGN_OR 6
  229. #define QRGN_AND 7
  230. #define QRGN_SUB 8
  231. #define QRGN_XOR 9
  232. #define QRGN_RECTS 10
  233. #ifndef QT_NO_DATASTREAM
  234. /*
  235. Executes region commands in the internal buffer and rebuilds the
  236. original region.
  237. We do this when we read a region from the data stream.
  238. If \a ver is non-0, uses the format version \a ver on reading the
  239. byte array.
  240. */
  241. void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
  242. {
  243. QByteArray copy = buffer;
  244. QDataStream s(&copy, QIODevice::ReadOnly);
  245. if (ver)
  246. s.setVersion(ver);
  247. s.setByteOrder(byteOrder);
  248. QRegion rgn;
  249. #ifndef QT_NO_DEBUG
  250. int test_cnt = 0;
  251. #endif
  252. while (!s.atEnd()) {
  253. qint32 id;
  254. if (s.version() == 1) {
  255. int id_int;
  256. s >> id_int;
  257. id = id_int;
  258. } else {
  259. s >> id;
  260. }
  261. #ifndef QT_NO_DEBUG
  262. if (test_cnt > 0 && id != QRGN_TRANSLATE)
  263. qWarning("QRegion::exec: Internal error");
  264. test_cnt++;
  265. #endif
  266. if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
  267. QRect r;
  268. s >> r;
  269. rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
  270. } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
  271. QPolygon a;
  272. s >> a;
  273. rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
  274. } else if (id == QRGN_TRANSLATE) {
  275. QPoint p;
  276. s >> p;
  277. rgn.translate(p.x(), p.y());
  278. } else if (id >= QRGN_OR && id <= QRGN_XOR) {
  279. QByteArray bop1, bop2;
  280. QRegion r1, r2;
  281. s >> bop1;
  282. r1.exec(bop1);
  283. s >> bop2;
  284. r2.exec(bop2);
  285. switch (id) {
  286. case QRGN_OR:
  287. rgn = r1.united(r2);
  288. break;
  289. case QRGN_AND:
  290. rgn = r1.intersected(r2);
  291. break;
  292. case QRGN_SUB:
  293. rgn = r1.subtracted(r2);
  294. break;
  295. case QRGN_XOR:
  296. rgn = r1.xored(r2);
  297. break;
  298. }
  299. } else if (id == QRGN_RECTS) {
  300. // (This is the only form used in Qt 2.0)
  301. quint32 n;
  302. s >> n;
  303. QRect r;
  304. for (int i=0; i<(int)n; i++) {
  305. s >> r;
  306. rgn = rgn.united(QRegion(r));
  307. }
  308. }
  309. }
  310. *this = rgn;
  311. }
  312. /*****************************************************************************
  313. QRegion stream functions
  314. *****************************************************************************/
  315. /*!
  316. \fn QRegion &QRegion::operator=(const QRegion &r)
  317. Assigns \a r to this region and returns a reference to the region.
  318. */
  319. /*!
  320. \fn void QRegion::swap(QRegion &other)
  321. \since 4.8
  322. Swaps region \a other with this region. This operation is very
  323. fast and never fails.
  324. */
  325. /*!
  326. \relates QRegion
  327. Writes the region \a r to the stream \a s and returns a reference
  328. to the stream.
  329. \sa \link datastreamformat.html Format of the QDataStream operators \endlink
  330. */
  331. QDataStream &operator<<(QDataStream &s, const QRegion &r)
  332. {
  333. QVector<QRect> a = r.rects();
  334. if (a.isEmpty()) {
  335. s << (quint32)0;
  336. } else {
  337. if (s.version() == 1) {
  338. int i;
  339. for (i = a.size() - 1; i > 0; --i) {
  340. s << (quint32)(12 + i * 24);
  341. s << (int)QRGN_OR;
  342. }
  343. for (i = 0; i < a.size(); ++i) {
  344. s << (quint32)(4+8) << (int)QRGN_SETRECT << a[i];
  345. }
  346. } else {
  347. s << (quint32)(4 + 4 + 16 * a.size()); // 16: storage size of QRect
  348. s << (qint32)QRGN_RECTS;
  349. s << a;
  350. }
  351. }
  352. return s;
  353. }
  354. /*!
  355. \relates QRegion
  356. Reads a region from the stream \a s into \a r and returns a
  357. reference to the stream.
  358. \sa \link datastreamformat.html Format of the QDataStream operators \endlink
  359. */
  360. QDataStream &operator>>(QDataStream &s, QRegion &r)
  361. {
  362. QByteArray b;
  363. s >> b;
  364. r.exec(b, s.version(), s.byteOrder());
  365. return s;
  366. }
  367. #endif //QT_NO_DATASTREAM
  368. #ifndef QT_NO_DEBUG_STREAM
  369. QDebug operator<<(QDebug s, const QRegion &r)
  370. {
  371. QVector<QRect> rects = r.rects();
  372. s.nospace() << "QRegion(size=" << rects.size() << "), "
  373. << "bounds = " << r.boundingRect() << '\n';
  374. for (int i=0; i<rects.size(); ++i)
  375. s << "- " << i << rects.at(i) << '\n';
  376. return s;
  377. }
  378. #endif
  379. // These are not inline - they can be implemented better on some platforms
  380. // (eg. Windows at least provides 3-variable operations). For now, simple.
  381. /*!
  382. Applies the united() function to this region and \a r. \c r1|r2 is
  383. equivalent to \c r1.united(r2).
  384. \sa united(), operator+()
  385. */
  386. const QRegion QRegion::operator|(const QRegion &r) const
  387. { return united(r); }
  388. /*!
  389. Applies the united() function to this region and \a r. \c r1+r2 is
  390. equivalent to \c r1.united(r2).
  391. \sa united(), operator|()
  392. */
  393. const QRegion QRegion::operator+(const QRegion &r) const
  394. { return united(r); }
  395. /*!
  396. \overload
  397. \since 4.4
  398. */
  399. const QRegion QRegion::operator+(const QRect &r) const
  400. { return united(r); }
  401. /*!
  402. Applies the intersected() function to this region and \a r. \c r1&r2
  403. is equivalent to \c r1.intersected(r2).
  404. \sa intersected()
  405. */
  406. const QRegion QRegion::operator&(const QRegion &r) const
  407. { return intersected(r); }
  408. /*!
  409. \overload
  410. \since 4.4
  411. */
  412. const QRegion QRegion::operator&(const QRect &r) const
  413. {
  414. return intersected(r);
  415. }
  416. /*!
  417. Applies the subtracted() function to this region and \a r. \c r1-r2
  418. is equivalent to \c r1.subtracted(r2).
  419. \sa subtracted()
  420. */
  421. const QRegion QRegion::operator-(const QRegion &r) const
  422. { return subtracted(r); }
  423. /*!
  424. Applies the xored() function to this region and \a r. \c r1^r2 is
  425. equivalent to \c r1.xored(r2).
  426. \sa xored()
  427. */
  428. const QRegion QRegion::operator^(const QRegion &r) const
  429. { return xored(r); }
  430. /*!
  431. Applies the united() function to this region and \a r and assigns
  432. the result to this region. \c r1|=r2 is equivalent to \c
  433. {r1 = r1.united(r2)}.
  434. \sa united()
  435. */
  436. QRegion& QRegion::operator|=(const QRegion &r)
  437. { return *this = *this | r; }
  438. /*!
  439. \fn QRegion& QRegion::operator+=(const QRect &rect)
  440. Returns a region that is the union of this region with the specified \a rect.
  441. \sa united()
  442. */
  443. /*!
  444. \fn QRegion& QRegion::operator+=(const QRegion &r)
  445. Applies the united() function to this region and \a r and assigns
  446. the result to this region. \c r1+=r2 is equivalent to \c
  447. {r1 = r1.united(r2)}.
  448. \sa intersected()
  449. */
  450. #if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN)
  451. QRegion& QRegion::operator+=(const QRect &r)
  452. {
  453. return operator+=(QRegion(r));
  454. }
  455. #endif
  456. /*!
  457. \fn QRegion& QRegion::operator&=(const QRegion &r)
  458. Applies the intersected() function to this region and \a r and
  459. assigns the result to this region. \c r1&=r2 is equivalent to \c
  460. r1 = r1.intersected(r2).
  461. \sa intersected()
  462. */
  463. QRegion& QRegion::operator&=(const QRegion &r)
  464. { return *this = *this & r; }
  465. /*!
  466. \overload
  467. \since 4.4
  468. */
  469. #if defined (Q_OS_UNIX) || defined (Q_WS_WIN)
  470. QRegion& QRegion::operator&=(const QRect &r)
  471. {
  472. return *this = *this & r;
  473. }
  474. #else
  475. QRegion& QRegion::operator&=(const QRect &r)
  476. {
  477. return *this &= (QRegion(r));
  478. }
  479. #endif
  480. /*!
  481. \fn QRegion& QRegion::operator-=(const QRegion &r)
  482. Applies the subtracted() function to this region and \a r and
  483. assigns the result to this region. \c r1-=r2 is equivalent to \c
  484. {r1 = r1.subtracted(r2)}.
  485. \sa subtracted()
  486. */
  487. QRegion& QRegion::operator-=(const QRegion &r)
  488. { return *this = *this - r; }
  489. /*!
  490. Applies the xored() function to this region and \a r and
  491. assigns the result to this region. \c r1^=r2 is equivalent to \c
  492. {r1 = r1.xored(r2)}.
  493. \sa xored()
  494. */
  495. QRegion& QRegion::operator^=(const QRegion &r)
  496. { return *this = *this ^ r; }
  497. /*!
  498. \fn bool QRegion::operator!=(const QRegion &other) const
  499. Returns true if this region is different from the \a other region;
  500. otherwise returns false.
  501. */
  502. /*!
  503. Returns the region as a QVariant
  504. */
  505. QRegion::operator QVariant() const
  506. {
  507. return QVariant(QVariant::Region, this);
  508. }
  509. /*!
  510. \fn bool QRegion::operator==(const QRegion &r) const
  511. Returns true if the region is equal to \a r; otherwise returns
  512. false.
  513. */
  514. /*!
  515. \fn bool QRegion::isNull() const
  516. Use isEmpty() instead.
  517. */
  518. /*!
  519. \fn void QRegion::translate(int dx, int dy)
  520. Translates (moves) the region \a dx along the X axis and \a dy
  521. along the Y axis.
  522. */
  523. /*!
  524. \fn QRegion QRegion::translated(const QPoint &p) const
  525. \overload
  526. \since 4.1
  527. Returns a copy of the regtion that is translated \a{p}\e{.x()}
  528. along the x axis and \a{p}\e{.y()} along the y axis, relative to
  529. the current position. Positive values move the rectangle to the
  530. right and down.
  531. \sa translate()
  532. */
  533. /*!
  534. \since 4.1
  535. Returns a copy of the region that is translated \a dx along the
  536. x axis and \a dy along the y axis, relative to the current
  537. position. Positive values move the region to the right and
  538. down.
  539. \sa translate()
  540. */
  541. QRegion
  542. QRegion::translated(int dx, int dy) const
  543. {
  544. QRegion ret(*this);
  545. ret.translate(dx, dy);
  546. return ret;
  547. }
  548. inline bool rect_intersects(const QRect &r1, const QRect &r2)
  549. {
  550. return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
  551. r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
  552. }
  553. /*!
  554. \since 4.2
  555. Returns true if this region intersects with \a region, otherwise
  556. returns false.
  557. */
  558. bool QRegion::intersects(const QRegion &region) const
  559. {
  560. if (isEmpty() || region.isEmpty())
  561. return false;
  562. if (!rect_intersects(boundingRect(), region.boundingRect()))
  563. return false;
  564. if (rectCount() == 1 && region.rectCount() == 1)
  565. return true;
  566. const QVector<QRect> myRects = rects();
  567. const QVector<QRect> otherRects = region.rects();
  568. for (QVector<QRect>::const_iterator i1 = myRects.constBegin(); i1 < myRects.constEnd(); ++i1)
  569. for (QVector<QRect>::const_iterator i2 = otherRects.constBegin(); i2 < otherRects.constEnd(); ++i2)
  570. if (rect_intersects(*i1, *i2))
  571. return true;
  572. return false;
  573. }
  574. /*!
  575. \fn bool QRegion::intersects(const QRect &rect) const
  576. \since 4.2
  577. Returns true if this region intersects with \a rect, otherwise
  578. returns false.
  579. */
  580. #if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN)
  581. /*!
  582. \overload
  583. \since 4.4
  584. */
  585. QRegion QRegion::intersect(const QRect &r) const
  586. {
  587. return intersect(QRegion(r));
  588. }
  589. #endif
  590. /*!
  591. \obsolete
  592. \fn int QRegion::numRects() const
  593. \since 4.4
  594. Returns the number of rectangles that will be returned in rects().
  595. */
  596. /*!
  597. \fn int QRegion::rectCount() const
  598. \since 4.6
  599. Returns the number of rectangles that will be returned in rects().
  600. */
  601. /*!
  602. \fn bool QRegion::isEmpty() const
  603. Returns true if the region is empty; otherwise returns false. An
  604. empty region is a region that contains no points.
  605. Example:
  606. \snippet doc/src/snippets/code/src_gui_painting_qregion_unix.cpp 0
  607. */
  608. /*!
  609. \fn bool QRegion::contains(const QPoint &p) const
  610. Returns true if the region contains the point \a p; otherwise
  611. returns false.
  612. */
  613. /*!
  614. \fn bool QRegion::contains(const QRect &r) const
  615. \overload
  616. Returns true if the region overlaps the rectangle \a r; otherwise
  617. returns false.
  618. */
  619. /*!
  620. \fn QRegion QRegion::unite(const QRegion &r) const
  621. \obsolete
  622. Use united(\a r) instead.
  623. */
  624. /*!
  625. \fn QRegion QRegion::unite(const QRect &rect) const
  626. \since 4.4
  627. \obsolete
  628. Use united(\a rect) instead.
  629. */
  630. /*!
  631. \fn QRegion QRegion::united(const QRect &rect) const
  632. \since 4.4
  633. Returns a region which is the union of this region and the given \a rect.
  634. \sa intersected(), subtracted(), xored()
  635. */
  636. /*!
  637. \fn QRegion QRegion::united(const QRegion &r) const
  638. \since 4.2
  639. Returns a region which is the union of this region and \a r.
  640. \img runion.png Region Union
  641. The figure shows the union of two elliptical regions.
  642. \sa intersected(), subtracted(), xored()
  643. */
  644. /*!
  645. \fn QRegion QRegion::intersect(const QRegion &r) const
  646. \obsolete
  647. Use intersected(\a r) instead.
  648. */
  649. /*!
  650. \fn QRegion QRegion::intersect(const QRect &rect) const
  651. \since 4.4
  652. \obsolete
  653. Use intersected(\a rect) instead.
  654. */
  655. /*!
  656. \fn QRegion QRegion::intersected(const QRect &rect) const
  657. \since 4.4
  658. Returns a region which is the intersection of this region and the given \a rect.
  659. \sa subtracted(), united(), xored()
  660. */
  661. /*!
  662. \fn QRegion QRegion::intersected(const QRegion &r) const
  663. \since 4.2
  664. Returns a region which is the intersection of this region and \a r.
  665. \img rintersect.png Region Intersection
  666. The figure shows the intersection of two elliptical regions.
  667. \sa subtracted(), united(), xored()
  668. */
  669. /*!
  670. \fn QRegion QRegion::subtract(const QRegion &r) const
  671. \obsolete
  672. Use subtracted(\a r) instead.
  673. */
  674. /*!
  675. \fn QRegion QRegion::subtracted(const QRegion &r) const
  676. \since 4.2
  677. Returns a region which is \a r subtracted from this region.
  678. \img rsubtract.png Region Subtraction
  679. The figure shows the result when the ellipse on the right is
  680. subtracted from the ellipse on the left (\c {left - right}).
  681. \sa intersected(), united(), xored()
  682. */
  683. /*!
  684. \fn QRegion QRegion::eor(const QRegion &r) const
  685. \obsolete
  686. Use xored(\a r) instead.
  687. */
  688. /*!
  689. \fn QRegion QRegion::xored(const QRegion &r) const
  690. \since 4.2
  691. Returns a region which is the exclusive or (XOR) of this region
  692. and \a r.
  693. \img rxor.png Region XORed
  694. The figure shows the exclusive or of two elliptical regions.
  695. \sa intersected(), united(), subtracted()
  696. */
  697. /*!
  698. \fn QRect QRegion::boundingRect() const
  699. Returns the bounding rectangle of this region. An empty region
  700. gives a rectangle that is QRect::isNull().
  701. */
  702. /*!
  703. \fn QVector<QRect> QRegion::rects() const
  704. Returns an array of non-overlapping rectangles that make up the
  705. region.
  706. The union of all the rectangles is equal to the original region.
  707. */
  708. /*!
  709. \fn void QRegion::setRects(const QRect *rects, int number)
  710. Sets the region using the array of rectangles specified by \a rects and
  711. \a number.
  712. The rectangles \e must be optimally Y-X sorted and follow these restrictions:
  713. \list
  714. \o The rectangles must not intersect.
  715. \o All rectangles with a given top coordinate must have the same height.
  716. \o No two rectangles may abut horizontally (they should be combined
  717. into a single wider rectangle in that case).
  718. \o The rectangles must be sorted in ascending order, with Y as the major
  719. sort key and X as the minor sort key.
  720. \endlist
  721. \omit
  722. Only some platforms have these restrictions (Qt for Embedded Linux, X11 and Mac OS X).
  723. \endomit
  724. */
  725. namespace {
  726. struct Segment
  727. {
  728. Segment() {}
  729. Segment(const QPoint &p)
  730. : added(false)
  731. , point(p)
  732. {
  733. }
  734. int left() const
  735. {
  736. return qMin(point.x(), next->point.x());
  737. }
  738. int right() const
  739. {
  740. return qMax(point.x(), next->point.x());
  741. }
  742. bool overlaps(const Segment &other) const
  743. {
  744. return left() < other.right() && other.left() < right();
  745. }
  746. void connect(Segment &other)
  747. {
  748. next = &other;
  749. other.prev = this;
  750. horizontal = (point.y() == other.point.y());
  751. }
  752. void merge(Segment &other)
  753. {
  754. if (right() <= other.right()) {
  755. QPoint p = other.point;
  756. Segment *oprev = other.prev;
  757. other.point = point;
  758. other.prev = prev;
  759. prev->next = &other;
  760. point = p;
  761. prev = oprev;
  762. oprev->next = this;
  763. } else {
  764. Segment *onext = other.next;
  765. other.next = next;
  766. next->prev = &other;
  767. next = onext;
  768. next->prev = this;
  769. }
  770. }
  771. int horizontal : 1;
  772. int added : 1;
  773. QPoint point;
  774. Segment *prev;
  775. Segment *next;
  776. };
  777. void mergeSegments(Segment *a, int na, Segment *b, int nb)
  778. {
  779. int i = 0;
  780. int j = 0;
  781. while (i != na && j != nb) {
  782. Segment &sa = a[i];
  783. Segment &sb = b[j];
  784. const int ra = sa.right();
  785. const int rb = sb.right();
  786. if (sa.overlaps(sb))
  787. sa.merge(sb);
  788. i += (rb >= ra);
  789. j += (ra >= rb);
  790. }
  791. }
  792. void addSegmentsToPath(Segment *segment, QPainterPath &path)
  793. {
  794. Segment *current = segment;
  795. path.moveTo(current->point);
  796. current->added = true;
  797. Segment *last = current;
  798. current = current->next;
  799. while (current != segment) {
  800. if (current->horizontal != last->horizontal)
  801. path.lineTo(current->point);
  802. current->added = true;
  803. last = current;
  804. current = current->next;
  805. }
  806. }
  807. }
  808. Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
  809. {
  810. QPainterPath result;
  811. if (region.rectCount() == 1) {
  812. result.addRect(region.boundingRect());
  813. return result;
  814. }
  815. const QVector<QRect> rects = region.rects();
  816. QVarLengthArray<Segment> segments;
  817. segments.resize(4 * rects.size());
  818. const QRect *rect = rects.constData();
  819. const QRect *end = rect + rects.size();
  820. int lastRowSegmentCount = 0;
  821. Segment *lastRowSegments = 0;
  822. int lastSegment = 0;
  823. int lastY = 0;
  824. while (rect != end) {
  825. const int y = rect[0].y();
  826. int count = 0;
  827. while (&rect[count] != end && rect[count].y() == y)
  828. ++count;
  829. for (int i = 0; i < count; ++i) {
  830. int offset = lastSegment + i;
  831. segments[offset] = Segment(rect[i].topLeft());
  832. segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
  833. segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
  834. segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
  835. offset = lastSegment + i;
  836. for (int j = 0; j < 4; ++j)
  837. segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
  838. }
  839. if (lastRowSegments && lastY == y)
  840. mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
  841. lastRowSegments = &segments[lastSegment + 2 * count];
  842. lastRowSegmentCount = count;
  843. lastSegment += 4 * count;
  844. lastY = y + rect[0].height();
  845. rect += count;
  846. }
  847. for (int i = 0; i < lastSegment; ++i) {
  848. Segment *segment = &segments[i];
  849. if (!segment->added)
  850. addSegmentsToPath(segment, result);
  851. }
  852. return result;
  853. }
  854. #if defined(Q_OS_UNIX) || defined(Q_WS_WIN)
  855. //#define QT_REGION_DEBUG
  856. /*
  857. * clip region
  858. */
  859. struct QRegionPrivate {
  860. int numRects;
  861. QVector<QRect> rects;
  862. QRect extents;
  863. QRect innerRect;
  864. int innerArea;
  865. inline QRegionPrivate() : numRects(0), innerArea(-1) {}
  866. inline QRegionPrivate(const QRect &r) {
  867. numRects = 1;
  868. extents = r;
  869. innerRect = r;
  870. innerArea = r.width() * r.height();
  871. }
  872. inline QRegionPrivate(const QRegionPrivate &r) {
  873. rects = r.rects;
  874. numRects = r.numRects;
  875. extents = r.extents;
  876. innerRect = r.innerRect;
  877. innerArea = r.innerArea;
  878. }
  879. inline QRegionPrivate &operator=(const QRegionPrivate &r) {
  880. rects = r.rects;
  881. numRects = r.numRects;
  882. extents = r.extents;
  883. innerRect = r.innerRect;
  884. innerArea = r.innerArea;
  885. return *this;
  886. }
  887. void intersect(const QRect &r);
  888. /*
  889. * Returns true if r is guaranteed to be fully contained in this region.
  890. * A false return value does not guarantee the opposite.
  891. */
  892. inline bool contains(const QRegionPrivate &r) const {
  893. return contains(r.extents);
  894. }
  895. inline bool contains(const QRect &r2) const {
  896. const QRect &r1 = innerRect;
  897. return r2.left() >= r1.left() && r2.right() <= r1.right()
  898. && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
  899. }
  900. /*
  901. * Returns true if this region is guaranteed to be fully contained in r.
  902. */
  903. inline bool within(const QRect &r1) const {
  904. const QRect &r2 = extents;
  905. return r2.left() >= r1.left() && r2.right() <= r1.right()
  906. && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
  907. }
  908. inline void updateInnerRect(const QRect &rect) {
  909. const int area = rect.width() * rect.height();
  910. if (area > innerArea) {
  911. innerArea = area;
  912. innerRect = rect;
  913. }
  914. }
  915. inline void vectorize() {
  916. if (numRects == 1) {
  917. if (!rects.size())
  918. rects.resize(1);
  919. rects[0] = extents;
  920. }
  921. }
  922. inline void append(const QRect *r);
  923. void append(const QRegionPrivate *r);
  924. void prepend(const QRect *r);
  925. void prepend(const QRegionPrivate *r);
  926. inline bool canAppend(const QRect *r) const;
  927. inline bool canAppend(const QRegionPrivate *r) const;
  928. inline bool canPrepend(const QRect *r) const;
  929. inline bool canPrepend(const QRegionPrivate *r) const;
  930. inline bool mergeFromRight(QRect *left, const QRect *right);
  931. inline bool mergeFromLeft(QRect *left, const QRect *right);
  932. inline bool mergeFromBelow(QRect *top, const QRect *bottom,
  933. const QRect *nextToTop,
  934. const QRect *nextToBottom);
  935. inline bool mergeFromAbove(QRect *bottom, const QRect *top,
  936. const QRect *nextToBottom,
  937. const QRect *nextToTop);
  938. #ifdef QT_REGION_DEBUG
  939. void selfTest() const;
  940. #endif
  941. };
  942. static inline bool isEmptyHelper(const QRegionPrivate *preg)
  943. {
  944. return !preg || preg->numRects == 0;
  945. }
  946. static inline bool canMergeFromRight(const QRect *left, const QRect *right)
  947. {
  948. return (right->top() == left->top()
  949. && right->bottom() == left->bottom()
  950. && right->left() <= (left->right() + 1));
  951. }
  952. static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
  953. {
  954. return canMergeFromRight(left, right);
  955. }
  956. bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right)
  957. {
  958. if (canMergeFromRight(left, right)) {
  959. left->setRight(right->right());
  960. updateInnerRect(*left);
  961. return true;
  962. }
  963. return false;
  964. }
  965. bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left)
  966. {
  967. if (canMergeFromLeft(right, left)) {
  968. right->setLeft(left->left());
  969. updateInnerRect(*right);
  970. return true;
  971. }
  972. return false;
  973. }
  974. static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom,
  975. const QRect *nextToTop,
  976. const QRect *nextToBottom)
  977. {
  978. if (nextToTop && nextToTop->y() == top->y())
  979. return false;
  980. if (nextToBottom && nextToBottom->y() == bottom->y())
  981. return false;
  982. return ((top->bottom() >= (bottom->top() - 1))
  983. && top->left() == bottom->left()
  984. && top->right() == bottom->right());
  985. }
  986. bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom,
  987. const QRect *nextToTop,
  988. const QRect *nextToBottom)
  989. {
  990. if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
  991. top->setBottom(bottom->bottom());
  992. updateInnerRect(*top);
  993. return true;
  994. }
  995. return false;
  996. }
  997. bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top,
  998. const QRect *nextToBottom,
  999. const QRect *nextToTop)
  1000. {
  1001. if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
  1002. bottom->setTop(top->top());
  1003. updateInnerRect(*bottom);
  1004. return true;
  1005. }
  1006. return false;
  1007. }
  1008. static inline QRect qt_rect_intersect_normalized(const QRect &r1,
  1009. const QRect &r2)
  1010. {
  1011. QRect r;
  1012. r.setLeft(qMax(r1.left(), r2.left()));
  1013. r.setRight(qMin(r1.right(), r2.right()));
  1014. r.setTop(qMax(r1.top(), r2.top()));
  1015. r.setBottom(qMin(r1.bottom(), r2.bottom()));
  1016. return r;
  1017. }
  1018. void QRegionPrivate::intersect(const QRect &rect)
  1019. {
  1020. Q_ASSERT(extents.intersects(rect));
  1021. Q_ASSERT(numRects > 1);
  1022. #ifdef QT_REGION_DEBUG
  1023. selfTest();
  1024. #endif
  1025. const QRect r = rect.normalized();
  1026. extents = QRect();
  1027. innerRect = QRect();
  1028. innerArea = -1;
  1029. QRect *dest = rects.data();
  1030. const QRect *src = dest;
  1031. int n = numRects;
  1032. numRects = 0;
  1033. while (n--) {
  1034. *dest = qt_rect_intersect_normalized(*src++, r);
  1035. if (dest->isEmpty())
  1036. continue;
  1037. if (numRects == 0) {
  1038. extents = *dest;
  1039. } else {
  1040. extents.setLeft(qMin(extents.left(), dest->left()));
  1041. // hw: extents.top() will never change after initialization
  1042. //extents.setTop(qMin(extents.top(), dest->top()));
  1043. extents.setRight(qMax(extents.right(), dest->right()));
  1044. extents.setBottom(qMax(extents.bottom(), dest->bottom()));
  1045. const QRect *nextToLast = (numRects > 1 ? dest - 2 : 0);
  1046. // mergeFromBelow inlined and optimized
  1047. if (canMergeFromBelow(dest - 1, dest, nextToLast, 0)) {
  1048. if (!n || src->y() != dest->y() || src->left() > r.right()) {
  1049. QRect *prev = dest - 1;
  1050. prev->setBottom(dest->bottom());
  1051. updateInnerRect(*prev);
  1052. continue;
  1053. }
  1054. }
  1055. }
  1056. updateInnerRect(*dest);
  1057. ++dest;
  1058. ++numRects;
  1059. }
  1060. #ifdef QT_REGION_DEBUG
  1061. selfTest();
  1062. #endif
  1063. }
  1064. void QRegionPrivate::append(const QRect *r)
  1065. {
  1066. Q_ASSERT(!r->isEmpty());
  1067. QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
  1068. if (mergeFromRight(myLast, r)) {
  1069. if (numRects > 1) {
  1070. const QRect *nextToTop = (numRects > 2 ? myLast - 2 : 0);
  1071. if (mergeFromBelow(myLast - 1, myLast, nextToTop, 0))
  1072. --numRects;
  1073. }
  1074. } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : 0), 0)) {
  1075. // nothing
  1076. } else {
  1077. vectorize();
  1078. ++numRects;
  1079. updateInnerRect(*r);
  1080. if (rects.size() < numRects)
  1081. rects.resize(numRects);
  1082. rects[numRects - 1] = *r;
  1083. }
  1084. extents.setCoords(qMin(extents.left(), r->left()),
  1085. qMin(extents.top(), r->top()),
  1086. qMax(extents.right(), r->right()),
  1087. qMax(extents.bottom(), r->bottom()));
  1088. #ifdef QT_REGION_DEBUG
  1089. selfTest();
  1090. #endif
  1091. }
  1092. void QRegionPrivate::append(const QRegionPrivate *r)
  1093. {
  1094. Q_ASSERT(!isEmptyHelper(r));
  1095. if (r->numRects == 1) {
  1096. append(&r->extents);
  1097. return;
  1098. }
  1099. vectorize();
  1100. QRect *destRect = rects.data() + numRects;
  1101. const QRect *srcRect = r->rects.constData();
  1102. int numAppend = r->numRects;
  1103. // try merging
  1104. {
  1105. const QRect *rFirst = srcRect;
  1106. QRect *myLast = destRect - 1;
  1107. const QRect *nextToLast = (numRects > 1 ? myLast - 1 : 0);
  1108. if (mergeFromRight(myLast, rFirst)) {
  1109. ++srcRect;
  1110. --numAppend;
  1111. const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : 0);
  1112. if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) {
  1113. ++srcRect;
  1114. --numAppend;
  1115. }
  1116. if (numRects > 1) {
  1117. nextToLast = (numRects > 2 ? myLast - 2 : 0);
  1118. rNextToFirst = (numAppend > 0 ? srcRect : 0);
  1119. if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) {
  1120. --destRect;
  1121. --numRects;
  1122. }
  1123. }
  1124. } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) {
  1125. ++srcRect;
  1126. --numAppend;
  1127. }
  1128. }
  1129. // append rectangles
  1130. if (numAppend > 0) {
  1131. const int newNumRects = numRects + numAppend;
  1132. if (newNumRects > rects.size()) {
  1133. rects.resize(newNumRects);
  1134. destRect = rects.data() + numRects;
  1135. }
  1136. memcpy(destRect, srcRect, numAppend * sizeof(QRect));
  1137. numRects = newNumRects;
  1138. }
  1139. // update inner rectangle
  1140. if (innerArea < r->innerArea) {
  1141. innerArea = r->innerArea;
  1142. innerRect = r->innerRect;
  1143. }
  1144. // update extents
  1145. destRect = &extents;
  1146. srcRect = &r->extents;
  1147. extents.setCoords(qMin(destRect->left(), srcRect->left()),
  1148. qMin(destRect->top(), srcRect->top()),
  1149. qMax(destRect->right(), srcRect->right()),
  1150. qMax(destRect->bottom(), srcRect->bottom()));
  1151. #ifdef QT_REGION_DEBUG
  1152. selfTest();
  1153. #endif
  1154. }
  1155. void QRegionPrivate::prepend(const QRegionPrivate *r)
  1156. {
  1157. Q_ASSERT(!isEmptyHelper(r));
  1158. if (r->numRects == 1) {
  1159. prepend(&r->extents);
  1160. return;
  1161. }
  1162. vectorize();
  1163. int numPrepend = r->numRects;
  1164. int numSkip = 0;
  1165. // try merging
  1166. {
  1167. QRect *myFirst = rects.data();
  1168. const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : 0);
  1169. const QRect *rLast = r->rects.constData() + r->numRects - 1;
  1170. const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : 0);
  1171. if (mergeFromLeft(myFirst, rLast)) {
  1172. --numPrepend;
  1173. --rLast;
  1174. rNextToLast = (numPrepend > 1 ? rLast - 1 : 0);
  1175. if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
  1176. --numPrepend;
  1177. --rLast;
  1178. }
  1179. if (numRects > 1) {
  1180. nextToFirst = (numRects > 2? myFirst + 2 : 0);
  1181. rNextToLast = (numPrepend > 0 ? rLast : 0);
  1182. if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) {
  1183. --numRects;
  1184. ++numSkip;
  1185. }
  1186. }
  1187. } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
  1188. --numPrepend;
  1189. }
  1190. }
  1191. if (numPrepend > 0) {
  1192. const int newNumRects = numRects + numPrepend;
  1193. if (newNumRects > rects.size())
  1194. rects.resize(newNumRects);
  1195. // move existing rectangles
  1196. memmove(rects.data() + numPrepend, rects.constData() + numSkip,
  1197. numRects * sizeof(QRect));
  1198. // prepend new rectangles
  1199. memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect));
  1200. numRects = newNumRects;
  1201. }
  1202. // update inner rectangle
  1203. if (innerArea < r->innerArea) {
  1204. innerArea = r->innerArea;
  1205. innerRect = r->innerRect;
  1206. }
  1207. // update extents
  1208. extents.setCoords(qMin(extents.left(), r->extents.left()),
  1209. qMin(extents.top(), r->extents.top()),
  1210. qMax(extents.right(), r->extents.right()),
  1211. qMax(extents.bottom(), r->extents.bottom()));
  1212. #ifdef QT_REGION_DEBUG
  1213. selfTest();
  1214. #endif
  1215. }
  1216. void QRegionPrivate::prepend(const QRect *r)
  1217. {
  1218. Q_ASSERT(!r->isEmpty());
  1219. QRect *myFirst = (numRects == 1 ? &extents : rects.data());
  1220. if (mergeFromLeft(myFirst, r)) {
  1221. if (numRects > 1) {
  1222. const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : 0);
  1223. if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, 0)) {
  1224. --numRects;
  1225. memmove(rects.data(), rects.constData() + 1,
  1226. numRects * sizeof(QRect));
  1227. }
  1228. }
  1229. } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : 0), 0)) {
  1230. // nothing
  1231. } else {
  1232. vectorize();
  1233. ++numRects;
  1234. updateInnerRect(*r);
  1235. rects.prepend(*r);
  1236. }
  1237. extents.setCoords(qMin(extents.left(), r->left()),
  1238. qMin(extents.top(), r->top()),
  1239. qMax(extents.right(), r->right()),
  1240. qMax(extents.bottom(), r->bottom()));
  1241. #ifdef QT_REGION_DEBUG
  1242. selfTest();
  1243. #endif
  1244. }
  1245. bool QRegionPrivate::canAppend(const QRect *r) const
  1246. {
  1247. Q_ASSERT(!r->isEmpty());
  1248. const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
  1249. if (r->top() > myLast->bottom())
  1250. return true;
  1251. if (r->top() == myLast->top()
  1252. && r->height() == myLast->height()
  1253. && r->left() > myLast->right())
  1254. {
  1255. return true;
  1256. }
  1257. return false;
  1258. }
  1259. bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
  1260. {
  1261. return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
  1262. }
  1263. bool QRegionPrivate::canPrepend(const QRect *r) const
  1264. {
  1265. Q_ASSERT(!r->isEmpty());
  1266. const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
  1267. if (r->bottom() < myFirst->top()) // not overlapping
  1268. return true;
  1269. if (r->top() == myFirst->top()
  1270. && r->height() == myFirst->height()
  1271. && r->right() < myFirst->left())
  1272. {
  1273. return true;
  1274. }
  1275. return false;
  1276. }
  1277. bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
  1278. {
  1279. return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1);
  1280. }
  1281. #ifdef QT_REGION_DEBUG
  1282. void QRegionPrivate::selfTest() const
  1283. {
  1284. if (numRects == 0) {
  1285. Q_ASSERT(extents.isEmpty());
  1286. Q_ASSERT(innerRect.isEmpty());
  1287. return;
  1288. }
  1289. Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
  1290. if (numRects == 1) {
  1291. Q_ASSERT(innerRect == extents);
  1292. Q_ASSERT(!innerRect.isEmpty());
  1293. return;
  1294. }
  1295. for (int i = 0; i < numRects; ++i) {
  1296. const QRect r = rects.at(i);
  1297. if ((r.width() * r.height()) > innerArea)
  1298. qDebug() << "selfTest(): innerRect" << innerRect << '<' << r;
  1299. }
  1300. QRect r = rects.first();
  1301. for (int i = 1; i < numRects; ++i) {
  1302. const QRect r2 = rects.at(i);
  1303. Q_ASSERT(!r2.isEmpty());
  1304. if (r2.y() == r.y()) {
  1305. Q_ASSERT(r.bottom() == r2.bottom());
  1306. Q_ASSERT(r.right() < (r2.left() + 1));
  1307. } else {
  1308. Q_ASSERT(r2.y() >= r.bottom());
  1309. }
  1310. r = r2;
  1311. }
  1312. }
  1313. #endif // QT_REGION_DEBUG
  1314. #if defined(Q_WS_X11)
  1315. QT_BEGIN_INCLUDE_NAMESPACE
  1316. # include "qregion_x11.cpp"
  1317. QT_END_INCLUDE_NAMESPACE
  1318. #elif defined(Q_WS_MAC)
  1319. QT_BEGIN_INCLUDE_NAMESPACE
  1320. # include "qregion_mac.cpp"
  1321. QT_END_INCLUDE_NAMESPACE
  1322. #elif defined(Q_WS_WIN)
  1323. QT_BEGIN_INCLUDE_NAMESPACE
  1324. # include "qregion_win.cpp"
  1325. QT_END_INCLUDE_NAMESPACE
  1326. #elif defined(Q_WS_QWS) || defined(Q_WS_QPA)
  1327. static QRegionPrivate qrp;
  1328. QRegion::QRegionData QRegion::shared_empty = {Q_BASIC_ATOMIC_INITIALIZER(1), &qrp};
  1329. #endif
  1330. typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
  1331. register const QRect *r2, const QRect *r2End, register int y1, register int y2);
  1332. typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
  1333. register int y1, register int y2);
  1334. static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
  1335. static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
  1336. static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
  1337. OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
  1338. NonOverlapFunc nonOverlap2Func);
  1339. #define RectangleOut 0
  1340. #define RectangleIn 1
  1341. #define RectanglePart 2
  1342. #define EvenOddRule 0
  1343. #define WindingRule 1
  1344. // START OF region.h extract
  1345. /* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
  1346. /************************************************************************
  1347. Copyright (c) 1987 X Consortium
  1348. Permission is hereby granted, free of charge, to any person obtaining a copy
  1349. of this software and associated documentation files (the "Software"), to deal
  1350. in the Software without restriction, including without limitation the rights
  1351. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1352. copies of the Software, and to permit persons to whom the Software is
  1353. furnished to do so, subject to the following conditions:
  1354. The above copyright notice and this permission notice shall be included in
  1355. all copies or substantial portions of the Software.
  1356. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1357. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1358. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1359. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  1360. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  1361. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1362. Except as contained in this notice, the name of the X Consortium shall not be
  1363. used in advertising or otherwise to promote the sale, use or other dealings
  1364. in this Software without prior written authorization from the X Consortium.
  1365. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  1366. All Rights Reserved
  1367. Permission to use, copy, modify, and distribute this software and its
  1368. documentation for any purpose and without fee is hereby granted,
  1369. provided that the above copyright notice appear in all copies and that
  1370. both that copyright notice and this permission notice appear in
  1371. supporting documentation, and that the name of Digital not be
  1372. used in advertising or publicity pertaining to distribution of the
  1373. software without specific, written prior permission.
  1374. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  1375. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  1376. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  1377. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  1378. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  1379. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  1380. SOFTWARE.
  1381. ************************************************************************/
  1382. #ifndef _XREGION_H
  1383. #define _XREGION_H
  1384. QT_BEGIN_INCLUDE_NAMESPACE
  1385. #include <limits.h>
  1386. QT_END_INCLUDE_NAMESPACE
  1387. /* 1 if two BOXes overlap.
  1388. * 0 if two BOXes do not overlap.
  1389. * Remember, x2 and y2 are not in the region
  1390. */
  1391. #define EXTENTCHECK(r1, r2) \
  1392. ((r1)->right() >= (r2)->left() && \
  1393. (r1)->left() <= (r2)->right() && \
  1394. (r1)->bottom() >= (r2)->top() && \
  1395. (r1)->top() <= (r2)->bottom())
  1396. /*
  1397. * update region extents
  1398. */
  1399. #define EXTENTS(r,idRect){\
  1400. if((r)->left() < (idRect)->extents.left())\
  1401. (idRect)->extents.setLeft((r)->left());\
  1402. if((r)->top() < (idRect)->extents.top())\
  1403. (idRect)->extents.setTop((r)->top());\
  1404. if((r)->right() > (idRect)->extents.right())\
  1405. (idRect)->extents.setRight((r)->right());\
  1406. if((r)->bottom() > (idRect)->extents.bottom())\
  1407. (idRect)->extents.setBottom((r)->bottom());\
  1408. }
  1409. /*
  1410. * Check to see if there is enough memory in the present region.
  1411. */
  1412. #define MEMCHECK(dest, rect, firstrect){\
  1413. if ((dest).numRects >= ((dest).rects.size()-1)){\
  1414. firstrect.resize(firstrect.size() * 2); \
  1415. (rect) = (firstrect).data() + (dest).numRects;\
  1416. }\
  1417. }
  1418. /*
  1419. * number of points to buffer before sending them off
  1420. * to scanlines(): Must be an even number
  1421. */
  1422. #define NUMPTSTOBUFFER 200
  1423. /*
  1424. * used to allocate buffers for points and link
  1425. * the buffers together
  1426. */
  1427. typedef struct _POINTBLOCK {
  1428. int data[NUMPTSTOBUFFER * sizeof(QPoint)];
  1429. QPoint *pts;
  1430. struct _POINTBLOCK *next;
  1431. } POINTBLOCK;
  1432. #endif
  1433. // END OF region.h extract
  1434. // START OF Region.c extract
  1435. /* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
  1436. /************************************************************************
  1437. Copyright (c) 1987, 1988