PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  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 PAR…

Large files files are truncated, but you can click here to view the full file