PageRenderTime 80ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtbase/src/gui/painting/qregion.cpp

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