PageRenderTime 38ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/qt-everywhere-opensource-src-4.8.2/src/gui/painting/qregion.cpp

#
C++ | 4365 lines | 2395 code | 472 blank | 1498 comment | 744 complexity | 003851c11f20588faa2d9fcbe796fd6d MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-4.0, LGPL-3.0, GPL-2.0, LGPL-2.0, LGPL-2.1, GPL-3.0
  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 X Consortium
  1438. Permission is hereby granted, free of charge, to any person obtaining a copy
  1439. of this software and associated documentation files (the "Software"), to deal
  1440. in the Software without restriction, including without limitation the rights
  1441. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1442. copies of the Software, and to permit persons to whom the Software is
  1443. furnished to do so, subject to the following conditions:
  1444. The above copyright notice and this permission notice shall be included in
  1445. all copies or substantial portions of the Software.
  1446. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1447. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1448. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1449. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  1450. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  1451. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  1452. Except as contained in this notice, the name of the X Consortium shall not be
  1453. used in advertising or otherwise to promote the sale, use or other dealings
  1454. in this Software without prior written authorization from the X Consortium.
  1455. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
  1456. All Rights Reserved
  1457. Permission to use, copy, modify, and distribute this software and its
  1458. documentation for any purpose and without fee is hereby granted,
  1459. provided that the above copyright notice appear in all copies and that
  1460. both that copyright notice and this permission notice appear in
  1461. supporting documentation, and that the name of Digital not be
  1462. used in advertising or publicity pertaining to distribution of the
  1463. software without specific, written prior permission.
  1464. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  1465. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  1466. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  1467. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  1468. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  1469. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  1470. SOFTWARE.
  1471. ************************************************************************/
  1472. /*
  1473. * The functions in this file implement the Region abstraction, similar to one
  1474. * used in the X11 sample server. A Region is simply an area, as the name
  1475. * implies, and is implemented as a "y-x-banded" array of rectangles. To
  1476. * explain: Each Region is made up of a certain number of rectangles sorted
  1477. * by y coordinate first, and then by x coordinate.
  1478. *
  1479. * Furthermore, the rectangles are banded such that every rectangle with a
  1480. * given upper-left y coordinate (y1) will have the same lower-right y
  1481. * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
  1482. * will span the entire vertical distance of the band. This means that some
  1483. * areas that could be merged into a taller rectangle will be represented as
  1484. * several shorter rectangles to account for shorter rectangles to its left
  1485. * or right but within its "vertical scope".
  1486. *
  1487. * An added constraint on the rectangles is that they must cover as much
  1488. * horizontal area as possible. E.g. no two rectangles in a band are allowed
  1489. * to touch.
  1490. *
  1491. * Whenever possible, bands will be merged together to cover a greater vertical
  1492. * distance (and thus reduce the number of rectangles). Two bands can be merged
  1493. * only if the bottom of one touches the top of the other and they have
  1494. * rectangles in the same places (of the same width, of course). This maintains
  1495. * the y-x-banding that's so nice to have...
  1496. */
  1497. /* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
  1498. static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source,
  1499. QRegionPrivate &dest)
  1500. {
  1501. if (rect->isEmpty())
  1502. return;
  1503. Q_ASSERT(EqualRegion(source, &dest));
  1504. if (dest.numRects == 0) {
  1505. dest = QRegionPrivate(*rect);
  1506. } else if (dest.canAppend(rect)) {
  1507. dest.append(rect);
  1508. } else {
  1509. QRegionPrivate p(*rect);
  1510. UnionRegion(&p, source, dest);
  1511. }
  1512. }
  1513. /*-
  1514. *-----------------------------------------------------------------------
  1515. * miSetExtents --
  1516. * Reset the extents and innerRect of a region to what they should be.
  1517. * Called by miSubtract and miIntersect b/c they can't figure it out
  1518. * along the way or do so easily, as miUnion can.
  1519. *
  1520. * Results:
  1521. * None.
  1522. *
  1523. * Side Effects:
  1524. * The region's 'extents' and 'innerRect' structure is overwritten.
  1525. *
  1526. *-----------------------------------------------------------------------
  1527. */
  1528. static void miSetExtents(QRegionPrivate &dest)
  1529. {
  1530. register const QRect *pBox,
  1531. *pBoxEnd;
  1532. register QRect *pExtents;
  1533. dest.innerRect.setCoords(0, 0, -1, -1);
  1534. dest.innerArea = -1;
  1535. if (dest.numRects == 0) {
  1536. dest.extents.setCoords(0, 0, -1, -1);
  1537. return;
  1538. }
  1539. pExtents = &dest.extents;
  1540. if (dest.rects.isEmpty())
  1541. pBox = &dest.extents;
  1542. else
  1543. pBox = dest.rects.constData();
  1544. pBoxEnd = pBox + dest.numRects - 1;
  1545. /*
  1546. * Since pBox is the first rectangle in the region, it must have the
  1547. * smallest y1 and since pBoxEnd is the last rectangle in the region,
  1548. * it must have the largest y2, because of banding. Initialize x1 and
  1549. * x2 from pBox and pBoxEnd, resp., as good things to initialize them
  1550. * to...
  1551. */
  1552. pExtents->setLeft(pBox->left());
  1553. pExtents->setTop(pBox->top());
  1554. pExtents->setRight(pBoxEnd->right());
  1555. pExtents->setBottom(pBoxEnd->bottom());
  1556. Q_ASSERT(pExtents->top() <= pExtents->bottom());
  1557. while (pBox <= pBoxEnd) {
  1558. if (pBox->left() < pExtents->left())
  1559. pExtents->setLeft(pBox->left());
  1560. if (pBox->right() > pExtents->right())
  1561. pExtents->setRight(pBox->right());
  1562. dest.updateInnerRect(*pBox);
  1563. ++pBox;
  1564. }
  1565. Q_ASSERT(pExtents->left() <= pExtents->right());
  1566. }
  1567. /* TranslateRegion(pRegion, x, y)
  1568. translates in place
  1569. added by raymond
  1570. */
  1571. static void OffsetRegion(register QRegionPrivate &region, register int x, register int y)
  1572. {
  1573. if (region.rects.size()) {
  1574. register QRect *pbox = region.rects.data();
  1575. register int nbox = region.numRects;
  1576. while (nbox--) {
  1577. pbox->translate(x, y);
  1578. ++pbox;
  1579. }
  1580. }
  1581. region.extents.translate(x, y);
  1582. region.innerRect.translate(x, y);
  1583. }
  1584. /*======================================================================
  1585. * Region Intersection
  1586. *====================================================================*/
  1587. /*-
  1588. *-----------------------------------------------------------------------
  1589. * miIntersectO --
  1590. * Handle an overlapping band for miIntersect.
  1591. *
  1592. * Results:
  1593. * None.
  1594. *
  1595. * Side Effects:
  1596. * Rectangles may be added to the region.
  1597. *
  1598. *-----------------------------------------------------------------------
  1599. */
  1600. static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
  1601. register const QRect *r2, const QRect *r2End, int y1, int y2)
  1602. {
  1603. register int x1;
  1604. register int x2;
  1605. register QRect *pNextRect;
  1606. pNextRect = dest.rects.data() + dest.numRects;
  1607. while (r1 != r1End && r2 != r2End) {
  1608. x1 = qMax(r1->left(), r2->left());
  1609. x2 = qMin(r1->right(), r2->right());
  1610. /*
  1611. * If there's any overlap between the two rectangles, add that
  1612. * overlap to the new region.
  1613. * There's no need to check for subsumption because the only way
  1614. * such a need could arise is if some region has two rectangles
  1615. * right next to each other. Since that should never happen...
  1616. */
  1617. if (x1 <= x2) {
  1618. Q_ASSERT(y1 <= y2);
  1619. MEMCHECK(dest, pNextRect, dest.rects)
  1620. pNextRect->setCoords(x1, y1, x2, y2);
  1621. ++dest.numRects;
  1622. ++pNextRect;
  1623. }
  1624. /*
  1625. * Need to advance the pointers. Shift the one that extends
  1626. * to the right the least, since the other still has a chance to
  1627. * overlap with that region's next rectangle, if you see what I mean.
  1628. */
  1629. if (r1->right() < r2->right()) {
  1630. ++r1;
  1631. } else if (r2->right() < r1->right()) {
  1632. ++r2;
  1633. } else {
  1634. ++r1;
  1635. ++r2;
  1636. }
  1637. }
  1638. }
  1639. /*======================================================================
  1640. * Generic Region Operator
  1641. *====================================================================*/
  1642. /*-
  1643. *-----------------------------------------------------------------------
  1644. * miCoalesce --
  1645. * Attempt to merge the boxes in the current band with those in the
  1646. * previous one. Used only by miRegionOp.
  1647. *
  1648. * Results:
  1649. * The new index for the previous band.
  1650. *
  1651. * Side Effects:
  1652. * If coalescing takes place:
  1653. * - rectangles in the previous band will have their y2 fields
  1654. * altered.
  1655. * - dest.numRects will be decreased.
  1656. *
  1657. *-----------------------------------------------------------------------
  1658. */
  1659. static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart)
  1660. {
  1661. register QRect *pPrevBox; /* Current box in previous band */
  1662. register QRect *pCurBox; /* Current box in current band */
  1663. register QRect *pRegEnd; /* End of region */
  1664. int curNumRects; /* Number of rectangles in current band */
  1665. int prevNumRects; /* Number of rectangles in previous band */
  1666. int bandY1; /* Y1 coordinate for current band */
  1667. QRect *rData = dest.rects.data();
  1668. pRegEnd = rData + dest.numRects;
  1669. pPrevBox = rData + prevStart;
  1670. prevNumRects = curStart - prevStart;
  1671. /*
  1672. * Figure out how many rectangles are in the current band. Have to do
  1673. * this because multiple bands could have been added in miRegionOp
  1674. * at the end when one region has been exhausted.
  1675. */
  1676. pCurBox = rData + curStart;
  1677. bandY1 = pCurBox->top();
  1678. for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
  1679. ++pCurBox;
  1680. }
  1681. if (pCurBox != pRegEnd) {
  1682. /*
  1683. * If more than one band was added, we have to find the start
  1684. * of the last band added so the next coalescing job can start
  1685. * at the right place... (given when multiple bands are added,
  1686. * this may be pointless -- see above).
  1687. */
  1688. --pRegEnd;
  1689. while ((pRegEnd - 1)->top() == pRegEnd->top())
  1690. --pRegEnd;
  1691. curStart = pRegEnd - rData;
  1692. pRegEnd = rData + dest.numRects;
  1693. }
  1694. if (curNumRects == prevNumRects && curNumRects != 0) {
  1695. pCurBox -= curNumRects;
  1696. /*
  1697. * The bands may only be coalesced if the bottom of the previous
  1698. * matches the top scanline of the current.
  1699. */
  1700. if (pPrevBox->bottom() == pCurBox->top() - 1) {
  1701. /*
  1702. * Make sure the bands have boxes in the same places. This
  1703. * assumes that boxes have been added in such a way that they
  1704. * cover the most area possible. I.e. two boxes in a band must
  1705. * have some horizontal space between them.
  1706. */
  1707. do {
  1708. if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
  1709. // The bands don't line up so they can't be coalesced.
  1710. return curStart;
  1711. }
  1712. ++pPrevBox;
  1713. ++pCurBox;
  1714. --prevNumRects;
  1715. } while (prevNumRects != 0);
  1716. dest.numRects -= curNumRects;
  1717. pCurBox -= curNumRects;
  1718. pPrevBox -= curNumRects;
  1719. /*
  1720. * The bands may be merged, so set the bottom y of each box
  1721. * in the previous band to that of the corresponding box in
  1722. * the current band.
  1723. */
  1724. do {
  1725. pPrevBox->setBottom(pCurBox->bottom());
  1726. dest.updateInnerRect(*pPrevBox);
  1727. ++pPrevBox;
  1728. ++pCurBox;
  1729. curNumRects -= 1;
  1730. } while (curNumRects != 0);
  1731. /*
  1732. * If only one band was added to the region, we have to backup
  1733. * curStart to the start of the previous band.
  1734. *
  1735. * If more than one band was added to the region, copy the
  1736. * other bands down. The assumption here is that the other bands
  1737. * came from the same region as the current one and no further
  1738. * coalescing can be done on them since it's all been done
  1739. * already... curStart is already in the right place.
  1740. */
  1741. if (pCurBox == pRegEnd) {
  1742. curStart = prevStart;
  1743. } else {
  1744. do {
  1745. *pPrevBox++ = *pCurBox++;
  1746. dest.updateInnerRect(*pPrevBox);
  1747. } while (pCurBox != pRegEnd);
  1748. }
  1749. }
  1750. }
  1751. return curStart;
  1752. }
  1753. /*-
  1754. *-----------------------------------------------------------------------
  1755. * miRegionOp --
  1756. * Apply an operation to two regions. Called by miUnion, miInverse,
  1757. * miSubtract, miIntersect...
  1758. *
  1759. * Results:
  1760. * None.
  1761. *
  1762. * Side Effects:
  1763. * The new region is overwritten.
  1764. *
  1765. * Notes:
  1766. * The idea behind this function is to view the two regions as sets.
  1767. * Together they cover a rectangle of area that this function divides
  1768. * into horizontal bands where points are covered only by one region
  1769. * or by both. For the first case, the nonOverlapFunc is called with
  1770. * each the band and the band's upper and lower extents. For the
  1771. * second, the overlapFunc is called to process the entire band. It
  1772. * is responsible for clipping the rectangles in the band, though
  1773. * this function provides the boundaries.
  1774. * At the end of each band, the new region is coalesced, if possible,
  1775. * to reduce the number of rectangles in the region.
  1776. *
  1777. *-----------------------------------------------------------------------
  1778. */
  1779. static void miRegionOp(register QRegionPrivate &dest,
  1780. const QRegionPrivate *reg1, const QRegionPrivate *reg2,
  1781. OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
  1782. NonOverlapFunc nonOverlap2Func)
  1783. {
  1784. register const QRect *r1; // Pointer into first region
  1785. register const QRect *r2; // Pointer into 2d region
  1786. const QRect *r1End; // End of 1st region
  1787. const QRect *r2End; // End of 2d region
  1788. register int ybot; // Bottom of intersection
  1789. register int ytop; // Top of intersection
  1790. int prevBand; // Index of start of previous band in dest
  1791. int curBand; // Index of start of current band in dest
  1792. register const QRect *r1BandEnd; // End of current band in r1
  1793. register const QRect *r2BandEnd; // End of current band in r2
  1794. int top; // Top of non-overlapping band
  1795. int bot; // Bottom of non-overlapping band
  1796. /*
  1797. * Initialization:
  1798. * set r1, r2, r1End and r2End appropriately, preserve the important
  1799. * parts of the destination region until the end in case it's one of
  1800. * the two source regions, then mark the "new" region empty, allocating
  1801. * another array of rectangles for it to use.
  1802. */
  1803. if (reg1->numRects == 1)
  1804. r1 = &reg1->extents;
  1805. else
  1806. r1 = reg1->rects.constData();
  1807. if (reg2->numRects == 1)
  1808. r2 = &reg2->extents;
  1809. else
  1810. r2 = reg2->rects.constData();
  1811. r1End = r1 + reg1->numRects;
  1812. r2End = r2 + reg2->numRects;
  1813. dest.vectorize();
  1814. QVector<QRect> oldRects = dest.rects;
  1815. dest.numRects = 0;
  1816. /*
  1817. * Allocate a reasonable number of rectangles for the new region. The idea
  1818. * is to allocate enough so the individual functions don't need to
  1819. * reallocate and copy the array, which is time consuming, yet we don't
  1820. * have to worry about using too much memory. I hope to be able to
  1821. * nuke the realloc() at the end of this function eventually.
  1822. */
  1823. dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
  1824. /*
  1825. * Initialize ybot and ytop.
  1826. * In the upcoming loop, ybot and ytop serve different functions depending
  1827. * on whether the band being handled is an overlapping or non-overlapping
  1828. * band.
  1829. * In the case of a non-overlapping band (only one of the regions
  1830. * has points in the band), ybot is the bottom of the most recent
  1831. * intersection and thus clips the top of the rectangles in that band.
  1832. * ytop is the top of the next intersection between the two regions and
  1833. * serves to clip the bottom of the rectangles in the current band.
  1834. * For an overlapping band (where the two regions intersect), ytop clips
  1835. * the top of the rectangles of both regions and ybot clips the bottoms.
  1836. */
  1837. if (reg1->extents.top() < reg2->extents.top())
  1838. ybot = reg1->extents.top() - 1;
  1839. else
  1840. ybot = reg2->extents.top() - 1;
  1841. /*
  1842. * prevBand serves to mark the start of the previous band so rectangles
  1843. * can be coalesced into larger rectangles. qv. miCoalesce, above.
  1844. * In the beginning, there is no previous band, so prevBand == curBand
  1845. * (curBand is set later on, of course, but the first band will always
  1846. * start at index 0). prevBand and curBand must be indices because of
  1847. * the possible expansion, and resultant moving, of the new region's
  1848. * array of rectangles.
  1849. */
  1850. prevBand = 0;
  1851. do {
  1852. curBand = dest.numRects;
  1853. /*
  1854. * This algorithm proceeds one source-band (as opposed to a
  1855. * destination band, which is determined by where the two regions
  1856. * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
  1857. * rectangle after the last one in the current band for their
  1858. * respective regions.
  1859. */
  1860. r1BandEnd = r1;
  1861. while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
  1862. ++r1BandEnd;
  1863. r2BandEnd = r2;
  1864. while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
  1865. ++r2BandEnd;
  1866. /*
  1867. * First handle the band that doesn't intersect, if any.
  1868. *
  1869. * Note that attention is restricted to one band in the
  1870. * non-intersecting region at once, so if a region has n
  1871. * bands between the current position and the next place it overlaps
  1872. * the other, this entire loop will be passed through n times.
  1873. */
  1874. if (r1->top() < r2->top()) {
  1875. top = qMax(r1->top(), ybot + 1);
  1876. bot = qMin(r1->bottom(), r2->top() - 1);
  1877. if (nonOverlap1Func != 0 && bot >= top)
  1878. (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
  1879. ytop = r2->top();
  1880. } else if (r2->top() < r1->top()) {
  1881. top = qMax(r2->top(), ybot + 1);
  1882. bot = qMin(r2->bottom(), r1->top() - 1);
  1883. if (nonOverlap2Func != 0 && bot >= top)
  1884. (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
  1885. ytop = r1->top();
  1886. } else {
  1887. ytop = r1->top();
  1888. }
  1889. /*
  1890. * If any rectangles got added to the region, try and coalesce them
  1891. * with rectangles from the previous band. Note we could just do
  1892. * this test in miCoalesce, but some machines incur a not
  1893. * inconsiderable cost for function calls, so...
  1894. */
  1895. if (dest.numRects != curBand)
  1896. prevBand = miCoalesce(dest, prevBand, curBand);
  1897. /*
  1898. * Now see if we've hit an intersecting band. The two bands only
  1899. * intersect if ybot >= ytop
  1900. */
  1901. ybot = qMin(r1->bottom(), r2->bottom());
  1902. curBand = dest.numRects;
  1903. if (ybot >= ytop)
  1904. (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
  1905. if (dest.numRects != curBand)
  1906. prevBand = miCoalesce(dest, prevBand, curBand);
  1907. /*
  1908. * If we've finished with a band (y2 == ybot) we skip forward
  1909. * in the region to the next band.
  1910. */
  1911. if (r1->bottom() == ybot)
  1912. r1 = r1BandEnd;
  1913. if (r2->bottom() == ybot)
  1914. r2 = r2BandEnd;
  1915. } while (r1 != r1End && r2 != r2End);
  1916. /*
  1917. * Deal with whichever region still has rectangles left.
  1918. */
  1919. curBand = dest.numRects;
  1920. if (r1 != r1End) {
  1921. if (nonOverlap1Func != 0) {
  1922. do {
  1923. r1BandEnd = r1;
  1924. while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
  1925. ++r1BandEnd;
  1926. (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
  1927. r1 = r1BandEnd;
  1928. } while (r1 != r1End);
  1929. }
  1930. } else if ((r2 != r2End) && (nonOverlap2Func != 0)) {
  1931. do {
  1932. r2BandEnd = r2;
  1933. while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
  1934. ++r2BandEnd;
  1935. (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
  1936. r2 = r2BandEnd;
  1937. } while (r2 != r2End);
  1938. }
  1939. if (dest.numRects != curBand)
  1940. (void)miCoalesce(dest, prevBand, curBand);
  1941. /*
  1942. * A bit of cleanup. To keep regions from growing without bound,
  1943. * we shrink the array of rectangles to match the new number of
  1944. * rectangles in the region.
  1945. *
  1946. * Only do this stuff if the number of rectangles allocated is more than
  1947. * twice the number of rectangles in the region (a simple optimization).
  1948. */
  1949. if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
  1950. dest.rects.resize(dest.numRects);
  1951. }
  1952. /*======================================================================
  1953. * Region Union
  1954. *====================================================================*/
  1955. /*-
  1956. *-----------------------------------------------------------------------
  1957. * miUnionNonO --
  1958. * Handle a non-overlapping band for the union operation. Just
  1959. * Adds the rectangles into the region. Doesn't have to check for
  1960. * subsumption or anything.
  1961. *
  1962. * Results:
  1963. * None.
  1964. *
  1965. * Side Effects:
  1966. * dest.numRects is incremented and the final rectangles overwritten
  1967. * with the rectangles we're passed.
  1968. *
  1969. *-----------------------------------------------------------------------
  1970. */
  1971. static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
  1972. register int y1, register int y2)
  1973. {
  1974. register QRect *pNextRect;
  1975. pNextRect = dest.rects.data() + dest.numRects;
  1976. Q_ASSERT(y1 <= y2);
  1977. while (r != rEnd) {
  1978. Q_ASSERT(r->left() <= r->right());
  1979. MEMCHECK(dest, pNextRect, dest.rects)
  1980. pNextRect->setCoords(r->left(), y1, r->right(), y2);
  1981. dest.numRects++;
  1982. ++pNextRect;
  1983. ++r;
  1984. }
  1985. }
  1986. /*-
  1987. *-----------------------------------------------------------------------
  1988. * miUnionO --
  1989. * Handle an overlapping band for the union operation. Picks the
  1990. * left-most rectangle each time and merges it into the region.
  1991. *
  1992. * Results:
  1993. * None.
  1994. *
  1995. * Side Effects:
  1996. * Rectangles are overwritten in dest.rects and dest.numRects will
  1997. * be changed.
  1998. *
  1999. *-----------------------------------------------------------------------
  2000. */
  2001. static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
  2002. register const QRect *r2, const QRect *r2End, register int y1, register int y2)
  2003. {
  2004. register QRect *pNextRect;
  2005. pNextRect = dest.rects.data() + dest.numRects;
  2006. #define MERGERECT(r) \
  2007. if ((dest.numRects != 0) && \
  2008. (pNextRect[-1].top() == y1) && \
  2009. (pNextRect[-1].bottom() == y2) && \
  2010. (pNextRect[-1].right() >= r->left()-1)) { \
  2011. if (pNextRect[-1].right() < r->right()) { \
  2012. pNextRect[-1].setRight(r->right()); \
  2013. dest.updateInnerRect(pNextRect[-1]); \
  2014. Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
  2015. } \
  2016. } else { \
  2017. MEMCHECK(dest, pNextRect, dest.rects) \
  2018. pNextRect->setCoords(r->left(), y1, r->right(), y2); \
  2019. dest.updateInnerRect(*pNextRect); \
  2020. dest.numRects++; \
  2021. pNextRect++; \
  2022. } \
  2023. r++;
  2024. Q_ASSERT(y1 <= y2);
  2025. while (r1 != r1End && r2 != r2End) {
  2026. if (r1->left() < r2->left()) {
  2027. MERGERECT(r1)
  2028. } else {
  2029. MERGERECT(r2)
  2030. }
  2031. }
  2032. if (r1 != r1End) {
  2033. do {
  2034. MERGERECT(r1)
  2035. } while (r1 != r1End);
  2036. } else {
  2037. while (r2 != r2End) {
  2038. MERGERECT(r2)
  2039. }
  2040. }
  2041. }
  2042. static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
  2043. {
  2044. Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2));
  2045. Q_ASSERT(!reg1->contains(*reg2));
  2046. Q_ASSERT(!reg2->contains(*reg1));
  2047. Q_ASSERT(!EqualRegion(reg1, reg2));
  2048. Q_ASSERT(!reg1->canAppend(reg2));
  2049. Q_ASSERT(!reg2->canAppend(reg1));
  2050. if (reg1->innerArea > reg2->innerArea) {
  2051. dest.innerArea = reg1->innerArea;
  2052. dest.innerRect = reg1->innerRect;
  2053. } else {
  2054. dest.innerArea = reg2->innerArea;
  2055. dest.innerRect = reg2->innerRect;
  2056. }
  2057. miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
  2058. dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
  2059. qMin(reg1->extents.top(), reg2->extents.top()),
  2060. qMax(reg1->extents.right(), reg2->extents.right()),
  2061. qMax(reg1->extents.bottom(), reg2->extents.bottom()));
  2062. }
  2063. /*======================================================================
  2064. * Region Subtraction
  2065. *====================================================================*/
  2066. /*-
  2067. *-----------------------------------------------------------------------
  2068. * miSubtractNonO --
  2069. * Deal with non-overlapping band for subtraction. Any parts from
  2070. * region 2 we discard. Anything from region 1 we add to the region.
  2071. *
  2072. * Results:
  2073. * None.
  2074. *
  2075. * Side Effects:
  2076. * dest may be affected.
  2077. *
  2078. *-----------------------------------------------------------------------
  2079. */
  2080. static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r,
  2081. const QRect *rEnd, register int y1, register int y2)
  2082. {
  2083. register QRect *pNextRect;
  2084. pNextRect = dest.rects.data() + dest.numRects;
  2085. Q_ASSERT(y1<=y2);
  2086. while (r != rEnd) {
  2087. Q_ASSERT(r->left() <= r->right());
  2088. MEMCHECK(dest, pNextRect, dest.rects)
  2089. pNextRect->setCoords(r->left(), y1, r->right(), y2);
  2090. ++dest.numRects;
  2091. ++pNextRect;
  2092. ++r;
  2093. }
  2094. }
  2095. /*-
  2096. *-----------------------------------------------------------------------
  2097. * miSubtractO --
  2098. * Overlapping band subtraction. x1 is the left-most point not yet
  2099. * checked.
  2100. *
  2101. * Results:
  2102. * None.
  2103. *
  2104. * Side Effects:
  2105. * dest may have rectangles added to it.
  2106. *
  2107. *-----------------------------------------------------------------------
  2108. */
  2109. static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
  2110. register const QRect *r2, const QRect *r2End, register int y1, register int y2)
  2111. {
  2112. register QRect *pNextRect;
  2113. register int x1;
  2114. x1 = r1->left();
  2115. Q_ASSERT(y1 <= y2);
  2116. pNextRect = dest.rects.data() + dest.numRects;
  2117. while (r1 != r1End && r2 != r2End) {
  2118. if (r2->right() < x1) {
  2119. /*
  2120. * Subtrahend missed the boat: go to next subtrahend.
  2121. */
  2122. ++r2;
  2123. } else if (r2->left() <= x1) {
  2124. /*
  2125. * Subtrahend precedes minuend: nuke left edge of minuend.
  2126. */
  2127. x1 = r2->right() + 1;
  2128. if (x1 > r1->right()) {
  2129. /*
  2130. * Minuend completely covered: advance to next minuend and
  2131. * reset left fence to edge of new minuend.
  2132. */
  2133. ++r1;
  2134. if (r1 != r1End)
  2135. x1 = r1->left();
  2136. } else {
  2137. // Subtrahend now used up since it doesn't extend beyond minuend
  2138. ++r2;
  2139. }
  2140. } else if (r2->left() <= r1->right()) {
  2141. /*
  2142. * Left part of subtrahend covers part of minuend: add uncovered
  2143. * part of minuend to region and skip to next subtrahend.
  2144. */
  2145. Q_ASSERT(x1 < r2->left());
  2146. MEMCHECK(dest, pNextRect, dest.rects)
  2147. pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
  2148. ++dest.numRects;
  2149. ++pNextRect;
  2150. x1 = r2->right() + 1;
  2151. if (x1 > r1->right()) {
  2152. /*
  2153. * Minuend used up: advance to new...
  2154. */
  2155. ++r1;
  2156. if (r1 != r1End)
  2157. x1 = r1->left();
  2158. } else {
  2159. // Subtrahend used up
  2160. ++r2;
  2161. }
  2162. } else {
  2163. /*
  2164. * Minuend used up: add any remaining piece before advancing.
  2165. */
  2166. if (r1->right() >= x1) {
  2167. MEMCHECK(dest, pNextRect, dest.rects)
  2168. pNextRect->setCoords(x1, y1, r1->right(), y2);
  2169. ++dest.numRects;
  2170. ++pNextRect;
  2171. }
  2172. ++r1;
  2173. if (r1 != r1End)
  2174. x1 = r1->left();
  2175. }
  2176. }
  2177. /*
  2178. * Add remaining minuend rectangles to region.
  2179. */
  2180. while (r1 != r1End) {
  2181. Q_ASSERT(x1 <= r1->right());
  2182. MEMCHECK(dest, pNextRect, dest.rects)
  2183. pNextRect->setCoords(x1, y1, r1->right(), y2);
  2184. ++dest.numRects;
  2185. ++pNextRect;
  2186. ++r1;
  2187. if (r1 != r1End)
  2188. x1 = r1->left();
  2189. }
  2190. }
  2191. /*-
  2192. *-----------------------------------------------------------------------
  2193. * miSubtract --
  2194. * Subtract regS from regM and leave the result in regD.
  2195. * S stands for subtrahend, M for minuend and D for difference.
  2196. *
  2197. * Side Effects:
  2198. * regD is overwritten.
  2199. *
  2200. *-----------------------------------------------------------------------
  2201. */
  2202. static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
  2203. register QRegionPrivate &dest)
  2204. {
  2205. Q_ASSERT(!isEmptyHelper(regM));
  2206. Q_ASSERT(!isEmptyHelper(regS));
  2207. Q_ASSERT(EXTENTCHECK(&regM->extents, &regS->extents));
  2208. Q_ASSERT(!regS->contains(*regM));
  2209. Q_ASSERT(!EqualRegion(regM, regS));
  2210. miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0);
  2211. /*
  2212. * Can't alter dest's extents before we call miRegionOp because
  2213. * it might be one of the source regions and miRegionOp depends
  2214. * on the extents of those regions being the unaltered. Besides, this
  2215. * way there's no checking against rectangles that will be nuked
  2216. * due to coalescing, so we have to examine fewer rectangles.
  2217. */
  2218. miSetExtents(dest);
  2219. }
  2220. static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
  2221. {
  2222. Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb));
  2223. Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents));
  2224. Q_ASSERT(!EqualRegion(sra, srb));
  2225. QRegionPrivate tra, trb;
  2226. if (!srb->contains(*sra))
  2227. SubtractRegion(sra, srb, tra);
  2228. if (!sra->contains(*srb))
  2229. SubtractRegion(srb, sra, trb);
  2230. Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb));
  2231. Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra));
  2232. if (isEmptyHelper(&tra)) {
  2233. dest = trb;
  2234. } else if (isEmptyHelper(&trb)) {
  2235. dest = tra;
  2236. } else if (tra.canAppend(&trb)) {
  2237. dest = tra;
  2238. dest.append(&trb);
  2239. } else if (trb.canAppend(&tra)) {
  2240. dest = trb;
  2241. dest.append(&tra);
  2242. } else {
  2243. UnionRegion(&tra, &trb, dest);
  2244. }
  2245. }
  2246. /*
  2247. * Check to see if two regions are equal
  2248. */
  2249. static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
  2250. {
  2251. if (r1->numRects != r2->numRects) {
  2252. return false;
  2253. } else if (r1->numRects == 0) {
  2254. return true;
  2255. } else if (r1->extents != r2->extents) {
  2256. return false;
  2257. } else if (r1->numRects == 1 && r2->numRects == 1) {
  2258. return true; // equality tested in previous if-statement
  2259. } else {
  2260. const QRect *rr1 = (r1->numRects == 1) ? &r1->extents : r1->rects.constData();
  2261. const QRect *rr2 = (r2->numRects == 1) ? &r2->extents : r2->rects.constData();
  2262. for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
  2263. if (*rr1 != *rr2)
  2264. return false;
  2265. }
  2266. }
  2267. return true;
  2268. }
  2269. static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
  2270. {
  2271. int i;
  2272. if (isEmptyHelper(pRegion))
  2273. return false;
  2274. if (!pRegion->extents.contains(x, y))
  2275. return false;
  2276. if (pRegion->numRects == 1)
  2277. return pRegion->extents.contains(x, y);
  2278. if (pRegion->innerRect.contains(x, y))
  2279. return true;
  2280. for (i = 0; i < pRegion->numRects; ++i) {
  2281. if (pRegion->rects[i].contains(x, y))
  2282. return true;
  2283. }
  2284. return false;
  2285. }
  2286. static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
  2287. {
  2288. register const QRect *pbox;
  2289. register const QRect *pboxEnd;
  2290. QRect rect(rx, ry, rwidth, rheight);
  2291. register QRect *prect = &rect;
  2292. int partIn, partOut;
  2293. if (!region || region->numRects == 0 || !EXTENTCHECK(&region->extents, prect))
  2294. return RectangleOut;
  2295. partOut = false;
  2296. partIn = false;
  2297. /* can stop when both partOut and partIn are true, or we reach prect->y2 */
  2298. pbox = (region->numRects == 1) ? &region->extents : region->rects.constData();
  2299. pboxEnd = pbox + region->numRects;
  2300. for (; pbox < pboxEnd; ++pbox) {
  2301. if (pbox->bottom() < ry)
  2302. continue;
  2303. if (pbox->top() > ry) {
  2304. partOut = true;
  2305. if (partIn || pbox->top() > prect->bottom())
  2306. break;
  2307. ry = pbox->top();
  2308. }
  2309. if (pbox->right() < rx)
  2310. continue; /* not far enough over yet */
  2311. if (pbox->left() > rx) {
  2312. partOut = true; /* missed part of rectangle to left */
  2313. if (partIn)
  2314. break;
  2315. }
  2316. if (pbox->left() <= prect->right()) {
  2317. partIn = true; /* definitely overlap */
  2318. if (partOut)
  2319. break;
  2320. }
  2321. if (pbox->right() >= prect->right()) {
  2322. ry = pbox->bottom() + 1; /* finished with this band */
  2323. if (ry > prect->bottom())
  2324. break;
  2325. rx = prect->left(); /* reset x out to left again */
  2326. } else {
  2327. /*
  2328. * Because boxes in a band are maximal width, if the first box
  2329. * to overlap the rectangle doesn't completely cover it in that
  2330. * band, the rectangle must be partially out, since some of it
  2331. * will be uncovered in that band. partIn will have been set true
  2332. * by now...
  2333. */
  2334. break;
  2335. }
  2336. }
  2337. return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
  2338. }
  2339. // END OF Region.c extract
  2340. // START OF poly.h extract
  2341. /* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
  2342. /************************************************************************
  2343. Copyright (c) 1987 X Consortium
  2344. Permission is hereby granted, free of charge, to any person obtaining a copy
  2345. of this software and associated documentation files (the "Software"), to deal
  2346. in the Software without restriction, including without limitation the rights
  2347. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2348. copies of the Software, and to permit persons to whom the Software is
  2349. furnished to do so, subject to the following conditions:
  2350. The above copyright notice and this permission notice shall be included in
  2351. all copies or substantial portions of the Software.
  2352. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2353. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2354. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2355. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  2356. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  2357. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  2358. Except as contained in this notice, the name of the X Consortium shall not be
  2359. used in advertising or otherwise to promote the sale, use or other dealings
  2360. in this Software without prior written authorization from the X Consortium.
  2361. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  2362. All Rights Reserved
  2363. Permission to use, copy, modify, and distribute this software and its
  2364. documentation for any purpose and without fee is hereby granted,
  2365. provided that the above copyright notice appear in all copies and that
  2366. both that copyright notice and this permission notice appear in
  2367. supporting documentation, and that the name of Digital not be
  2368. used in advertising or publicity pertaining to distribution of the
  2369. software without specific, written prior permission.
  2370. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  2371. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  2372. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  2373. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  2374. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  2375. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  2376. SOFTWARE.
  2377. ************************************************************************/
  2378. /*
  2379. * This file contains a few macros to help track
  2380. * the edge of a filled object. The object is assumed
  2381. * to be filled in scanline order, and thus the
  2382. * algorithm used is an extension of Bresenham's line
  2383. * drawing algorithm which assumes that y is always the
  2384. * major axis.
  2385. * Since these pieces of code are the same for any filled shape,
  2386. * it is more convenient to gather the library in one
  2387. * place, but since these pieces of code are also in
  2388. * the inner loops of output primitives, procedure call
  2389. * overhead is out of the question.
  2390. * See the author for a derivation if needed.
  2391. */
  2392. /*
  2393. * In scan converting polygons, we want to choose those pixels
  2394. * which are inside the polygon. Thus, we add .5 to the starting
  2395. * x coordinate for both left and right edges. Now we choose the
  2396. * first pixel which is inside the pgon for the left edge and the
  2397. * first pixel which is outside the pgon for the right edge.
  2398. * Draw the left pixel, but not the right.
  2399. *
  2400. * How to add .5 to the starting x coordinate:
  2401. * If the edge is moving to the right, then subtract dy from the
  2402. * error term from the general form of the algorithm.
  2403. * If the edge is moving to the left, then add dy to the error term.
  2404. *
  2405. * The reason for the difference between edges moving to the left
  2406. * and edges moving to the right is simple: If an edge is moving
  2407. * to the right, then we want the algorithm to flip immediately.
  2408. * If it is moving to the left, then we don't want it to flip until
  2409. * we traverse an entire pixel.
  2410. */
  2411. #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
  2412. int dx; /* local storage */ \
  2413. \
  2414. /* \
  2415. * if the edge is horizontal, then it is ignored \
  2416. * and assumed not to be processed. Otherwise, do this stuff. \
  2417. */ \
  2418. if ((dy) != 0) { \
  2419. xStart = (x1); \
  2420. dx = (x2) - xStart; \
  2421. if (dx < 0) { \
  2422. m = dx / (dy); \
  2423. m1 = m - 1; \
  2424. incr1 = -2 * dx + 2 * (dy) * m1; \
  2425. incr2 = -2 * dx + 2 * (dy) * m; \
  2426. d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
  2427. } else { \
  2428. m = dx / (dy); \
  2429. m1 = m + 1; \
  2430. incr1 = 2 * dx - 2 * (dy) * m1; \
  2431. incr2 = 2 * dx - 2 * (dy) * m; \
  2432. d = -2 * m * (dy) + 2 * dx; \
  2433. } \
  2434. } \
  2435. }
  2436. #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
  2437. if (m1 > 0) { \
  2438. if (d > 0) { \
  2439. minval += m1; \
  2440. d += incr1; \
  2441. } \
  2442. else { \
  2443. minval += m; \
  2444. d += incr2; \
  2445. } \
  2446. } else {\
  2447. if (d >= 0) { \
  2448. minval += m1; \
  2449. d += incr1; \
  2450. } \
  2451. else { \
  2452. minval += m; \
  2453. d += incr2; \
  2454. } \
  2455. } \
  2456. }
  2457. /*
  2458. * This structure contains all of the information needed
  2459. * to run the bresenham algorithm.
  2460. * The variables may be hardcoded into the declarations
  2461. * instead of using this structure to make use of
  2462. * register declarations.
  2463. */
  2464. typedef struct {
  2465. int minor_axis; /* minor axis */
  2466. int d; /* decision variable */
  2467. int m, m1; /* slope and slope+1 */
  2468. int incr1, incr2; /* error increments */
  2469. } BRESINFO;
  2470. #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
  2471. BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
  2472. bres.m, bres.m1, bres.incr1, bres.incr2)
  2473. #define BRESINCRPGONSTRUCT(bres) \
  2474. BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
  2475. /*
  2476. * These are the data structures needed to scan
  2477. * convert regions. Two different scan conversion
  2478. * methods are available -- the even-odd method, and
  2479. * the winding number method.
  2480. * The even-odd rule states that a point is inside
  2481. * the polygon if a ray drawn from that point in any
  2482. * direction will pass through an odd number of
  2483. * path segments.
  2484. * By the winding number rule, a point is decided
  2485. * to be inside the polygon if a ray drawn from that
  2486. * point in any direction passes through a different
  2487. * number of clockwise and counter-clockwise path
  2488. * segments.
  2489. *
  2490. * These data structures are adapted somewhat from
  2491. * the algorithm in (Foley/Van Dam) for scan converting
  2492. * polygons.
  2493. * The basic algorithm is to start at the top (smallest y)
  2494. * of the polygon, stepping down to the bottom of
  2495. * the polygon by incrementing the y coordinate. We
  2496. * keep a list of edges which the current scanline crosses,
  2497. * sorted by x. This list is called the Active Edge Table (AET)
  2498. * As we change the y-coordinate, we update each entry in
  2499. * in the active edge table to reflect the edges new xcoord.
  2500. * This list must be sorted at each scanline in case
  2501. * two edges intersect.
  2502. * We also keep a data structure known as the Edge Table (ET),
  2503. * which keeps track of all the edges which the current
  2504. * scanline has not yet reached. The ET is basically a
  2505. * list of ScanLineList structures containing a list of
  2506. * edges which are entered at a given scanline. There is one
  2507. * ScanLineList per scanline at which an edge is entered.
  2508. * When we enter a new edge, we move it from the ET to the AET.
  2509. *
  2510. * From the AET, we can implement the even-odd rule as in
  2511. * (Foley/Van Dam).
  2512. * The winding number rule is a little trickier. We also
  2513. * keep the EdgeTableEntries in the AET linked by the
  2514. * nextWETE (winding EdgeTableEntry) link. This allows
  2515. * the edges to be linked just as before for updating
  2516. * purposes, but only uses the edges linked by the nextWETE
  2517. * link as edges representing spans of the polygon to
  2518. * drawn (as with the even-odd rule).
  2519. */
  2520. /*
  2521. * for the winding number rule
  2522. */
  2523. #define CLOCKWISE 1
  2524. #define COUNTERCLOCKWISE -1
  2525. typedef struct _EdgeTableEntry {
  2526. int ymax; /* ycoord at which we exit this edge. */
  2527. BRESINFO bres; /* Bresenham info to run the edge */
  2528. struct _EdgeTableEntry *next; /* next in the list */
  2529. struct _EdgeTableEntry *back; /* for insertion sort */
  2530. struct _EdgeTableEntry *nextWETE; /* for winding num rule */
  2531. int ClockWise; /* flag for winding number rule */
  2532. } EdgeTableEntry;
  2533. typedef struct _ScanLineList{
  2534. int scanline; /* the scanline represented */
  2535. EdgeTableEntry *edgelist; /* header node */
  2536. struct _ScanLineList *next; /* next in the list */
  2537. } ScanLineList;
  2538. typedef struct {
  2539. int ymax; /* ymax for the polygon */
  2540. int ymin; /* ymin for the polygon */
  2541. ScanLineList scanlines; /* header node */
  2542. } EdgeTable;
  2543. /*
  2544. * Here is a struct to help with storage allocation
  2545. * so we can allocate a big chunk at a time, and then take
  2546. * pieces from this heap when we need to.
  2547. */
  2548. #define SLLSPERBLOCK 25
  2549. typedef struct _ScanLineListBlock {
  2550. ScanLineList SLLs[SLLSPERBLOCK];
  2551. struct _ScanLineListBlock *next;
  2552. } ScanLineListBlock;
  2553. /*
  2554. *
  2555. * a few macros for the inner loops of the fill code where
  2556. * performance considerations don't allow a procedure call.
  2557. *
  2558. * Evaluate the given edge at the given scanline.
  2559. * If the edge has expired, then we leave it and fix up
  2560. * the active edge table; otherwise, we increment the
  2561. * x value to be ready for the next scanline.
  2562. * The winding number rule is in effect, so we must notify
  2563. * the caller when the edge has been removed so he
  2564. * can reorder the Winding Active Edge Table.
  2565. */
  2566. #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
  2567. if (pAET->ymax == y) { /* leaving this edge */ \
  2568. pPrevAET->next = pAET->next; \
  2569. pAET = pPrevAET->next; \
  2570. fixWAET = 1; \
  2571. if (pAET) \
  2572. pAET->back = pPrevAET; \
  2573. } \
  2574. else { \
  2575. BRESINCRPGONSTRUCT(pAET->bres) \
  2576. pPrevAET = pAET; \
  2577. pAET = pAET->next; \
  2578. } \
  2579. }
  2580. /*
  2581. * Evaluate the given edge at the given scanline.
  2582. * If the edge has expired, then we leave it and fix up
  2583. * the active edge table; otherwise, we increment the
  2584. * x value to be ready for the next scanline.
  2585. * The even-odd rule is in effect.
  2586. */
  2587. #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
  2588. if (pAET->ymax == y) { /* leaving this edge */ \
  2589. pPrevAET->next = pAET->next; \
  2590. pAET = pPrevAET->next; \
  2591. if (pAET) \
  2592. pAET->back = pPrevAET; \
  2593. } \
  2594. else { \
  2595. BRESINCRPGONSTRUCT(pAET->bres) \
  2596. pPrevAET = pAET; \
  2597. pAET = pAET->next; \
  2598. } \
  2599. }
  2600. // END OF poly.h extract
  2601. // START OF PolyReg.c extract
  2602. /* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
  2603. /************************************************************************
  2604. Copyright (c) 1987 X Consortium
  2605. Permission is hereby granted, free of charge, to any person obtaining a copy
  2606. of this software and associated documentation files (the "Software"), to deal
  2607. in the Software without restriction, including without limitation the rights
  2608. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  2609. copies of the Software, and to permit persons to whom the Software is
  2610. furnished to do so, subject to the following conditions:
  2611. The above copyright notice and this permission notice shall be included in
  2612. all copies or substantial portions of the Software.
  2613. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2614. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2615. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2616. X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  2617. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  2618. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  2619. Except as contained in this notice, the name of the X Consortium shall not be
  2620. used in advertising or otherwise to promote the sale, use or other dealings
  2621. in this Software without prior written authorization from the X Consortium.
  2622. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  2623. All Rights Reserved
  2624. Permission to use, copy, modify, and distribute this software and its
  2625. documentation for any purpose and without fee is hereby granted,
  2626. provided that the above copyright notice appear in all copies and that
  2627. both that copyright notice and this permission notice appear in
  2628. supporting documentation, and that the name of Digital not be
  2629. used in advertising or publicity pertaining to distribution of the
  2630. software without specific, written prior permission.
  2631. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  2632. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  2633. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  2634. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  2635. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  2636. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  2637. SOFTWARE.
  2638. ************************************************************************/
  2639. /* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
  2640. #define LARGE_COORDINATE INT_MAX
  2641. #define SMALL_COORDINATE INT_MIN
  2642. /*
  2643. * InsertEdgeInET
  2644. *
  2645. * Insert the given edge into the edge table.
  2646. * First we must find the correct bucket in the
  2647. * Edge table, then find the right slot in the
  2648. * bucket. Finally, we can insert it.
  2649. *
  2650. */
  2651. static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
  2652. ScanLineListBlock **SLLBlock, int *iSLLBlock)
  2653. {
  2654. register EdgeTableEntry *start, *prev;
  2655. register ScanLineList *pSLL, *pPrevSLL;
  2656. ScanLineListBlock *tmpSLLBlock;
  2657. /*
  2658. * find the right bucket to put the edge into
  2659. */
  2660. pPrevSLL = &ET->scanlines;
  2661. pSLL = pPrevSLL->next;
  2662. while (pSLL && (pSLL->scanline < scanline)) {
  2663. pPrevSLL = pSLL;
  2664. pSLL = pSLL->next;
  2665. }
  2666. /*
  2667. * reassign pSLL (pointer to ScanLineList) if necessary
  2668. */
  2669. if ((!pSLL) || (pSLL->scanline > scanline)) {
  2670. if (*iSLLBlock > SLLSPERBLOCK-1)
  2671. {
  2672. tmpSLLBlock =
  2673. (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
  2674. Q_CHECK_PTR(tmpSLLBlock);
  2675. (*SLLBlock)->next = tmpSLLBlock;
  2676. tmpSLLBlock->next = (ScanLineListBlock *)NULL;
  2677. *SLLBlock = tmpSLLBlock;
  2678. *iSLLBlock = 0;
  2679. }
  2680. pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
  2681. pSLL->next = pPrevSLL->next;
  2682. pSLL->edgelist = (EdgeTableEntry *)NULL;
  2683. pPrevSLL->next = pSLL;
  2684. }
  2685. pSLL->scanline = scanline;
  2686. /*
  2687. * now insert the edge in the right bucket
  2688. */
  2689. prev = 0;
  2690. start = pSLL->edgelist;
  2691. while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
  2692. prev = start;
  2693. start = start->next;
  2694. }
  2695. ETE->next = start;
  2696. if (prev)
  2697. prev->next = ETE;
  2698. else
  2699. pSLL->edgelist = ETE;
  2700. }
  2701. /*
  2702. * CreateEdgeTable
  2703. *
  2704. * This routine creates the edge table for
  2705. * scan converting polygons.
  2706. * The Edge Table (ET) looks like:
  2707. *
  2708. * EdgeTable
  2709. * --------
  2710. * | ymax | ScanLineLists
  2711. * |scanline|-->------------>-------------->...
  2712. * -------- |scanline| |scanline|
  2713. * |edgelist| |edgelist|
  2714. * --------- ---------
  2715. * | |
  2716. * | |
  2717. * V V
  2718. * list of ETEs list of ETEs
  2719. *
  2720. * where ETE is an EdgeTableEntry data structure,
  2721. * and there is one ScanLineList per scanline at
  2722. * which an edge is initially entered.
  2723. *
  2724. */
  2725. static void CreateETandAET(register int count, register const QPoint *pts,
  2726. EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
  2727. ScanLineListBlock *pSLLBlock)
  2728. {
  2729. register const QPoint *top,
  2730. *bottom,
  2731. *PrevPt,
  2732. *CurrPt;
  2733. int iSLLBlock = 0;
  2734. int dy;
  2735. if (count < 2)
  2736. return;
  2737. /*
  2738. * initialize the Active Edge Table
  2739. */
  2740. AET->next = 0;
  2741. AET->back = 0;
  2742. AET->nextWETE = 0;
  2743. AET->bres.minor_axis = SMALL_COORDINATE;
  2744. /*
  2745. * initialize the Edge Table.
  2746. */
  2747. ET->scanlines.next = 0;
  2748. ET->ymax = SMALL_COORDINATE;
  2749. ET->ymin = LARGE_COORDINATE;
  2750. pSLLBlock->next = 0;
  2751. PrevPt = &pts[count - 1];
  2752. /*
  2753. * for each vertex in the array of points.
  2754. * In this loop we are dealing with two vertices at
  2755. * a time -- these make up one edge of the polygon.
  2756. */
  2757. while (count--) {
  2758. CurrPt = pts++;
  2759. /*
  2760. * find out which point is above and which is below.
  2761. */
  2762. if (PrevPt->y() > CurrPt->y()) {
  2763. bottom = PrevPt;
  2764. top = CurrPt;
  2765. pETEs->ClockWise = 0;
  2766. } else {
  2767. bottom = CurrPt;
  2768. top = PrevPt;
  2769. pETEs->ClockWise = 1;
  2770. }
  2771. /*
  2772. * don't add horizontal edges to the Edge table.
  2773. */
  2774. if (bottom->y() != top->y()) {
  2775. pETEs->ymax = bottom->y() - 1; /* -1 so we don't get last scanline */
  2776. /*
  2777. * initialize integer edge algorithm
  2778. */
  2779. dy = bottom->y() - top->y();
  2780. BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
  2781. InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
  2782. if (PrevPt->y() > ET->ymax)
  2783. ET->ymax = PrevPt->y();
  2784. if (PrevPt->y() < ET->ymin)
  2785. ET->ymin = PrevPt->y();
  2786. ++pETEs;
  2787. }
  2788. PrevPt = CurrPt;
  2789. }
  2790. }
  2791. /*
  2792. * loadAET
  2793. *
  2794. * This routine moves EdgeTableEntries from the
  2795. * EdgeTable into the Active Edge Table,
  2796. * leaving them sorted by smaller x coordinate.
  2797. *
  2798. */
  2799. static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
  2800. {
  2801. register EdgeTableEntry *pPrevAET;
  2802. register EdgeTableEntry *tmp;
  2803. pPrevAET = AET;
  2804. AET = AET->next;
  2805. while (ETEs) {
  2806. while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
  2807. pPrevAET = AET;
  2808. AET = AET->next;
  2809. }
  2810. tmp = ETEs->next;
  2811. ETEs->next = AET;
  2812. if (AET)
  2813. AET->back = ETEs;
  2814. ETEs->back = pPrevAET;
  2815. pPrevAET->next = ETEs;
  2816. pPrevAET = ETEs;
  2817. ETEs = tmp;
  2818. }
  2819. }
  2820. /*
  2821. * computeWAET
  2822. *
  2823. * This routine links the AET by the
  2824. * nextWETE (winding EdgeTableEntry) link for
  2825. * use by the winding number rule. The final
  2826. * Active Edge Table (AET) might look something
  2827. * like:
  2828. *
  2829. * AET
  2830. * ---------- --------- ---------
  2831. * |ymax | |ymax | |ymax |
  2832. * | ... | |... | |... |
  2833. * |next |->|next |->|next |->...
  2834. * |nextWETE| |nextWETE| |nextWETE|
  2835. * --------- --------- ^--------
  2836. * | | |
  2837. * V-------------------> V---> ...
  2838. *
  2839. */
  2840. static void computeWAET(register EdgeTableEntry *AET)
  2841. {
  2842. register EdgeTableEntry *pWETE;
  2843. register int inside = 1;
  2844. register int isInside = 0;
  2845. AET->nextWETE = 0;
  2846. pWETE = AET;
  2847. AET = AET->next;
  2848. while (AET) {
  2849. if (AET->ClockWise)
  2850. ++isInside;
  2851. else
  2852. --isInside;
  2853. if ((!inside && !isInside) || (inside && isInside)) {
  2854. pWETE->nextWETE = AET;
  2855. pWETE = AET;
  2856. inside = !inside;
  2857. }
  2858. AET = AET->next;
  2859. }
  2860. pWETE->nextWETE = 0;
  2861. }
  2862. /*
  2863. * InsertionSort
  2864. *
  2865. * Just a simple insertion sort using
  2866. * pointers and back pointers to sort the Active
  2867. * Edge Table.
  2868. *
  2869. */
  2870. static int InsertionSort(register EdgeTableEntry *AET)
  2871. {
  2872. register EdgeTableEntry *pETEchase;
  2873. register EdgeTableEntry *pETEinsert;
  2874. register EdgeTableEntry *pETEchaseBackTMP;
  2875. register int changed = 0;
  2876. AET = AET->next;
  2877. while (AET) {
  2878. pETEinsert = AET;
  2879. pETEchase = AET;
  2880. while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
  2881. pETEchase = pETEchase->back;
  2882. AET = AET->next;
  2883. if (pETEchase != pETEinsert) {
  2884. pETEchaseBackTMP = pETEchase->back;
  2885. pETEinsert->back->next = AET;
  2886. if (AET)
  2887. AET->back = pETEinsert->back;
  2888. pETEinsert->next = pETEchase;
  2889. pETEchase->back->next = pETEinsert;
  2890. pETEchase->back = pETEinsert;
  2891. pETEinsert->back = pETEchaseBackTMP;
  2892. changed = 1;
  2893. }
  2894. }
  2895. return changed;
  2896. }
  2897. /*
  2898. * Clean up our act.
  2899. */
  2900. static void FreeStorage(register ScanLineListBlock *pSLLBlock)
  2901. {
  2902. register ScanLineListBlock *tmpSLLBlock;
  2903. while (pSLLBlock) {
  2904. tmpSLLBlock = pSLLBlock->next;
  2905. free(pSLLBlock);
  2906. pSLLBlock = tmpSLLBlock;
  2907. }
  2908. }
  2909. struct QRegionSpan {
  2910. QRegionSpan() {}
  2911. QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {}
  2912. int x1;
  2913. int x2;
  2914. int width() const { return x2 - x1; }
  2915. };
  2916. Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
  2917. static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend)
  2918. {
  2919. QRect *regRects = reg->rects.data() + *lastRow;
  2920. bool canExtend = reg->rects.size() - *lastRow == numSpans
  2921. && !(*needsExtend && *extendTo + 1 != y)
  2922. && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
  2923. for (int i = 0; i < numSpans && canExtend; ++i) {
  2924. if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
  2925. canExtend = false;
  2926. }
  2927. if (canExtend) {
  2928. *extendTo = y;
  2929. *needsExtend = true;
  2930. } else {
  2931. if (*needsExtend) {
  2932. for (int i = 0; i < reg->rects.size() - *lastRow; ++i)
  2933. regRects[i].setBottom(*extendTo);
  2934. }
  2935. *lastRow = reg->rects.size();
  2936. reg->rects.reserve(*lastRow + numSpans);
  2937. for (int i = 0; i < numSpans; ++i)
  2938. reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
  2939. if (spans[0].x1 < reg->extents.left())
  2940. reg->extents.setLeft(spans[0].x1);
  2941. if (spans[numSpans-1].x2 - 1 > reg->extents.right())
  2942. reg->extents.setRight(spans[numSpans-1].x2 - 1);
  2943. *needsExtend = false;
  2944. }
  2945. }
  2946. /*
  2947. * Create an array of rectangles from a list of points.
  2948. * If indeed these things (POINTS, RECTS) are the same,
  2949. * then this proc is still needed, because it allocates
  2950. * storage for the array, which was allocated on the
  2951. * stack by the calling procedure.
  2952. *
  2953. */
  2954. static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
  2955. POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
  2956. {
  2957. int lastRow = 0;
  2958. int extendTo = 0;
  2959. bool needsExtend = false;
  2960. QVarLengthArray<QRegionSpan> row;
  2961. int rowSize = 0;
  2962. reg->extents.setLeft(INT_MAX);
  2963. reg->extents.setRight(INT_MIN);
  2964. reg->innerArea = -1;
  2965. POINTBLOCK *CurPtBlock = FirstPtBlock;
  2966. for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
  2967. /* the loop uses 2 points per iteration */
  2968. int i = NUMPTSTOBUFFER >> 1;
  2969. if (!numFullPtBlocks)
  2970. i = iCurPtBlock >> 1;
  2971. if(i) {
  2972. row.resize(qMax(row.size(), rowSize + i));
  2973. for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) {
  2974. const int width = pts[1].x() - pts[0].x();
  2975. if (width) {
  2976. if (rowSize && row[rowSize-1].x2 == pts[0].x())
  2977. row[rowSize-1].x2 = pts[1].x();
  2978. else
  2979. row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
  2980. }
  2981. if (rowSize) {
  2982. QPoint *next = i ? &pts[2] : (numFullPtBlocks ? CurPtBlock->next->pts : 0);
  2983. if (!next || next->y() != pts[0].y()) {
  2984. flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
  2985. rowSize = 0;
  2986. }
  2987. }
  2988. }
  2989. }
  2990. CurPtBlock = CurPtBlock->next;
  2991. }
  2992. if (needsExtend) {
  2993. for (int i = lastRow; i < reg->rects.size(); ++i)
  2994. reg->rects[i].setBottom(extendTo);
  2995. }
  2996. reg->numRects = reg->rects.size();
  2997. if (reg->numRects) {
  2998. reg->extents.setTop(reg->rects[0].top());
  2999. reg->extents.setBottom(reg->rects[lastRow].bottom());
  3000. for (int i = 0; i < reg->rects.size(); ++i)
  3001. reg->updateInnerRect(reg->rects[i]);
  3002. } else {
  3003. reg->extents.setCoords(0, 0, 0, 0);
  3004. }
  3005. }
  3006. /*
  3007. * polytoregion
  3008. *
  3009. * Scan converts a polygon by returning a run-length
  3010. * encoding of the resultant bitmap -- the run-length
  3011. * encoding is in the form of an array of rectangles.
  3012. *
  3013. * Can return 0 in case of errors.
  3014. */
  3015. static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
  3016. //Point *Pts; /* the pts */
  3017. //int Count; /* number of pts */
  3018. //int rule; /* winding rule */
  3019. {
  3020. QRegionPrivate *region;
  3021. register EdgeTableEntry *pAET; /* Active Edge Table */
  3022. register int y; /* current scanline */
  3023. register int iPts = 0; /* number of pts in buffer */
  3024. register EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
  3025. register ScanLineList *pSLL; /* current scanLineList */
  3026. register QPoint *pts; /* output buffer */
  3027. EdgeTableEntry *pPrevAET; /* ptr to previous AET */
  3028. EdgeTable ET; /* header node for ET */
  3029. EdgeTableEntry AET; /* header node for AET */
  3030. EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
  3031. ScanLineListBlock SLLBlock; /* header for scanlinelist */
  3032. int fixWAET = false;
  3033. POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
  3034. FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
  3035. POINTBLOCK *tmpPtBlock;
  3036. int numFullPtBlocks = 0;
  3037. if (!(region = new QRegionPrivate))
  3038. return 0;
  3039. /* special case a rectangle */
  3040. if (((Count == 4) ||
  3041. ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
  3042. && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
  3043. && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
  3044. && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
  3045. && (Pts[3].y() == Pts[0].y())))) {
  3046. int x = qMin(Pts[0].x(), Pts[2].x());
  3047. region->extents.setLeft(x);
  3048. int y = qMin(Pts[0].y(), Pts[2].y());
  3049. region->extents.setTop(y);
  3050. region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
  3051. region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
  3052. if ((region->extents.left() <= region->extents.right()) &&
  3053. (region->extents.top() <= region->extents.bottom())) {
  3054. region->numRects = 1;
  3055. region->innerRect = region->extents;
  3056. region->innerArea = region->innerRect.width() * region->innerRect.height();
  3057. }
  3058. return region;
  3059. }
  3060. if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
  3061. return 0;
  3062. region->vectorize();
  3063. pts = FirstPtBlock.pts;
  3064. CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
  3065. pSLL = ET.scanlines.next;
  3066. curPtBlock = &FirstPtBlock;
  3067. // sanity check that the region won't become too big...
  3068. if (ET.ymax - ET.ymin > 100000) {
  3069. // clean up region ptr
  3070. #ifndef QT_NO_DEBUG
  3071. qWarning("QRegion: creating region from big polygon failed...!");
  3072. #endif
  3073. delete region;
  3074. return 0;
  3075. }
  3076. QT_TRY {
  3077. if (rule == EvenOddRule) {
  3078. /*
  3079. * for each scanline
  3080. */
  3081. for (y = ET.ymin; y < ET.ymax; ++y) {
  3082. /*
  3083. * Add a new edge to the active edge table when we
  3084. * get to the next edge.
  3085. */
  3086. if (pSLL && y == pSLL->scanline) {
  3087. loadAET(&AET, pSLL->edgelist);
  3088. pSLL = pSLL->next;
  3089. }
  3090. pPrevAET = &AET;
  3091. pAET = AET.next;
  3092. /*
  3093. * for each active edge
  3094. */
  3095. while (pAET) {
  3096. pts->setX(pAET->bres.minor_axis);
  3097. pts->setY(y);
  3098. ++pts;
  3099. ++iPts;
  3100. /*
  3101. * send out the buffer
  3102. */
  3103. if (iPts == NUMPTSTOBUFFER) {
  3104. tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
  3105. Q_CHECK_PTR(tmpPtBlock);
  3106. tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
  3107. curPtBlock->next = tmpPtBlock;
  3108. curPtBlock = tmpPtBlock;
  3109. pts = curPtBlock->pts;
  3110. ++numFullPtBlocks;
  3111. iPts = 0;
  3112. }
  3113. EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
  3114. }
  3115. InsertionSort(&AET);
  3116. }
  3117. } else {
  3118. /*
  3119. * for each scanline
  3120. */
  3121. for (y = ET.ymin; y < ET.ymax; ++y) {
  3122. /*
  3123. * Add a new edge to the active edge table when we
  3124. * get to the next edge.
  3125. */
  3126. if (pSLL && y == pSLL->scanline) {
  3127. loadAET(&AET, pSLL->edgelist);
  3128. computeWAET(&AET);
  3129. pSLL = pSLL->next;
  3130. }
  3131. pPrevAET = &AET;
  3132. pAET = AET.next;
  3133. pWETE = pAET;
  3134. /*
  3135. * for each active edge
  3136. */
  3137. while (pAET) {
  3138. /*
  3139. * add to the buffer only those edges that
  3140. * are in the Winding active edge table.
  3141. */
  3142. if (pWETE == pAET) {
  3143. pts->setX(pAET->bres.minor_axis);
  3144. pts->setY(y);
  3145. ++pts;
  3146. ++iPts;
  3147. /*
  3148. * send out the buffer
  3149. */
  3150. if (iPts == NUMPTSTOBUFFER) {
  3151. tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
  3152. tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
  3153. curPtBlock->next = tmpPtBlock;
  3154. curPtBlock = tmpPtBlock;
  3155. pts = curPtBlock->pts;
  3156. ++numFullPtBlocks;
  3157. iPts = 0;
  3158. }
  3159. pWETE = pWETE->nextWETE;
  3160. }
  3161. EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
  3162. }
  3163. /*
  3164. * recompute the winding active edge table if
  3165. * we just resorted or have exited an edge.
  3166. */
  3167. if (InsertionSort(&AET) || fixWAET) {
  3168. computeWAET(&AET);
  3169. fixWAET = false;
  3170. }
  3171. }
  3172. }
  3173. } QT_CATCH(...) {
  3174. FreeStorage(SLLBlock.next);
  3175. PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
  3176. for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
  3177. tmpPtBlock = curPtBlock->next;
  3178. free(curPtBlock);
  3179. curPtBlock = tmpPtBlock;
  3180. }
  3181. free(pETEs);
  3182. return 0; // this function returns 0 in case of an error
  3183. }
  3184. FreeStorage(SLLBlock.next);
  3185. PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
  3186. for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
  3187. tmpPtBlock = curPtBlock->next;
  3188. free(curPtBlock);
  3189. curPtBlock = tmpPtBlock;
  3190. }
  3191. free(pETEs);
  3192. return region;
  3193. }
  3194. // END OF PolyReg.c extract
  3195. QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
  3196. {
  3197. QImage image = bitmap.toImage();
  3198. QRegionPrivate *region = new QRegionPrivate;
  3199. QRect xr;
  3200. #define AddSpan \
  3201. { \
  3202. xr.setCoords(prev1, y, x-1, y); \
  3203. UnionRectWithRegion(&xr, region, *region); \
  3204. }
  3205. const uchar zero = 0;
  3206. bool little = image.format() == QImage::Format_MonoLSB;
  3207. int x,
  3208. y;
  3209. for (y = 0; y < image.height(); ++y) {
  3210. uchar *line = image.scanLine(y);
  3211. int w = image.width();
  3212. uchar all = zero;
  3213. int prev1 = -1;
  3214. for (x = 0; x < w;) {
  3215. uchar byte = line[x / 8];
  3216. if (x > w - 8 || byte!=all) {
  3217. if (little) {
  3218. for (int b = 8; b > 0 && x < w; --b) {
  3219. if (!(byte & 0x01) == !all) {
  3220. // More of the same
  3221. } else {
  3222. // A change.
  3223. if (all!=zero) {
  3224. AddSpan
  3225. all = zero;
  3226. } else {
  3227. prev1 = x;
  3228. all = ~zero;
  3229. }
  3230. }
  3231. byte >>= 1;
  3232. ++x;
  3233. }
  3234. } else {
  3235. for (int b = 8; b > 0 && x < w; --b) {
  3236. if (!(byte & 0x80) == !all) {
  3237. // More of the same
  3238. } else {
  3239. // A change.
  3240. if (all != zero) {
  3241. AddSpan
  3242. all = zero;
  3243. } else {
  3244. prev1 = x;
  3245. all = ~zero;
  3246. }
  3247. }
  3248. byte <<= 1;
  3249. ++x;
  3250. }
  3251. }
  3252. } else {
  3253. x += 8;
  3254. }
  3255. }
  3256. if (all != zero) {
  3257. AddSpan
  3258. }
  3259. }
  3260. #undef AddSpan
  3261. return region;
  3262. }
  3263. QRegion::QRegion()
  3264. : d(&shared_empty)
  3265. {
  3266. d->ref.ref();
  3267. }
  3268. QRegion::QRegion(const QRect &r, RegionType t)
  3269. {
  3270. if (r.isEmpty()) {
  3271. d = &shared_empty;
  3272. d->ref.ref();
  3273. } else {
  3274. d = new QRegionData;
  3275. d->ref = 1;
  3276. #if defined(Q_WS_X11)
  3277. d->rgn = 0;
  3278. d->xrectangles = 0;
  3279. #elif defined(Q_WS_WIN)
  3280. d->rgn = 0;
  3281. #endif
  3282. if (t == Rectangle) {
  3283. d->qt_rgn = new QRegionPrivate(r);
  3284. } else if (t == Ellipse) {
  3285. QPainterPath path;
  3286. path.addEllipse(r.x(), r.y(), r.width(), r.height());
  3287. QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
  3288. d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
  3289. }
  3290. }
  3291. }
  3292. QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
  3293. {
  3294. if (a.count() > 2) {
  3295. QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
  3296. fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
  3297. if (qt_rgn) {
  3298. d = new QRegionData;
  3299. d->ref = 1;
  3300. #if defined(Q_WS_X11)
  3301. d->rgn = 0;
  3302. d->xrectangles = 0;
  3303. #elif defined(Q_WS_WIN)
  3304. d->rgn = 0;
  3305. #endif
  3306. d->qt_rgn = qt_rgn;
  3307. } else {
  3308. d = &shared_empty;
  3309. d->ref.ref();
  3310. }
  3311. } else {
  3312. d = &shared_empty;
  3313. d->ref.ref();
  3314. }
  3315. }
  3316. QRegion::QRegion(const QRegion &r)
  3317. {
  3318. d = r.d;
  3319. d->ref.ref();
  3320. }
  3321. QRegion::QRegion(const QBitmap &bm)
  3322. {
  3323. if (bm.isNull()) {
  3324. d = &shared_empty;
  3325. d->ref.ref();
  3326. } else {
  3327. d = new QRegionData;
  3328. d->ref = 1;
  3329. #if defined(Q_WS_X11)
  3330. d->rgn = 0;
  3331. d->xrectangles = 0;
  3332. #elif defined(Q_WS_WIN)
  3333. d->rgn = 0;
  3334. #endif
  3335. d->qt_rgn = qt_bitmapToRegion(bm);
  3336. }
  3337. }
  3338. void QRegion::cleanUp(QRegion::QRegionData *x)
  3339. {
  3340. delete x->qt_rgn;
  3341. #if defined(Q_WS_X11)
  3342. if (x->rgn)
  3343. XDestroyRegion(x->rgn);
  3344. if (x->xrectangles)
  3345. free(x->xrectangles);
  3346. #elif defined(Q_WS_WIN)
  3347. if (x->rgn)
  3348. qt_win_dispose_rgn(x->rgn);
  3349. #endif
  3350. delete x;
  3351. }
  3352. QRegion::~QRegion()
  3353. {
  3354. if (!d->ref.deref())
  3355. cleanUp(d);
  3356. }
  3357. QRegion &QRegion::operator=(const QRegion &r)
  3358. {
  3359. r.d->ref.ref();
  3360. if (!d->ref.deref())
  3361. cleanUp(d);
  3362. d = r.d;
  3363. return *this;
  3364. }
  3365. /*!
  3366. \internal
  3367. */
  3368. QRegion QRegion::copy() const
  3369. {
  3370. QRegion r;
  3371. QScopedPointer<QRegionData> x(new QRegionData);
  3372. x->ref = 1;
  3373. #if defined(Q_WS_X11)
  3374. x->rgn = 0;
  3375. x->xrectangles = 0;
  3376. #elif defined(Q_WS_WIN)
  3377. x->rgn = 0;
  3378. #endif
  3379. if (d->qt_rgn)
  3380. x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
  3381. else
  3382. x->qt_rgn = new QRegionPrivate;
  3383. if (!r.d->ref.deref())
  3384. cleanUp(r.d);
  3385. r.d = x.take();
  3386. return r;
  3387. }
  3388. bool QRegion::isEmpty() const
  3389. {
  3390. return d == &shared_empty || d->qt_rgn->numRects == 0;
  3391. }
  3392. bool QRegion::contains(const QPoint &p) const
  3393. {
  3394. return PointInRegion(d->qt_rgn, p.x(), p.y());
  3395. }
  3396. bool QRegion::contains(const QRect &r) const
  3397. {
  3398. return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
  3399. }
  3400. void QRegion::translate(int dx, int dy)
  3401. {
  3402. if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
  3403. return;
  3404. detach();
  3405. OffsetRegion(*d->qt_rgn, dx, dy);
  3406. }
  3407. QRegion QRegion::unite(const QRegion &r) const
  3408. {
  3409. if (isEmptyHelper(d->qt_rgn))
  3410. return r;
  3411. if (isEmptyHelper(r.d->qt_rgn))
  3412. return *this;
  3413. if (d == r.d)
  3414. return *this;
  3415. if (d->qt_rgn->contains(*r.d->qt_rgn)) {
  3416. return *this;
  3417. } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
  3418. return r;
  3419. } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
  3420. QRegion result(*this);
  3421. result.detach();
  3422. result.d->qt_rgn->append(r.d->qt_rgn);
  3423. return result;
  3424. } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
  3425. QRegion result(*this);
  3426. result.detach();
  3427. result.d->qt_rgn->prepend(r.d->qt_rgn);
  3428. return result;
  3429. } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
  3430. return *this;
  3431. } else {
  3432. QRegion result;
  3433. result.detach();
  3434. UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
  3435. return result;
  3436. }
  3437. }
  3438. QRegion& QRegion::operator+=(const QRegion &r)
  3439. {
  3440. if (isEmptyHelper(d->qt_rgn))
  3441. return *this = r;
  3442. if (isEmptyHelper(r.d->qt_rgn))
  3443. return *this;
  3444. if (d == r.d)
  3445. return *this;
  3446. if (d->qt_rgn->contains(*r.d->qt_rgn)) {
  3447. return *this;
  3448. } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
  3449. return *this = r;
  3450. } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
  3451. detach();
  3452. d->qt_rgn->append(r.d->qt_rgn);
  3453. return *this;
  3454. } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
  3455. detach();
  3456. d->qt_rgn->prepend(r.d->qt_rgn);
  3457. return *this;
  3458. } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
  3459. return *this;
  3460. } else {
  3461. detach();
  3462. UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
  3463. return *this;
  3464. }
  3465. }
  3466. QRegion QRegion::unite(const QRect &r) const
  3467. {
  3468. if (isEmptyHelper(d->qt_rgn))
  3469. return r;
  3470. if (r.isEmpty())
  3471. return *this;
  3472. if (d->qt_rgn->contains(r)) {
  3473. return *this;
  3474. } else if (d->qt_rgn->within(r)) {
  3475. return r;
  3476. } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
  3477. return *this;
  3478. } else if (d->qt_rgn->canAppend(&r)) {
  3479. QRegion result(*this);
  3480. result.detach();
  3481. result.d->qt_rgn->append(&r);
  3482. return result;
  3483. } else if (d->qt_rgn->canPrepend(&r)) {
  3484. QRegion result(*this);
  3485. result.detach();
  3486. result.d->qt_rgn->prepend(&r);
  3487. return result;
  3488. } else {
  3489. QRegion result;
  3490. result.detach();
  3491. QRegionPrivate rp(r);
  3492. UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
  3493. return result;
  3494. }
  3495. }
  3496. QRegion& QRegion::operator+=(const QRect &r)
  3497. {
  3498. if (isEmptyHelper(d->qt_rgn))
  3499. return *this = r;
  3500. if (r.isEmpty())
  3501. return *this;
  3502. if (d->qt_rgn->contains(r)) {
  3503. return *this;
  3504. } else if (d->qt_rgn->within(r)) {
  3505. return *this = r;
  3506. } else if (d->qt_rgn->canAppend(&r)) {
  3507. detach();
  3508. d->qt_rgn->append(&r);
  3509. return *this;
  3510. } else if (d->qt_rgn->canPrepend(&r)) {
  3511. detach();
  3512. d->qt_rgn->prepend(&r);
  3513. return *this;
  3514. } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
  3515. return *this;
  3516. } else {
  3517. detach();
  3518. QRegionPrivate p(r);
  3519. UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
  3520. return *this;
  3521. }
  3522. }
  3523. QRegion QRegion::intersect(const QRegion &r) const
  3524. {
  3525. if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
  3526. || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
  3527. return QRegion();
  3528. /* this is fully contained in r */
  3529. if (r.d->qt_rgn->contains(*d->qt_rgn))
  3530. return *this;
  3531. /* r is fully contained in this */
  3532. if (d->qt_rgn->contains(*r.d->qt_rgn))
  3533. return r;
  3534. if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
  3535. const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
  3536. d->qt_rgn->extents);
  3537. return QRegion(rect);
  3538. } else if (r.d->qt_rgn->numRects == 1) {
  3539. QRegion result(*this);
  3540. result.detach();
  3541. result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
  3542. return result;
  3543. } else if (d->qt_rgn->numRects == 1) {
  3544. QRegion result(r);
  3545. result.detach();
  3546. result.d->qt_rgn->intersect(d->qt_rgn->extents);
  3547. return result;
  3548. }
  3549. QRegion result;
  3550. result.detach();
  3551. miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
  3552. /*
  3553. * Can't alter dest's extents before we call miRegionOp because
  3554. * it might be one of the source regions and miRegionOp depends
  3555. * on the extents of those regions being the same. Besides, this
  3556. * way there's no checking against rectangles that will be nuked
  3557. * due to coalescing, so we have to examine fewer rectangles.
  3558. */
  3559. miSetExtents(*result.d->qt_rgn);
  3560. return result;
  3561. }
  3562. QRegion QRegion::intersect(const QRect &r) const
  3563. {
  3564. if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
  3565. || !EXTENTCHECK(&d->qt_rgn->extents, &r))
  3566. return QRegion();
  3567. /* this is fully contained in r */
  3568. if (d->qt_rgn->within(r))
  3569. return *this;
  3570. /* r is fully contained in this */
  3571. if (d->qt_rgn->contains(r))
  3572. return r;
  3573. if (d->qt_rgn->numRects == 1) {
  3574. const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
  3575. r.normalized());
  3576. return QRegion(rect);
  3577. }
  3578. QRegion result(*this);
  3579. result.detach();
  3580. result.d->qt_rgn->intersect(r);
  3581. return result;
  3582. }
  3583. QRegion QRegion::subtract(const QRegion &r) const
  3584. {
  3585. if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
  3586. return *this;
  3587. if (r.d->qt_rgn->contains(*d->qt_rgn))
  3588. return QRegion();
  3589. if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
  3590. return *this;
  3591. if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
  3592. return QRegion();
  3593. #ifdef QT_REGION_DEBUG
  3594. d->qt_rgn->selfTest();
  3595. r.d->qt_rgn->selfTest();
  3596. #endif
  3597. QRegion result;
  3598. result.detach();
  3599. SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
  3600. #ifdef QT_REGION_DEBUG
  3601. result.d->qt_rgn->selfTest();
  3602. #endif
  3603. return result;
  3604. }
  3605. QRegion QRegion::eor(const QRegion &r) const
  3606. {
  3607. if (isEmptyHelper(d->qt_rgn)) {
  3608. return r;
  3609. } else if (isEmptyHelper(r.d->qt_rgn)) {
  3610. return *this;
  3611. } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
  3612. return (*this + r);
  3613. } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
  3614. return QRegion();
  3615. } else {
  3616. QRegion result;
  3617. result.detach();
  3618. XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
  3619. return result;
  3620. }
  3621. }
  3622. QRect QRegion::boundingRect() const
  3623. {
  3624. if (isEmpty())
  3625. return QRect();
  3626. return d->qt_rgn->extents;
  3627. }
  3628. /*! \internal
  3629. Returns true if \a rect is guaranteed to be fully contained in \a region.
  3630. A false return value does not guarantee the opposite.
  3631. */
  3632. #if defined(Q_WS_QWS) || defined(Q_WS_QPA)
  3633. Q_GUI_EXPORT
  3634. #endif
  3635. bool qt_region_strictContains(const QRegion &region, const QRect &rect)
  3636. {
  3637. if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
  3638. return false;
  3639. #if 0 // TEST_INNERRECT
  3640. static bool guard = false;
  3641. if (guard)
  3642. return false;
  3643. guard = true;
  3644. QRegion inner = region.d->qt_rgn->innerRect;
  3645. Q_ASSERT((inner - region).isEmpty());
  3646. guard = false;
  3647. int maxArea = 0;
  3648. for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
  3649. const QRect r = region.d->qt_rgn->rects.at(i);
  3650. if (r.width() * r.height() > maxArea)
  3651. maxArea = r.width() * r.height();
  3652. }
  3653. if (maxArea > region.d->qt_rgn->innerArea) {
  3654. qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
  3655. }
  3656. Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
  3657. #endif
  3658. const QRect r1 = region.d->qt_rgn->innerRect;
  3659. return (rect.left() >= r1.left() && rect.right() <= r1.right()
  3660. && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
  3661. }
  3662. QVector<QRect> QRegion::rects() const
  3663. {
  3664. if (d->qt_rgn) {
  3665. d->qt_rgn->vectorize();
  3666. // hw: modify the vector size directly to avoid reallocation
  3667. d->qt_rgn->rects.d->size = d->qt_rgn->numRects;
  3668. return d->qt_rgn->rects;
  3669. } else {
  3670. return QVector<QRect>();
  3671. }
  3672. }
  3673. void QRegion::setRects(const QRect *rects, int num)
  3674. {
  3675. *this = QRegion();
  3676. if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
  3677. return;
  3678. detach();
  3679. d->qt_rgn->numRects = num;
  3680. if (num == 1) {
  3681. d->qt_rgn->extents = *rects;
  3682. d->qt_rgn->innerRect = *rects;
  3683. } else {
  3684. d->qt_rgn->rects.resize(num);
  3685. int left = INT_MAX,
  3686. right = INT_MIN,
  3687. top = INT_MAX,
  3688. bottom = INT_MIN;
  3689. for (int i = 0; i < num; ++i) {
  3690. const QRect &rect = rects[i];
  3691. d->qt_rgn->rects[i] = rect;
  3692. left = qMin(rect.left(), left);
  3693. right = qMax(rect.right(), right);
  3694. top = qMin(rect.top(), top);
  3695. bottom = qMax(rect.bottom(), bottom);
  3696. d->qt_rgn->updateInnerRect(rect);
  3697. }
  3698. d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
  3699. }
  3700. }
  3701. int QRegion::numRects() const
  3702. {
  3703. return (d->qt_rgn ? d->qt_rgn->numRects : 0);
  3704. }
  3705. int QRegion::rectCount() const
  3706. {
  3707. return (d->qt_rgn ? d->qt_rgn->numRects : 0);
  3708. }
  3709. bool QRegion::operator==(const QRegion &r) const
  3710. {
  3711. if (!d->qt_rgn)
  3712. return r.isEmpty();
  3713. if (!r.d->qt_rgn)
  3714. return isEmpty();
  3715. if (d == r.d)
  3716. return true;
  3717. else
  3718. return EqualRegion(d->qt_rgn, r.d->qt_rgn);
  3719. }
  3720. bool QRegion::intersects(const QRect &rect) const
  3721. {
  3722. if (isEmptyHelper(d->qt_rgn) || rect.isNull())
  3723. return false;
  3724. const QRect r = rect.normalized();
  3725. if (!rect_intersects(d->qt_rgn->extents, r))
  3726. return false;
  3727. if (d->qt_rgn->numRects == 1)
  3728. return true;
  3729. const QVector<QRect> myRects = rects();
  3730. for (QVector<QRect>::const_iterator it = myRects.constBegin(); it < myRects.constEnd(); ++it)
  3731. if (rect_intersects(r, *it))
  3732. return true;
  3733. return false;
  3734. }
  3735. #endif
  3736. QT_END_NAMESPACE