src/gui/painting/qregion_unix.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qregion.h"
00025 #include "qpainterpath.h"
00026 #include "qpolygon.h"
00027 #include "qbuffer.h"
00028 #include "qimage.h"
00029 #include <qdebug.h>
00030 #include "qbitmap.h"
00031 #include <stdlib.h>
00032 
00033 /*
00034  *   clip region
00035  */
00036 
00037 struct QRegionPrivate {
00038     int numRects;
00039     QVector<QRect> rects;
00040     QRect extents;
00041 #ifdef QT_EXPERIMENTAL_REGIONS
00042     QRect innerRect;
00043     int innerArea;
00044 #endif
00045 
00046     inline QRegionPrivate() : numRects(0) {}
00047     inline QRegionPrivate(const QRect &r) : rects(1) {
00048         numRects = 1;
00049         rects[0] = r;
00050         extents = r;
00051 #ifdef QT_EXPERIMENTAL_REGIONS
00052         innerRect = r;
00053         innerArea = r.width() * r.height();
00054 #endif
00055     }
00056 
00057     inline QRegionPrivate(const QRegionPrivate &r) {
00058         rects = r.rects;
00059         numRects = r.numRects;
00060         extents = r.extents;
00061 #ifdef QT_EXPERIMENTAL_REGIONS
00062         innerRect = r.innerRect;
00063         innerArea = r.innerArea;
00064 #endif
00065     }
00066 
00067     inline QRegionPrivate &operator=(const QRegionPrivate &r) {
00068         rects = r.rects;
00069         numRects = r.numRects;
00070         extents = r.extents;
00071 #ifdef QT_EXPERIMENTAL_REGIONS
00072         innerRect = r.innerRect;
00073         innerArea = r.innerArea;
00074 #endif
00075         return *this;
00076     }
00077 
00078 #ifdef QT_EXPERIMENTAL_REGIONS
00079     /*
00080      * Returns true if r is guaranteed to be fully contained in this region.
00081      * A false return value does not guarantee the opposite.
00082      */
00083     inline bool contains(const QRegionPrivate &r) const {
00084         const QRect &r1 = innerRect;
00085         const QRect &r2 = r.extents;
00086         return r2.left() >= r1.left() && r2.right() <= r1.right()
00087             && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
00088     }
00089 
00090     inline void updateInnerRect(const QRect &rect) {
00091         const int area = rect.width() * rect.height();
00092         if (area > innerArea) {
00093             innerArea = area;
00094             innerRect = rect;
00095         }
00096     }
00097 
00098     void append(const QRegionPrivate *r);
00099     inline bool canAppend(const QRegionPrivate *r) const;
00100 
00101 #endif
00102 };
00103 
00104 #ifdef QT_EXPERIMENTAL_REGIONS
00105 static inline bool isEmpty(const QRegionPrivate *preg)
00106 {
00107     return !preg || preg->numRects == 0;
00108 }
00109 
00110 void QRegionPrivate::append(const QRegionPrivate *r)
00111 {
00112     Q_ASSERT(!isEmpty(r));
00113 
00114     const int newNumRects = numRects + r->numRects;
00115     if (newNumRects > rects.size())
00116         rects.resize(newNumRects);
00117 
00118     // append rectangles
00119     QRect *destRect = rects.data() + numRects;
00120     const QRect *srcRect = r->rects.constData();
00121     for (int i = 0; i < r->numRects; ++i)
00122         *destRect++ = *srcRect++;
00123 
00124     // update inner rectangle
00125     if (innerArea < r->innerArea) {
00126         innerArea = r->innerArea;
00127         innerRect = r->innerRect;
00128     }
00129 
00130     // update extents
00131     destRect = &extents;
00132     srcRect = &r->extents;
00133     extents.setCoords(qMin(destRect->left(), srcRect->left()),
00134                       qMin(destRect->top(), srcRect->top()),
00135                       qMax(destRect->right(), srcRect->right()),
00136                       qMax(destRect->bottom(), srcRect->bottom()));
00137 
00138     numRects = newNumRects;
00139 }
00140 
00141 bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
00142 {
00143     Q_ASSERT(!isEmpty(r));
00144 
00145     const QRect *rFirst = r->rects.constData();
00146     const QRect *myLast = rects.constData() + (numRects - 1);
00147     // XXX: possible improvements:
00148     //   - same technique for prepending
00149     //   - nFirst->top() == myLast->bottom(), must possibly merge bands
00150     //   - rFirst->left() == myLast->right(), merge rectangles, possibly bands
00151     if (rFirst->top() > myLast->bottom()
00152         || (rFirst->top() == myLast->top()
00153             && rFirst->height() == myLast->height()
00154             && rFirst->left() > myLast->right()))
00155     {
00156         return true;
00157     }
00158 
00159     return false;
00160 }
00161 #endif // QT_EXPERIMENTAL_REGIONS
00162 
00163 #if defined(Q_WS_X11)
00164 # include "qregion_x11.cpp"
00165 #elif defined(Q_WS_MAC)
00166 # include "qregion_mac.cpp"
00167 #elif defined(Q_WS_QWS)
00168 static QRegionPrivate qrp;
00169 QRegion::QRegionData QRegion::shared_empty = {Q_ATOMIC_INIT(1), &qrp};
00170 #endif
00171 
00172 #ifndef QT_EXPERIMENTAL_REGIONS
00173 static inline bool isEmpty(const QRegionPrivate *preg)
00174 {
00175     return !preg || preg->numRects == 0;
00176 }
00177 #endif
00178 
00179 typedef void (*OverlapFunc)(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
00180                             register const QRect *r2, const QRect *r2End, register int y1, register int y2);
00181 typedef void (*NonOverlapFunc)(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
00182                                register int y1, register int y2);
00183 
00184 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
00185 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
00186 static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
00187                        OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
00188                        NonOverlapFunc nonOverlap2Func);
00189 
00190 #define RectangleOut 0
00191 #define RectangleIn 1
00192 #define RectanglePart 2
00193 #define EvenOddRule 0
00194 #define WindingRule 1
00195 
00196 // START OF region.h extract
00197 /* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
00198 /************************************************************************
00199 
00200 Copyright (c) 1987  X Consortium
00201 
00202 Permission is hereby granted, free of charge, to any person obtaining a copy
00203 of this software and associated documentation files (the "Software"), to deal
00204 in the Software without restriction, including without limitation the rights
00205 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00206 copies of the Software, and to permit persons to whom the Software is
00207 furnished to do so, subject to the following conditions:
00208 
00209 The above copyright notice and this permission notice shall be included in
00210 all copies or substantial portions of the Software.
00211 
00212 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00213 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00214 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00215 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00216 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00217 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00218 
00219 Except as contained in this notice, the name of the X Consortium shall not be
00220 used in advertising or otherwise to promote the sale, use or other dealings
00221 in this Software without prior written authorization from the X Consortium.
00222 
00223 
00224 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
00225 
00226                         All Rights Reserved
00227 
00228 Permission to use, copy, modify, and distribute this software and its
00229 documentation for any purpose and without fee is hereby granted,
00230 provided that the above copyright notice appear in all copies and that
00231 both that copyright notice and this permission notice appear in
00232 supporting documentation, and that the name of Digital not be
00233 used in advertising or publicity pertaining to distribution of the
00234 software without specific, written prior permission.
00235 
00236 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00237 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00238 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00239 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00240 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00241 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00242 SOFTWARE.
00243 
00244 ************************************************************************/
00245 
00246 #ifndef _XREGION_H
00247 #define _XREGION_H
00248 
00249 #include <limits.h>
00250 
00251 /*  1 if two BOXs overlap.
00252  *  0 if two BOXs do not overlap.
00253  *  Remember, x2 and y2 are not in the region
00254  */
00255 #define EXTENTCHECK(r1, r2) \
00256         ((r1)->right() >= (r2)->left() && \
00257          (r1)->left() <= (r2)->right() && \
00258          (r1)->bottom() >= (r2)->top() && \
00259          (r1)->top() <= (r2)->bottom())
00260 
00261 /*
00262  *  update region extents
00263  */
00264 #define EXTENTS(r,idRect){\
00265             if((r)->left() < (idRect)->extents.left())\
00266               (idRect)->extents.setLeft((r)->left());\
00267             if((r)->top() < (idRect)->extents.top())\
00268               (idRect)->extents.setTop((r)->top());\
00269             if((r)->right() > (idRect)->extents.right())\
00270               (idRect)->extents.setRight((r)->right());\
00271             if((r)->bottom() > (idRect)->extents.bottom())\
00272               (idRect)->extents.setBottom((r)->bottom());\
00273         }
00274 
00275 /*
00276  *   Check to see if there is enough memory in the present region.
00277  */
00278 #define MEMCHECK(dest, rect, firstrect){\
00279         if ((dest).numRects >= ((dest).rects.size()-1)){\
00280           firstrect.resize(firstrect.size() * 2); \
00281           (rect) = (firstrect).data() + (dest).numRects;\
00282         }\
00283       }
00284 
00285 
00286 /*
00287  * number of points to buffer before sending them off
00288  * to scanlines(): Must be an even number
00289  */
00290 #define NUMPTSTOBUFFER 200
00291 
00292 /*
00293  * used to allocate buffers for points and link
00294  * the buffers together
00295  */
00296 typedef struct _POINTBLOCK {
00297     QPoint pts[NUMPTSTOBUFFER];
00298     struct _POINTBLOCK *next;
00299 } POINTBLOCK;
00300 
00301 #endif
00302 // END OF region.h extract
00303 
00304 // START OF Region.c extract
00305 /* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
00306 /************************************************************************
00307 
00308 Copyright (c) 1987, 1988  X Consortium
00309 
00310 Permission is hereby granted, free of charge, to any person obtaining a copy
00311 of this software and associated documentation files (the "Software"), to deal
00312 in the Software without restriction, including without limitation the rights
00313 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00314 copies of the Software, and to permit persons to whom the Software is
00315 furnished to do so, subject to the following conditions:
00316 
00317 The above copyright notice and this permission notice shall be included in
00318 all copies or substantial portions of the Software.
00319 
00320 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00321 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00322 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00323 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00324 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00325 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00326 
00327 Except as contained in this notice, the name of the X Consortium shall not be
00328 used in advertising or otherwise to promote the sale, use or other dealings
00329 in this Software without prior written authorization from the X Consortium.
00330 
00331 
00332 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
00333 
00334                         All Rights Reserved
00335 
00336 Permission to use, copy, modify, and distribute this software and its
00337 documentation for any purpose and without fee is hereby granted,
00338 provided that the above copyright notice appear in all copies and that
00339 both that copyright notice and this permission notice appear in
00340 supporting documentation, and that the name of Digital not be
00341 used in advertising or publicity pertaining to distribution of the
00342 software without specific, written prior permission.
00343 
00344 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00345 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00346 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00347 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00348 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00349 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00350 SOFTWARE.
00351 
00352 ************************************************************************/
00353 /*
00354  * The functions in this file implement the Region abstraction, similar to one
00355  * used in the X11 sample server. A Region is simply an area, as the name
00356  * implies, and is implemented as a "y-x-banded" array of rectangles. To
00357  * explain: Each Region is made up of a certain number of rectangles sorted
00358  * by y coordinate first, and then by x coordinate.
00359  *
00360  * Furthermore, the rectangles are banded such that every rectangle with a
00361  * given upper-left y coordinate (y1) will have the same lower-right y
00362  * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
00363  * will span the entire vertical distance of the band. This means that some
00364  * areas that could be merged into a taller rectangle will be represented as
00365  * several shorter rectangles to account for shorter rectangles to its left
00366  * or right but within its "vertical scope".
00367  *
00368  * An added constraint on the rectangles is that they must cover as much
00369  * horizontal area as possible. E.g. no two rectangles in a band are allowed
00370  * to touch.
00371  *
00372  * Whenever possible, bands will be merged together to cover a greater vertical
00373  * distance (and thus reduce the number of rectangles). Two bands can be merged
00374  * only if the bottom of one touches the top of the other and they have
00375  * rectangles in the same places (of the same width, of course). This maintains
00376  * the y-x-banding that's so nice to have...
00377  */
00378 /* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
00379 
00380 static void UnionRectWithRegion(register const QRect *rect, const QRegionPrivate *source,
00381                                 QRegionPrivate &dest)
00382 {
00383     if (!rect->width() || !rect->height())
00384         return;
00385 
00386     QRegionPrivate region;
00387     region.rects.resize(1);
00388     region.numRects = 1;
00389     region.rects[0] = *rect;
00390     region.extents = *rect;
00391 #ifdef QT_EXPERIMENTAL_REGIONS
00392     region.innerRect = *rect;
00393     region.innerArea = rect->width() * rect->height();
00394 #endif
00395 
00396     UnionRegion(&region, source, dest);
00397     return;
00398 }
00399 
00400 /*-
00401  *-----------------------------------------------------------------------
00402  * miSetExtents --
00403  *      Reset the extents and innerRect of a region to what they should be.
00404  *      Called by miSubtract and miIntersect b/c they can't figure it out
00405  *      along the way or do so easily, as miUnion can.
00406  *
00407  * Results:
00408  *      None.
00409  *
00410  * Side Effects:
00411  *      The region's 'extents' and 'innerRect' structure is overwritten.
00412  *
00413  *-----------------------------------------------------------------------
00414  */
00415 static void miSetExtents(QRegionPrivate &dest)
00416 {
00417     register const QRect *pBox,
00418                          *pBoxEnd;
00419     register QRect *pExtents;
00420 
00421 #ifdef QT_EXPERIMENTAL_REGIONS
00422     dest.innerRect.setCoords(0, 0, -1, -1);
00423     dest.innerArea = -1;
00424 #endif
00425     if (dest.numRects == 0) {
00426         dest.extents.setCoords(0, 0, 0, 0);
00427         return;
00428     }
00429 
00430     pExtents = &dest.extents;
00431     pBox = dest.rects.constData();
00432     pBoxEnd = &pBox[dest.numRects - 1];
00433 
00434     /*
00435      * Since pBox is the first rectangle in the region, it must have the
00436      * smallest y1 and since pBoxEnd is the last rectangle in the region,
00437      * it must have the largest y2, because of banding. Initialize x1 and
00438      * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
00439      * to...
00440      */
00441     pExtents->setLeft(pBox->left());
00442     pExtents->setTop(pBox->top());
00443     pExtents->setRight(pBoxEnd->right());
00444     pExtents->setBottom(pBoxEnd->bottom());
00445 
00446     Q_ASSERT(pExtents->top() <= pExtents->bottom());
00447     while (pBox <= pBoxEnd) {
00448         if (pBox->left() < pExtents->left())
00449             pExtents->setLeft(pBox->left());
00450         if (pBox->right() > pExtents->right())
00451             pExtents->setRight(pBox->right());
00452 #ifdef QT_EXPERIMENTAL_REGIONS
00453         dest.updateInnerRect(*pBox);
00454 #endif
00455         ++pBox;
00456     }
00457     Q_ASSERT(pExtents->left() <= pExtents->right());
00458 }
00459 
00460 /* TranslateRegion(pRegion, x, y)
00461    translates in place
00462    added by raymond
00463 */
00464 
00465 static void OffsetRegion(register QRegionPrivate &region, register int x, register int y)
00466 {
00467     register int nbox;
00468     register QRect *pbox;
00469 
00470     pbox = region.rects.data();
00471     nbox = region.numRects;
00472 
00473     while (nbox--) {
00474         pbox->translate(x, y);
00475         ++pbox;
00476     }
00477     region.extents.translate(x, y);
00478 #ifdef QT_EXPERIMENTAL_REGIONS
00479     region.innerRect.translate(x, y);
00480 #endif
00481 }
00482 
00483 /*======================================================================
00484  *          Region Intersection
00485  *====================================================================*/
00486 /*-
00487  *-----------------------------------------------------------------------
00488  * miIntersectO --
00489  *      Handle an overlapping band for miIntersect.
00490  *
00491  * Results:
00492  *      None.
00493  *
00494  * Side Effects:
00495  *      Rectangles may be added to the region.
00496  *
00497  *-----------------------------------------------------------------------
00498  */
00499 static void miIntersectO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
00500                          register const QRect *r2, const QRect *r2End, int y1, int y2)
00501 {
00502     register int x1;
00503     register int x2;
00504     register QRect *pNextRect;
00505 
00506     pNextRect = dest.rects.data() + dest.numRects;
00507 
00508     while (r1 != r1End && r2 != r2End) {
00509         x1 = qMax(r1->left(), r2->left());
00510         x2 = qMin(r1->right(), r2->right());
00511 
00512         /*
00513          * If there's any overlap between the two rectangles, add that
00514          * overlap to the new region.
00515          * There's no need to check for subsumption because the only way
00516          * such a need could arise is if some region has two rectangles
00517          * right next to each other. Since that should never happen...
00518          */
00519         if (x1 <= x2) {
00520             Q_ASSERT(y1 <= y2);
00521             MEMCHECK(dest, pNextRect, dest.rects)
00522             pNextRect->setCoords(x1, y1, x2, y2);
00523             ++dest.numRects;
00524             ++pNextRect;
00525         }
00526 
00527         /*
00528          * Need to advance the pointers. Shift the one that extends
00529          * to the right the least, since the other still has a chance to
00530          * overlap with that region's next rectangle, if you see what I mean.
00531          */
00532         if (r1->right() < r2->right()) {
00533             ++r1;
00534         } else if (r2->right() < r1->right()) {
00535             ++r2;
00536         } else {
00537             ++r1;
00538             ++r2;
00539         }
00540     }
00541 }
00542 
00543 /*======================================================================
00544  *          Generic Region Operator
00545  *====================================================================*/
00546 
00547 /*-
00548  *-----------------------------------------------------------------------
00549  * miCoalesce --
00550  *      Attempt to merge the boxes in the current band with those in the
00551  *      previous one. Used only by miRegionOp.
00552  *
00553  * Results:
00554  *      The new index for the previous band.
00555  *
00556  * Side Effects:
00557  *      If coalescing takes place:
00558  *          - rectangles in the previous band will have their y2 fields
00559  *            altered.
00560  *          - dest.numRects will be decreased.
00561  *
00562  *-----------------------------------------------------------------------
00563  */
00564 static int miCoalesce(register QRegionPrivate &dest, int prevStart, int curStart)
00565 {
00566     register QRect *pPrevBox;   /* Current box in previous band */
00567     register QRect *pCurBox;    /* Current box in current band */
00568     register QRect *pRegEnd;    /* End of region */
00569     int curNumRects;    /* Number of rectangles in current band */
00570     int prevNumRects;   /* Number of rectangles in previous band */
00571     int bandY1;         /* Y1 coordinate for current band */
00572     QRect *rData = dest.rects.data();
00573 
00574     pRegEnd = rData + dest.numRects;
00575 
00576     pPrevBox = rData + prevStart;
00577     prevNumRects = curStart - prevStart;
00578 
00579     /*
00580      * Figure out how many rectangles are in the current band. Have to do
00581      * this because multiple bands could have been added in miRegionOp
00582      * at the end when one region has been exhausted.
00583      */
00584     pCurBox = rData + curStart;
00585     bandY1 = pCurBox->top();
00586     for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
00587         ++pCurBox;
00588     }
00589 
00590     if (pCurBox != pRegEnd) {
00591         /*
00592          * If more than one band was added, we have to find the start
00593          * of the last band added so the next coalescing job can start
00594          * at the right place... (given when multiple bands are added,
00595          * this may be pointless -- see above).
00596          */
00597         --pRegEnd;
00598         while ((pRegEnd - 1)->top() == pRegEnd->top())
00599             --pRegEnd;
00600         curStart = pRegEnd - rData;
00601         pRegEnd = rData + dest.numRects;
00602     }
00603 
00604     if (curNumRects == prevNumRects && curNumRects != 0) {
00605         pCurBox -= curNumRects;
00606         /*
00607          * The bands may only be coalesced if the bottom of the previous
00608          * matches the top scanline of the current.
00609          */
00610         if (pPrevBox->bottom() == pCurBox->top() - 1) {
00611             /*
00612              * Make sure the bands have boxes in the same places. This
00613              * assumes that boxes have been added in such a way that they
00614              * cover the most area possible. I.e. two boxes in a band must
00615              * have some horizontal space between them.
00616              */
00617             do {
00618                 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
00619                      // The bands don't line up so they can't be coalesced.
00620                     return curStart;
00621                 }
00622                 ++pPrevBox;
00623                 ++pCurBox;
00624                 --prevNumRects;
00625             } while (prevNumRects != 0);
00626 
00627             dest.numRects -= curNumRects;
00628             pCurBox -= curNumRects;
00629             pPrevBox -= curNumRects;
00630 
00631             /*
00632              * The bands may be merged, so set the bottom y of each box
00633              * in the previous band to that of the corresponding box in
00634              * the current band.
00635              */
00636             do {
00637                 pPrevBox->setBottom(pCurBox->bottom());
00638 #ifdef QT_EXPERIMENTAL_REGIONS
00639                 dest.updateInnerRect(*pPrevBox);
00640 #endif
00641                 ++pPrevBox;
00642                 ++pCurBox;
00643                 curNumRects -= 1;
00644             } while (curNumRects != 0);
00645 
00646             /*
00647              * If only one band was added to the region, we have to backup
00648              * curStart to the start of the previous band.
00649              *
00650              * If more than one band was added to the region, copy the
00651              * other bands down. The assumption here is that the other bands
00652              * came from the same region as the current one and no further
00653              * coalescing can be done on them since it's all been done
00654              * already... curStart is already in the right place.
00655              */
00656             if (pCurBox == pRegEnd) {
00657                 curStart = prevStart;
00658             } else {
00659                 do {
00660                     *pPrevBox++ = *pCurBox++;
00661 #ifdef QT_EXPERIMENTAL_REGIONS
00662                     dest.updateInnerRect(*pPrevBox);
00663 #endif
00664                 } while (pCurBox != pRegEnd);
00665             }
00666         }
00667     }
00668     return curStart;
00669 }
00670 
00671 /*-
00672  *-----------------------------------------------------------------------
00673  * miRegionOp --
00674  *      Apply an operation to two regions. Called by miUnion, miInverse,
00675  *      miSubtract, miIntersect...
00676  *
00677  * Results:
00678  *      None.
00679  *
00680  * Side Effects:
00681  *      The new region is overwritten.
00682  *
00683  * Notes:
00684  *      The idea behind this function is to view the two regions as sets.
00685  *      Together they cover a rectangle of area that this function divides
00686  *      into horizontal bands where points are covered only by one region
00687  *      or by both. For the first case, the nonOverlapFunc is called with
00688  *      each the band and the band's upper and lower extents. For the
00689  *      second, the overlapFunc is called to process the entire band. It
00690  *      is responsible for clipping the rectangles in the band, though
00691  *      this function provides the boundaries.
00692  *      At the end of each band, the new region is coalesced, if possible,
00693  *      to reduce the number of rectangles in the region.
00694  *
00695  *-----------------------------------------------------------------------
00696  */
00697 static void miRegionOp(register QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
00698                        OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
00699                        NonOverlapFunc nonOverlap2Func)
00700 {
00701     register const QRect *r1;         // Pointer into first region
00702     register const QRect *r2;         // Pointer into 2d region
00703     const QRect *r1End;               // End of 1st region
00704     const QRect *r2End;               // End of 2d region
00705     register int ybot;          // Bottom of intersection
00706     register int ytop;          // Top of intersection
00707     int prevBand;               // Index of start of previous band in dest
00708     int curBand;                // Index of start of current band in dest
00709     register const QRect *r1BandEnd;  // End of current band in r1
00710     register const QRect *r2BandEnd;  // End of current band in r2
00711     int top;                    // Top of non-overlapping band
00712     int bot;                    // Bottom of non-overlapping band
00713 
00714     /*
00715      * Initialization:
00716      *  set r1, r2, r1End and r2End appropriately, preserve the important
00717      * parts of the destination region until the end in case it's one of
00718      * the two source regions, then mark the "new" region empty, allocating
00719      * another array of rectangles for it to use.
00720      */
00721     r1 = reg1->rects.data();
00722     r2 = reg2->rects.data();
00723     r1End = r1 + reg1->numRects;
00724     r2End = r2 + reg2->numRects;
00725 
00726     QVector<QRect> oldRects = dest.rects;
00727 
00728     dest.numRects = 0;
00729 
00730     /*
00731      * Allocate a reasonable number of rectangles for the new region. The idea
00732      * is to allocate enough so the individual functions don't need to
00733      * reallocate and copy the array, which is time consuming, yet we don't
00734      * have to worry about using too much memory. I hope to be able to
00735      * nuke the realloc() at the end of this function eventually.
00736      */
00737     dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
00738 
00739     /*
00740      * Initialize ybot and ytop.
00741      * In the upcoming loop, ybot and ytop serve different functions depending
00742      * on whether the band being handled is an overlapping or non-overlapping
00743      * band.
00744      *  In the case of a non-overlapping band (only one of the regions
00745      * has points in the band), ybot is the bottom of the most recent
00746      * intersection and thus clips the top of the rectangles in that band.
00747      * ytop is the top of the next intersection between the two regions and
00748      * serves to clip the bottom of the rectangles in the current band.
00749      *  For an overlapping band (where the two regions intersect), ytop clips
00750      * the top of the rectangles of both regions and ybot clips the bottoms.
00751      */
00752     if (reg1->extents.top() < reg2->extents.top())
00753         ybot = reg1->extents.top() - 1;
00754     else
00755         ybot = reg2->extents.top() - 1;
00756 
00757     /*
00758      * prevBand serves to mark the start of the previous band so rectangles
00759      * can be coalesced into larger rectangles. qv. miCoalesce, above.
00760      * In the beginning, there is no previous band, so prevBand == curBand
00761      * (curBand is set later on, of course, but the first band will always
00762      * start at index 0). prevBand and curBand must be indices because of
00763      * the possible expansion, and resultant moving, of the new region's
00764      * array of rectangles.
00765      */
00766     prevBand = 0;
00767 
00768     do {
00769         curBand = dest.numRects;
00770 
00771         /*
00772          * This algorithm proceeds one source-band (as opposed to a
00773          * destination band, which is determined by where the two regions
00774          * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
00775          * rectangle after the last one in the current band for their
00776          * respective regions.
00777          */
00778         r1BandEnd = r1;
00779         while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
00780             ++r1BandEnd;
00781 
00782         r2BandEnd = r2;
00783         while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
00784             ++r2BandEnd;
00785 
00786         /*
00787          * First handle the band that doesn't intersect, if any.
00788          *
00789          * Note that attention is restricted to one band in the
00790          * non-intersecting region at once, so if a region has n
00791          * bands between the current position and the next place it overlaps
00792          * the other, this entire loop will be passed through n times.
00793          */
00794         if (r1->top() < r2->top()) {
00795             top = qMax(r1->top(), ybot + 1);
00796             bot = qMin(r1->bottom(), r2->top() - 1);
00797 
00798             if (nonOverlap1Func != 0 && bot >= top)
00799                 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
00800             ytop = r2->top();
00801         } else if (r2->top() < r1->top()) {
00802             top = qMax(r2->top(), ybot + 1);
00803             bot = qMin(r2->bottom(), r1->top() - 1);
00804 
00805             if (nonOverlap2Func != 0 && bot >= top)
00806                 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
00807             ytop = r1->top();
00808         } else {
00809             ytop = r1->top();
00810         }
00811 
00812         /*
00813          * If any rectangles got added to the region, try and coalesce them
00814          * with rectangles from the previous band. Note we could just do
00815          * this test in miCoalesce, but some machines incur a not
00816          * inconsiderable cost for function calls, so...
00817          */
00818         if (dest.numRects != curBand)
00819             prevBand = miCoalesce(dest, prevBand, curBand);
00820 
00821         /*
00822          * Now see if we've hit an intersecting band. The two bands only
00823          * intersect if ybot >= ytop
00824          */
00825         ybot = qMin(r1->bottom(), r2->bottom());
00826         curBand = dest.numRects;
00827         if (ybot >= ytop)
00828             (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
00829 
00830         if (dest.numRects != curBand)
00831             prevBand = miCoalesce(dest, prevBand, curBand);
00832 
00833         /*
00834          * If we've finished with a band (y2 == ybot) we skip forward
00835          * in the region to the next band.
00836          */
00837         if (r1->bottom() == ybot)
00838             r1 = r1BandEnd;
00839         if (r2->bottom() == ybot)
00840             r2 = r2BandEnd;
00841     } while (r1 != r1End && r2 != r2End);
00842 
00843     /*
00844      * Deal with whichever region still has rectangles left.
00845      */
00846     curBand = dest.numRects;
00847     if (r1 != r1End) {
00848         if (nonOverlap1Func != 0) {
00849             do {
00850                 r1BandEnd = r1;
00851                 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
00852                     ++r1BandEnd;
00853                 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
00854                 r1 = r1BandEnd;
00855             } while (r1 != r1End);
00856         }
00857     } else if ((r2 != r2End) && (nonOverlap2Func != 0)) {
00858         do {
00859             r2BandEnd = r2;
00860             while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
00861                  ++r2BandEnd;
00862             (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
00863             r2 = r2BandEnd;
00864         } while (r2 != r2End);
00865     }
00866 
00867     if (dest.numRects != curBand)
00868         (void)miCoalesce(dest, prevBand, curBand);
00869 
00870     /*
00871      * A bit of cleanup. To keep regions from growing without bound,
00872      * we shrink the array of rectangles to match the new number of
00873      * rectangles in the region.
00874      *
00875      * Only do this stuff if the number of rectangles allocated is more than
00876      * twice the number of rectangles in the region (a simple optimization).
00877      */
00878 #ifdef QT_EXPERIMENTAL_REGIONS
00879     if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
00880 #else
00881     if (dest.numRects < (dest.rects.size() >> 1))
00882 #endif
00883         dest.rects.resize(dest.numRects);
00884 }
00885 
00886 /*======================================================================
00887  *          Region Union
00888  *====================================================================*/
00889 
00890 /*-
00891  *-----------------------------------------------------------------------
00892  * miUnionNonO --
00893  *      Handle a non-overlapping band for the union operation. Just
00894  *      Adds the rectangles into the region. Doesn't have to check for
00895  *      subsumption or anything.
00896  *
00897  * Results:
00898  *      None.
00899  *
00900  * Side Effects:
00901  *      dest.numRects is incremented and the final rectangles overwritten
00902  *      with the rectangles we're passed.
00903  *
00904  *-----------------------------------------------------------------------
00905  */
00906 
00907 static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd,
00908                         register int y1, register int y2)
00909 {
00910     register QRect *pNextRect;
00911 
00912     pNextRect = dest.rects.data() + dest.numRects;
00913 
00914     Q_ASSERT(y1 <= y2);
00915 
00916     while (r != rEnd) {
00917         Q_ASSERT(r->left() <= r->right());
00918         MEMCHECK(dest, pNextRect, dest.rects)
00919         pNextRect->setCoords(r->left(), y1, r->right(), y2);
00920         dest.numRects++;
00921         ++pNextRect;
00922         ++r;
00923     }
00924 }
00925 
00926 
00927 /*-
00928  *-----------------------------------------------------------------------
00929  * miUnionO --
00930  *      Handle an overlapping band for the union operation. Picks the
00931  *      left-most rectangle each time and merges it into the region.
00932  *
00933  * Results:
00934  *      None.
00935  *
00936  * Side Effects:
00937  *      Rectangles are overwritten in dest.rects and dest.numRects will
00938  *      be changed.
00939  *
00940  *-----------------------------------------------------------------------
00941  */
00942 
00943 static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
00944                      register const QRect *r2, const QRect *r2End, register int y1, register int y2)
00945 {
00946     register QRect *pNextRect;
00947 
00948     pNextRect = dest.rects.data() + dest.numRects;
00949 
00950 #ifndef QT_EXPERIMENTAL_REGIONS
00951 #define MERGERECT(r)             \
00952     if ((dest.numRects != 0) &&  \
00953         (pNextRect[-1].top() == y1) &&  \
00954         (pNextRect[-1].bottom() == y2) &&  \
00955         (pNextRect[-1].right() >= r->left()-1)) { \
00956         if (pNextRect[-1].right() < r->right()) { \
00957             pNextRect[-1].setRight(r->right());  \
00958             Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
00959         }  \
00960     } else { \
00961         MEMCHECK(dest, pNextRect, dest.rects)  \
00962         pNextRect->setCoords(r->left(), y1, r->right(), y2); \
00963         dest.numRects++;  \
00964         pNextRect++;  \
00965     }  \
00966     r++;
00967 #else
00968 #define MERGERECT(r)             \
00969     if ((dest.numRects != 0) &&  \
00970         (pNextRect[-1].top() == y1) &&  \
00971         (pNextRect[-1].bottom() == y2) &&  \
00972         (pNextRect[-1].right() >= r->left()-1)) { \
00973         if (pNextRect[-1].right() < r->right()) { \
00974             pNextRect[-1].setRight(r->right());  \
00975             dest.updateInnerRect(pNextRect[-1]); \
00976             Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
00977         }  \
00978     } else { \
00979         MEMCHECK(dest, pNextRect, dest.rects)  \
00980         pNextRect->setCoords(r->left(), y1, r->right(), y2); \
00981         dest.updateInnerRect(*pNextRect); \
00982         dest.numRects++;  \
00983         pNextRect++;  \
00984     }  \
00985     r++;
00986 #endif
00987 
00988     Q_ASSERT(y1 <= y2);
00989     while (r1 != r1End && r2 != r2End) {
00990         if (r1->left() < r2->left()) {
00991             MERGERECT(r1)
00992         } else {
00993             MERGERECT(r2)
00994         }
00995     }
00996 
00997     if (r1 != r1End) {
00998         do {
00999             MERGERECT(r1)
01000         } while (r1 != r1End);
01001     } else {
01002         while (r2 != r2End) {
01003             MERGERECT(r2)
01004         }
01005     }
01006 }
01007 
01008 static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
01009 {
01010 #ifdef QT_EXPERIMENTAL_REGIONS
01011     /*
01012       Empty region
01013     */
01014     if (isEmpty(reg1)) {
01015         dest = *reg2;
01016         return;
01017     }
01018     if (isEmpty(reg2)) {
01019         dest = *reg1;
01020         return;
01021     }
01022 
01023     /*
01024       A region completely subsumes the other
01025     */
01026     if (reg1->contains(*reg2)) {
01027         dest = *reg1;
01028         return;
01029     }
01030     if (reg2->contains(*reg1)) {
01031         dest = *reg2;
01032         return;
01033     }
01034 
01035     /*
01036       Regions are equal.
01037     */
01038     if (EqualRegion(reg1, reg2)) {
01039         dest = *reg1;
01040         return;
01041     }
01042 
01043     /*
01044       Can append reg2 to reg1
01045     */
01046     if (reg1->canAppend(reg2)) {
01047         dest = *reg1;
01048         dest.append(reg2);
01049         return;
01050     }
01051 
01052     /*
01053       Can append reg1 to reg2
01054     */
01055     if (reg2->canAppend(reg1)) {
01056         dest = *reg2;
01057         dest.append(reg1);
01058         return;
01059     }
01060 #else
01061     /*
01062       Region 1 is empty or is equal to region 2.
01063     */
01064     if (reg1 == reg2 || isEmpty(reg1)) {
01065         if (!isEmpty(reg2))
01066             dest = *reg2;
01067         return;
01068     }
01069 
01070     /*
01071       Region 2 is empty (and region 1 isn't).
01072     */
01073     if (isEmpty(reg2)) {
01074         dest = *reg1;
01075         return;
01076     }
01077 
01078     /*
01079       Region 1 completely subsumes region 2.
01080      */
01081     if (reg1->numRects == 1 && reg1->extents.left() <= reg2->extents.left()
01082             && reg1->extents.top() <= reg2->extents.top()
01083             && reg1->extents.right() >= reg2->extents.right()
01084             && reg1->extents.bottom() >= reg2->extents.bottom()) {
01085         dest = *reg1;
01086         return;
01087     }
01088 
01089     /*
01090       Region 2 completely subsumes region 1.
01091      */
01092     if (reg2->numRects == 1 && reg2->extents.left() <= reg1->extents.left()
01093             && reg2->extents.top() <= reg1->extents.top()
01094             && reg2->extents.right() >= reg1->extents.right()
01095             && reg2->extents.bottom() >= reg1->extents.bottom()) {
01096         dest = *reg2;
01097         return;
01098     }
01099 #endif
01100 
01101 #ifdef QT_EXPERIMENTAL_REGIONS
01102     if (reg1->innerArea > reg2->innerArea) {
01103         dest.innerArea = reg1->innerArea;
01104         dest.innerRect = reg1->innerRect;
01105     } else {
01106         dest.innerArea = reg2->innerArea;
01107         dest.innerRect = reg2->innerRect;
01108     }
01109 #endif
01110     miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
01111 
01112     dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
01113                            qMin(reg1->extents.top(), reg2->extents.top()),
01114                            qMax(reg1->extents.right(), reg2->extents.right()),
01115                            qMax(reg1->extents.bottom(), reg2->extents.bottom()));
01116 }
01117 
01118 /*======================================================================
01119  *        Region Subtraction
01120  *====================================================================*/
01121 
01122 /*-
01123  *-----------------------------------------------------------------------
01124  * miSubtractNonO --
01125  *      Deal with non-overlapping band for subtraction. Any parts from
01126  *      region 2 we discard. Anything from region 1 we add to the region.
01127  *
01128  * Results:
01129  *      None.
01130  *
01131  * Side Effects:
01132  *      dest may be affected.
01133  *
01134  *-----------------------------------------------------------------------
01135  */
01136 
01137 static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r,
01138                             const QRect *rEnd, register int y1, register int y2)
01139 {
01140     register QRect *pNextRect;
01141 
01142     pNextRect = dest.rects.data() + dest.numRects;
01143 
01144     Q_ASSERT(y1<=y2);
01145 
01146     while (r != rEnd) {
01147         Q_ASSERT(r->left() <= r->right());
01148         MEMCHECK(dest, pNextRect, dest.rects)
01149         pNextRect->setCoords(r->left(), y1, r->right(), y2);
01150         ++dest.numRects;
01151         ++pNextRect;
01152         ++r;
01153     }
01154 }
01155 
01156 /*-
01157  *-----------------------------------------------------------------------
01158  * miSubtractO --
01159  *      Overlapping band subtraction. x1 is the left-most point not yet
01160  *      checked.
01161  *
01162  * Results:
01163  *      None.
01164  *
01165  * Side Effects:
01166  *      dest may have rectangles added to it.
01167  *
01168  *-----------------------------------------------------------------------
01169  */
01170 
01171 static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End,
01172                         register const QRect *r2, const QRect *r2End, register int y1, register int y2)
01173 {
01174     register QRect *pNextRect;
01175     register int x1;
01176 
01177     x1 = r1->left();
01178 
01179     Q_ASSERT(y1 <= y2);
01180     pNextRect = dest.rects.data() + dest.numRects;
01181 
01182     while (r1 != r1End && r2 != r2End) {
01183         if (r2->right() < x1) {
01184             /*
01185              * Subtrahend missed the boat: go to next subtrahend.
01186              */
01187             ++r2;
01188         } else if (r2->left() <= x1) {
01189             /*
01190              * Subtrahend precedes minuend: nuke left edge of minuend.
01191              */
01192             x1 = r2->right() + 1;
01193             if (x1 > r1->right()) {
01194                 /*
01195                  * Minuend completely covered: advance to next minuend and
01196                  * reset left fence to edge of new minuend.
01197                  */
01198                 ++r1;
01199                 if (r1 != r1End)
01200                     x1 = r1->left();
01201             } else {
01202                 // Subtrahend now used up since it doesn't extend beyond minuend
01203                 ++r2;
01204             }
01205         } else if (r2->left() <= r1->right()) {
01206             /*
01207              * Left part of subtrahend covers part of minuend: add uncovered
01208              * part of minuend to region and skip to next subtrahend.
01209              */
01210             Q_ASSERT(x1 < r2->left());
01211             MEMCHECK(dest, pNextRect, dest.rects)
01212             pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
01213             ++dest.numRects;
01214             ++pNextRect;
01215 
01216             x1 = r2->right() + 1;
01217             if (x1 > r1->right()) {
01218                 /*
01219                  * Minuend used up: advance to new...
01220                  */
01221                 ++r1;
01222                 if (r1 != r1End)
01223                     x1 = r1->left();
01224             } else {
01225                 // Subtrahend used up
01226                 ++r2;
01227             }
01228         } else {
01229             /*
01230              * Minuend used up: add any remaining piece before advancing.
01231              */
01232             if (r1->right() >= x1) {
01233                 MEMCHECK(dest, pNextRect, dest.rects)
01234                 pNextRect->setCoords(x1, y1, r1->right(), y2);
01235                 ++dest.numRects;
01236                 ++pNextRect;
01237             }
01238             ++r1;
01239             if (r1 != r1End)
01240                 x1 = r1->left();
01241         }
01242     }
01243 
01244     /*
01245      * Add remaining minuend rectangles to region.
01246      */
01247     while (r1 != r1End) {
01248         Q_ASSERT(x1 <= r1->right());
01249         MEMCHECK(dest, pNextRect, dest.rects)
01250         pNextRect->setCoords(x1, y1, r1->right(), y2);
01251         ++dest.numRects;
01252         ++pNextRect;
01253 
01254         ++r1;
01255         if (r1 != r1End)
01256             x1 = r1->left();
01257     }
01258 }
01259 
01260 /*-
01261  *-----------------------------------------------------------------------
01262  * miSubtract --
01263  *      Subtract regS from regM and leave the result in regD.
01264  *      S stands for subtrahend, M for minuend and D for difference.
01265  *
01266  * Side Effects:
01267  *      regD is overwritten.
01268  *
01269  *-----------------------------------------------------------------------
01270  */
01271 
01272 static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
01273                            register QRegionPrivate &dest)
01274 {
01275    /* check for trivial reject */
01276     if (isEmpty(regM))
01277         return;
01278 
01279     if (isEmpty(regS) || !EXTENTCHECK(&regM->extents, &regS->extents)) {
01280         dest = *regM;
01281         return;
01282     }
01283 
01284 #ifdef QT_EXPERIMENTAL_REGIONS
01285     if (regS->contains(*regM)) {
01286         dest = QRegionPrivate();
01287         return;
01288     }
01289 
01290     if (EqualRegion(regM, regS)) {
01291         dest = QRegionPrivate();
01292         return;
01293     }
01294 #endif
01295 
01296     miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, 0);
01297 
01298     /*
01299      * Can't alter dest's extents before we call miRegionOp because
01300      * it might be one of the source regions and miRegionOp depends
01301      * on the extents of those regions being the unaltered. Besides, this
01302      * way there's no checking against rectangles that will be nuked
01303      * due to coalescing, so we have to examine fewer rectangles.
01304      */
01305     miSetExtents(dest);
01306 }
01307 
01308 static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
01309 {
01310     QRegionPrivate tra, trb;
01311 
01312     SubtractRegion(sra, srb, tra);
01313     SubtractRegion(srb, sra, trb);
01314     UnionRegion(&tra, &trb, dest);
01315 }
01316 
01317 /*
01318  *      Check to see if two regions are equal
01319  */
01320 static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
01321 {
01322     if (r1->numRects != r2->numRects) {
01323         return false;
01324     } else if (r1->numRects == 0) {
01325         return true;
01326     } else if (r1->extents != r2->extents) {
01327         return false;
01328     } else {
01329         const QRect *rr1 = r1->rects.constData();
01330         const QRect *rr2 = r2->rects.constData();
01331         for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
01332             if (*rr1 != *rr2)
01333                 return false;
01334         }
01335     }
01336 
01337     return true;
01338 }
01339 
01340 static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
01341 {
01342     int i;
01343 
01344     if (isEmpty(pRegion))
01345         return false;
01346     if (!pRegion->extents.contains(x, y))
01347         return false;
01348 #ifdef QT_EXPERIMENTAL_REGIONS
01349     if (pRegion->innerRect.contains(x, y))
01350         return true;
01351 #endif
01352     for (i = 0; i < pRegion->numRects; ++i) {
01353         if (pRegion->rects[i].contains(x, y))
01354             return true;
01355     }
01356     return false;
01357 }
01358 
01359 static bool RectInRegion(register QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
01360 {
01361     register const QRect *pbox;
01362     register const QRect *pboxEnd;
01363     QRect rect(rx, ry, rwidth, rheight);
01364     register QRect *prect = &rect;
01365     int partIn, partOut;
01366 
01367     if (!region || region->numRects == 0 || !EXTENTCHECK(&region->extents, prect))
01368         return RectangleOut;
01369 
01370     partOut = false;
01371     partIn = false;
01372 
01373     /* can stop when both partOut and partIn are true, or we reach prect->y2 */
01374     for (pbox = region->rects.constData(), pboxEnd = pbox + region->numRects;
01375          pbox < pboxEnd; ++pbox) {
01376         if (pbox->bottom() < ry)
01377            continue;
01378 
01379         if (pbox->top() > ry) {
01380            partOut = true;
01381            if (partIn || pbox->top() > prect->bottom())
01382               break;
01383            ry = pbox->top();
01384         }
01385 
01386         if (pbox->right() < rx)
01387            continue;            /* not far enough over yet */
01388 
01389         if (pbox->left() > rx) {
01390            partOut = true;      /* missed part of rectangle to left */
01391            if (partIn)
01392               break;
01393         }
01394 
01395         if (pbox->left() <= prect->right()) {
01396             partIn = true;      /* definitely overlap */
01397             if (partOut)
01398                break;
01399         }
01400 
01401         if (pbox->right() >= prect->right()) {
01402            ry = pbox->bottom() + 1;     /* finished with this band */
01403            if (ry > prect->bottom())
01404               break;
01405            rx = prect->left();  /* reset x out to left again */
01406         } else {
01407             /*
01408              * Because boxes in a band are maximal width, if the first box
01409              * to overlap the rectangle doesn't completely cover it in that
01410              * band, the rectangle must be partially out, since some of it
01411              * will be uncovered in that band. partIn will have been set true
01412              * by now...
01413              */
01414             break;
01415         }
01416     }
01417     return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
01418 }
01419 // END OF Region.c extract
01420 // START OF poly.h extract
01421 /* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
01422 /************************************************************************
01423 
01424 Copyright (c) 1987  X Consortium
01425 
01426 Permission is hereby granted, free of charge, to any person obtaining a copy
01427 of this software and associated documentation files (the "Software"), to deal
01428 in the Software without restriction, including without limitation the rights
01429 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
01430 copies of the Software, and to permit persons to whom the Software is
01431 furnished to do so, subject to the following conditions:
01432 
01433 The above copyright notice and this permission notice shall be included in
01434 all copies or substantial portions of the Software.
01435 
01436 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
01437 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
01438 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
01439 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
01440 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
01441 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
01442 
01443 Except as contained in this notice, the name of the X Consortium shall not be
01444 used in advertising or otherwise to promote the sale, use or other dealings
01445 in this Software without prior written authorization from the X Consortium.
01446 
01447 
01448 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
01449 
01450                         All Rights Reserved
01451 
01452 Permission to use, copy, modify, and distribute this software and its
01453 documentation for any purpose and without fee is hereby granted,
01454 provided that the above copyright notice appear in all copies and that
01455 both that copyright notice and this permission notice appear in
01456 supporting documentation, and that the name of Digital not be
01457 used in advertising or publicity pertaining to distribution of the
01458 software without specific, written prior permission.
01459 
01460 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
01461 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
01462 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
01463 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
01464 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
01465 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
01466 SOFTWARE.
01467 
01468 ************************************************************************/
01469 
01470 /*
01471  *     This file contains a few macros to help track
01472  *     the edge of a filled object.  The object is assumed
01473  *     to be filled in scanline order, and thus the
01474  *     algorithm used is an extension of Bresenham's line
01475  *     drawing algorithm which assumes that y is always the
01476  *     major axis.
01477  *     Since these pieces of code are the same for any filled shape,
01478  *     it is more convenient to gather the library in one
01479  *     place, but since these pieces of code are also in
01480  *     the inner loops of output primitives, procedure call
01481  *     overhead is out of the question.
01482  *     See the author for a derivation if needed.
01483  */
01484 
01485 
01486 /*
01487  *  In scan converting polygons, we want to choose those pixels
01488  *  which are inside the polygon.  Thus, we add .5 to the starting
01489  *  x coordinate for both left and right edges.  Now we choose the
01490  *  first pixel which is inside the pgon for the left edge and the
01491  *  first pixel which is outside the pgon for the right edge.
01492  *  Draw the left pixel, but not the right.
01493  *
01494  *  How to add .5 to the starting x coordinate:
01495  *      If the edge is moving to the right, then subtract dy from the
01496  *  error term from the general form of the algorithm.
01497  *      If the edge is moving to the left, then add dy to the error term.
01498  *
01499  *  The reason for the difference between edges moving to the left
01500  *  and edges moving to the right is simple:  If an edge is moving
01501  *  to the right, then we want the algorithm to flip immediately.
01502  *  If it is moving to the left, then we don't want it to flip until
01503  *  we traverse an entire pixel.
01504  */
01505 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
01506     int dx;      /* local storage */ \
01507 \
01508     /* \
01509      *  if the edge is horizontal, then it is ignored \
01510      *  and assumed not to be processed.  Otherwise, do this stuff. \
01511      */ \
01512     if ((dy) != 0) { \
01513         xStart = (x1); \
01514         dx = (x2) - xStart; \
01515         if (dx < 0) { \
01516             m = dx / (dy); \
01517             m1 = m - 1; \
01518             incr1 = -2 * dx + 2 * (dy) * m1; \
01519             incr2 = -2 * dx + 2 * (dy) * m; \
01520             d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
01521         } else { \
01522             m = dx / (dy); \
01523             m1 = m + 1; \
01524             incr1 = 2 * dx - 2 * (dy) * m1; \
01525             incr2 = 2 * dx - 2 * (dy) * m; \
01526             d = -2 * m * (dy) + 2 * dx; \
01527         } \
01528     } \
01529 }
01530 
01531 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
01532     if (m1 > 0) { \
01533         if (d > 0) { \
01534             minval += m1; \
01535             d += incr1; \
01536         } \
01537         else { \
01538             minval += m; \
01539             d += incr2; \
01540         } \
01541     } else {\
01542         if (d >= 0) { \
01543             minval += m1; \
01544             d += incr1; \
01545         } \
01546         else { \
01547             minval += m; \
01548             d += incr2; \
01549         } \
01550     } \
01551 }
01552 
01553 
01554 /*
01555  *     This structure contains all of the information needed
01556  *     to run the bresenham algorithm.
01557  *     The variables may be hardcoded into the declarations
01558  *     instead of using this structure to make use of
01559  *     register declarations.
01560  */
01561 typedef struct {
01562     int minor_axis;     /* minor axis        */
01563     int d;              /* decision variable */
01564     int m, m1;          /* slope and slope+1 */
01565     int incr1, incr2;   /* error increments */
01566 } BRESINFO;
01567 
01568 
01569 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
01570         BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
01571                      bres.m, bres.m1, bres.incr1, bres.incr2)
01572 
01573 #define BRESINCRPGONSTRUCT(bres) \
01574         BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
01575 
01576 
01577 
01578 /*
01579  *     These are the data structures needed to scan
01580  *     convert regions.  Two different scan conversion
01581  *     methods are available -- the even-odd method, and
01582  *     the winding number method.
01583  *     The even-odd rule states that a point is inside
01584  *     the polygon if a ray drawn from that point in any
01585  *     direction will pass through an odd number of
01586  *     path segments.
01587  *     By the winding number rule, a point is decided
01588  *     to be inside the polygon if a ray drawn from that
01589  *     point in any direction passes through a different
01590  *     number of clockwise and counter-clockwise path
01591  *     segments.
01592  *
01593  *     These data structures are adapted somewhat from
01594  *     the algorithm in (Foley/Van Dam) for scan converting
01595  *     polygons.
01596  *     The basic algorithm is to start at the top (smallest y)
01597  *     of the polygon, stepping down to the bottom of
01598  *     the polygon by incrementing the y coordinate.  We
01599  *     keep a list of edges which the current scanline crosses,
01600  *     sorted by x.  This list is called the Active Edge Table (AET)
01601  *     As we change the y-coordinate, we update each entry in
01602  *     in the active edge table to reflect the edges new xcoord.
01603  *     This list must be sorted at each scanline in case
01604  *     two edges intersect.
01605  *     We also keep a data structure known as the Edge Table (ET),
01606  *     which keeps track of all the edges which the current
01607  *     scanline has not yet reached.  The ET is basically a
01608  *     list of ScanLineList structures containing a list of
01609  *     edges which are entered at a given scanline.  There is one
01610  *     ScanLineList per scanline at which an edge is entered.
01611  *     When we enter a new edge, we move it from the ET to the AET.
01612  *
01613  *     From the AET, we can implement the even-odd rule as in
01614  *     (Foley/Van Dam).
01615  *     The winding number rule is a little trickier.  We also
01616  *     keep the EdgeTableEntries in the AET linked by the
01617  *     nextWETE (winding EdgeTableEntry) link.  This allows
01618  *     the edges to be linked just as before for updating
01619  *     purposes, but only uses the edges linked by the nextWETE
01620  *     link as edges representing spans of the polygon to
01621  *     drawn (as with the even-odd rule).
01622  */
01623 
01624 /*
01625  * for the winding number rule
01626  */
01627 #define CLOCKWISE          1
01628 #define COUNTERCLOCKWISE  -1
01629 
01630 typedef struct _EdgeTableEntry {
01631      int ymax;             /* ycoord at which we exit this edge. */
01632      BRESINFO bres;        /* Bresenham info to run the edge     */
01633      struct _EdgeTableEntry *next;       /* next in the list     */
01634      struct _EdgeTableEntry *back;       /* for insertion sort   */
01635      struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
01636      int ClockWise;        /* flag for winding number rule       */
01637 } EdgeTableEntry;
01638 
01639 
01640 typedef struct _ScanLineList{
01641      int scanline;              /* the scanline represented */
01642      EdgeTableEntry *edgelist;  /* header node              */
01643      struct _ScanLineList *next;  /* next in the list       */
01644 } ScanLineList;
01645 
01646 
01647 typedef struct {
01648      int ymax;                 /* ymax for the polygon     */
01649      int ymin;                 /* ymin for the polygon     */
01650      ScanLineList scanlines;   /* header node              */
01651 } EdgeTable;
01652 
01653 
01654 /*
01655  * Here is a struct to help with storage allocation
01656  * so we can allocate a big chunk at a time, and then take
01657  * pieces from this heap when we need to.
01658  */
01659 #define SLLSPERBLOCK 25
01660 
01661 typedef struct _ScanLineListBlock {
01662      ScanLineList SLLs[SLLSPERBLOCK];
01663      struct _ScanLineListBlock *next;
01664 } ScanLineListBlock;
01665 
01666 
01667 
01668 /*
01669  *
01670  *     a few macros for the inner loops of the fill code where
01671  *     performance considerations don't allow a procedure call.
01672  *
01673  *     Evaluate the given edge at the given scanline.
01674  *     If the edge has expired, then we leave it and fix up
01675  *     the active edge table; otherwise, we increment the
01676  *     x value to be ready for the next scanline.
01677  *     The winding number rule is in effect, so we must notify
01678  *     the caller when the edge has been removed so he
01679  *     can reorder the Winding Active Edge Table.
01680  */
01681 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
01682    if (pAET->ymax == y) {          /* leaving this edge */ \
01683       pPrevAET->next = pAET->next; \
01684       pAET = pPrevAET->next; \
01685       fixWAET = 1; \
01686       if (pAET) \
01687          pAET->back = pPrevAET; \
01688    } \
01689    else { \
01690       BRESINCRPGONSTRUCT(pAET->bres) \
01691       pPrevAET = pAET; \
01692       pAET = pAET->next; \
01693    } \
01694 }
01695 
01696 
01697 /*
01698  *     Evaluate the given edge at the given scanline.
01699  *     If the edge has expired, then we leave it and fix up
01700  *     the active edge table; otherwise, we increment the
01701  *     x value to be ready for the next scanline.
01702  *     The even-odd rule is in effect.
01703  */
01704 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
01705    if (pAET->ymax == y) {          /* leaving this edge */ \
01706       pPrevAET->next = pAET->next; \
01707       pAET = pPrevAET->next; \
01708       if (pAET) \
01709          pAET->back = pPrevAET; \
01710    } \
01711    else { \
01712       BRESINCRPGONSTRUCT(pAET->bres) \
01713       pPrevAET = pAET; \
01714       pAET = pAET->next; \
01715    } \
01716 }
01717 // END OF poly.h extract
01718 // START OF PolyReg.c extract
01719 /* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
01720 /************************************************************************
01721 
01722 Copyright (c) 1987  X Consortium
01723 
01724 Permission is hereby granted, free of charge, to any person obtaining a copy
01725 of this software and associated documentation files (the "Software"), to deal
01726 in the Software without restriction, including without limitation the rights
01727 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
01728 copies of the Software, and to permit persons to whom the Software is
01729 furnished to do so, subject to the following conditions:
01730 
01731 The above copyright notice and this permission notice shall be included in
01732 all copies or substantial portions of the Software.
01733 
01734 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
01735 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
01736 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
01737 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
01738 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
01739 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
01740 
01741 Except as contained in this notice, the name of the X Consortium shall not be
01742 used in advertising or otherwise to promote the sale, use or other dealings
01743 in this Software without prior written authorization from the X Consortium.
01744 
01745 
01746 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
01747 
01748                         All Rights Reserved
01749 
01750 Permission to use, copy, modify, and distribute this software and its
01751 documentation for any purpose and without fee is hereby granted,
01752 provided that the above copyright notice appear in all copies and that
01753 both that copyright notice and this permission notice appear in
01754 supporting documentation, and that the name of Digital not be
01755 used in advertising or publicity pertaining to distribution of the
01756 software without specific, written prior permission.
01757 
01758 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
01759 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
01760 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
01761 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
01762 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
01763 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
01764 SOFTWARE.
01765 
01766 ************************************************************************/
01767 /* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
01768 
01769 #define LARGE_COORDINATE 1000000
01770 #define SMALL_COORDINATE -LARGE_COORDINATE
01771 
01772 /*
01773  *     InsertEdgeInET
01774  *
01775  *     Insert the given edge into the edge table.
01776  *     First we must find the correct bucket in the
01777  *     Edge table, then find the right slot in the
01778  *     bucket.  Finally, we can insert it.
01779  *
01780  */
01781 static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
01782                            ScanLineListBlock **SLLBlock, int *iSLLBlock)
01783 {
01784     register EdgeTableEntry *start, *prev;
01785     register ScanLineList *pSLL, *pPrevSLL;
01786     ScanLineListBlock *tmpSLLBlock;
01787 
01788     /*
01789      * find the right bucket to put the edge into
01790      */
01791     pPrevSLL = &ET->scanlines;
01792     pSLL = pPrevSLL->next;
01793     while (pSLL && (pSLL->scanline < scanline)) {
01794         pPrevSLL = pSLL;
01795         pSLL = pSLL->next;
01796     }
01797 
01798     /*
01799      * reassign pSLL (pointer to ScanLineList) if necessary
01800      */
01801     if ((!pSLL) || (pSLL->scanline > scanline)) {
01802         if (*iSLLBlock > SLLSPERBLOCK-1)
01803         {
01804             tmpSLLBlock =
01805                   (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
01806             (*SLLBlock)->next = tmpSLLBlock;
01807             tmpSLLBlock->next = (ScanLineListBlock *)NULL;
01808             *SLLBlock = tmpSLLBlock;
01809             *iSLLBlock = 0;
01810         }
01811         pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
01812 
01813         pSLL->next = pPrevSLL->next;
01814         pSLL->edgelist = (EdgeTableEntry *)NULL;
01815         pPrevSLL->next = pSLL;
01816     }
01817     pSLL->scanline = scanline;
01818 
01819     /*
01820      * now insert the edge in the right bucket
01821      */
01822     prev = 0;
01823     start = pSLL->edgelist;
01824     while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
01825         prev = start;
01826         start = start->next;
01827     }
01828     ETE->next = start;
01829 
01830     if (prev)
01831         prev->next = ETE;
01832     else
01833         pSLL->edgelist = ETE;
01834 }
01835 
01836 /*
01837  *     CreateEdgeTable
01838  *
01839  *     This routine creates the edge table for
01840  *     scan converting polygons.
01841  *     The Edge Table (ET) looks like:
01842  *
01843  *    EdgeTable
01844  *     --------
01845  *    |  ymax  |        ScanLineLists
01846  *    |scanline|-->------------>-------------->...
01847  *     --------   |scanline|   |scanline|
01848  *                |edgelist|   |edgelist|
01849  *                ---------    ---------
01850  *                    |             |
01851  *                    |             |
01852  *                    V             V
01853  *              list of ETEs   list of ETEs
01854  *
01855  *     where ETE is an EdgeTableEntry data structure,
01856  *     and there is one ScanLineList per scanline at
01857  *     which an edge is initially entered.
01858  *
01859  */
01860 
01861 static void CreateETandAET(register int count, register const QPoint *pts,
01862                            EdgeTable *ET, EdgeTableEntry *AET, register EdgeTableEntry *pETEs,
01863                            ScanLineListBlock *pSLLBlock)
01864 {
01865     register const QPoint *top,
01866                           *bottom,
01867                           *PrevPt,
01868                           *CurrPt;
01869     int iSLLBlock = 0;
01870     int dy;
01871 
01872     if (count < 2)
01873         return;
01874 
01875     /*
01876      *  initialize the Active Edge Table
01877      */
01878     AET->next = 0;
01879     AET->back = 0;
01880     AET->nextWETE = 0;
01881     AET->bres.minor_axis = SMALL_COORDINATE;
01882 
01883     /*
01884      *  initialize the Edge Table.
01885      */
01886     ET->scanlines.next = 0;
01887     ET->ymax = SMALL_COORDINATE;
01888     ET->ymin = LARGE_COORDINATE;
01889     pSLLBlock->next = 0;
01890 
01891     PrevPt = &pts[count - 1];
01892 
01893     /*
01894      *  for each vertex in the array of points.
01895      *  In this loop we are dealing with two vertices at
01896      *  a time -- these make up one edge of the polygon.
01897      */
01898     while (count--) {
01899         CurrPt = pts++;
01900 
01901         /*
01902          *  find out which point is above and which is below.
01903          */
01904         if (PrevPt->y() > CurrPt->y()) {
01905             bottom = PrevPt;
01906             top = CurrPt;
01907             pETEs->ClockWise = 0;
01908         } else {
01909             bottom = CurrPt;
01910             top = PrevPt;
01911             pETEs->ClockWise = 1;
01912         }
01913 
01914         /*
01915          * don't add horizontal edges to the Edge table.
01916          */
01917         if (bottom->y() != top->y()) {
01918             pETEs->ymax = bottom->y() - 1;  /* -1 so we don't get last scanline */
01919 
01920             /*
01921              *  initialize integer edge algorithm
01922              */
01923             dy = bottom->y() - top->y();
01924             BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
01925 
01926             InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
01927 
01928             if (PrevPt->y() > ET->ymax)
01929                 ET->ymax = PrevPt->y();
01930             if (PrevPt->y() < ET->ymin)
01931                 ET->ymin = PrevPt->y();
01932             ++pETEs;
01933         }
01934 
01935         PrevPt = CurrPt;
01936     }
01937 }
01938 
01939 /*
01940  *     loadAET
01941  *
01942  *     This routine moves EdgeTableEntries from the
01943  *     EdgeTable into the Active Edge Table,
01944  *     leaving them sorted by smaller x coordinate.
01945  *
01946  */
01947 
01948 static void loadAET(register EdgeTableEntry *AET, register EdgeTableEntry *ETEs)
01949 {
01950     register EdgeTableEntry *pPrevAET;
01951     register EdgeTableEntry *tmp;
01952 
01953     pPrevAET = AET;
01954     AET = AET->next;
01955     while (ETEs) {
01956         while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
01957             pPrevAET = AET;
01958             AET = AET->next;
01959         }
01960         tmp = ETEs->next;
01961         ETEs->next = AET;
01962         if (AET)
01963             AET->back = ETEs;
01964         ETEs->back = pPrevAET;
01965         pPrevAET->next = ETEs;
01966         pPrevAET = ETEs;
01967 
01968         ETEs = tmp;
01969     }
01970 }
01971 
01972 /*
01973  *     computeWAET
01974  *
01975  *     This routine links the AET by the
01976  *     nextWETE (winding EdgeTableEntry) link for
01977  *     use by the winding number rule.  The final
01978  *     Active Edge Table (AET) might look something
01979  *     like:
01980  *
01981  *     AET
01982  *     ----------  ---------   ---------
01983  *     |ymax    |  |ymax    |  |ymax    |
01984  *     | ...    |  |...     |  |...     |
01985  *     |next    |->|next    |->|next    |->...
01986  *     |nextWETE|  |nextWETE|  |nextWETE|
01987  *     ---------   ---------   ^--------
01988  *         |                   |       |
01989  *         V------------------->       V---> ...
01990  *
01991  */
01992 static void computeWAET(register EdgeTableEntry *AET)
01993 {
01994     register EdgeTableEntry *pWETE;
01995     register int inside = 1;
01996     register int isInside = 0;
01997 
01998     AET->nextWETE = 0;
01999     pWETE = AET;
02000     AET = AET->next;
02001     while (AET) {
02002         if (AET->ClockWise)
02003             ++isInside;
02004         else
02005             --isInside;
02006 
02007         if (!inside && !isInside || inside && isInside) {
02008             pWETE->nextWETE = AET;
02009             pWETE = AET;
02010             inside = !inside;
02011         }
02012         AET = AET->next;
02013     }
02014     pWETE->nextWETE = 0;
02015 }
02016 
02017 /*
02018  *     InsertionSort
02019  *
02020  *     Just a simple insertion sort using
02021  *     pointers and back pointers to sort the Active
02022  *     Edge Table.
02023  *
02024  */
02025 
02026 static int InsertionSort(register EdgeTableEntry *AET)
02027 {
02028     register EdgeTableEntry *pETEchase;
02029     register EdgeTableEntry *pETEinsert;
02030     register EdgeTableEntry *pETEchaseBackTMP;
02031     register int changed = 0;
02032 
02033     AET = AET->next;
02034     while (AET) {
02035         pETEinsert = AET;
02036         pETEchase = AET;
02037         while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
02038             pETEchase = pETEchase->back;
02039 
02040         AET = AET->next;
02041         if (pETEchase != pETEinsert) {
02042             pETEchaseBackTMP = pETEchase->back;
02043             pETEinsert->back->next = AET;
02044             if (AET)
02045                 AET->back = pETEinsert->back;
02046             pETEinsert->next = pETEchase;
02047             pETEchase->back->next = pETEinsert;
02048             pETEchase->back = pETEinsert;
02049             pETEinsert->back = pETEchaseBackTMP;
02050             changed = 1;
02051         }
02052     }
02053     return changed;
02054 }
02055 
02056 /*
02057  *     Clean up our act.
02058  */
02059 static void FreeStorage(register ScanLineListBlock *pSLLBlock)
02060 {
02061     register ScanLineListBlock *tmpSLLBlock;
02062 
02063     while (pSLLBlock) {
02064         tmpSLLBlock = pSLLBlock->next;
02065         free(pSLLBlock);
02066         pSLLBlock = tmpSLLBlock;
02067     }
02068 }
02069 
02070 /*
02071  *     Create an array of rectangles from a list of points.
02072  *     If indeed these things (POINTS, RECTS) are the same,
02073  *     then this proc is still needed, because it allocates
02074  *     storage for the array, which was allocated on the
02075  *     stack by the calling procedure.
02076  *
02077  */
02078 static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock,
02079                        POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
02080 {
02081     register QRect *rects;
02082     register QPoint *pts;
02083     register POINTBLOCK *CurPtBlock;
02084     register int i;
02085     register QRect *extents;
02086     register int numRects;
02087 
02088     extents = &reg->extents;
02089     numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
02090 
02091     reg->rects.resize(numRects);
02092 
02093     CurPtBlock = FirstPtBlock;
02094     rects = reg->rects.data() - 1;
02095     numRects = 0;
02096     extents->setLeft(INT_MAX);
02097     extents->setRight(INT_MIN);
02098 #ifdef QT_EXPERIMENTAL_REGIONS
02099     reg->innerArea = -1;
02100 #endif
02101 
02102     for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
02103         /* the loop uses 2 points per iteration */
02104         i = NUMPTSTOBUFFER >> 1;
02105         if (!numFullPtBlocks)
02106             i = iCurPtBlock >> 1;
02107         if(i) {
02108             for (pts = CurPtBlock->pts; i--; pts += 2) {
02109                 if (pts->x() == pts[1].x())
02110                     continue;
02111                 if (numRects && pts->x() == rects->left() && pts->y() == rects->bottom() + 1
02112                     && pts[1].x() == rects->right()+1 && (numRects == 1 || rects[-1].top() != rects->top())
02113                                                           && (i && pts[2].y() > pts[1].y())) {
02114                         rects->setBottom(pts[1].y());
02115 #ifdef QT_EXPERIMENTAL_REGIONS
02116                         reg->updateInnerRect(*rects);
02117 #endif
02118                         continue;
02119                 }
02120                 ++numRects;
02121                 ++rects;
02122                 rects->setCoords(pts->x(), pts->y(), pts[1].x() - 1, pts[1].y());
02123                 if (rects->left() < extents->left())
02124                     extents->setLeft(rects->left());
02125                 if (rects->right() > extents->right())
02126                     extents->setRight(rects->right());
02127 #ifdef QT_EXPERIMENTAL_REGIONS
02128                 reg->updateInnerRect(*rects);
02129 #endif
02130             }
02131         }
02132         CurPtBlock = CurPtBlock->next;
02133     }
02134 
02135     if (numRects) {
02136         extents->setTop(reg->rects[0].top());
02137         extents->setBottom(rects->bottom());
02138     } else {
02139         extents->setCoords(0, 0, 0, 0);
02140     }
02141     reg->numRects = numRects;
02142 }
02143 
02144 /*
02145  *     polytoregion
02146  *
02147  *     Scan converts a polygon by returning a run-length
02148  *     encoding of the resultant bitmap -- the run-length
02149  *     encoding is in the form of an array of rectangles.
02150  */
02151 static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
02152     //Point     *Pts;                /* the pts                 */
02153     //int       Count;                 /* number of pts           */
02154     //int       rule;                        /* winding rule */
02155 {
02156     QRegionPrivate *region;
02157     register EdgeTableEntry *pAET;   /* Active Edge Table       */
02158     register int y;                  /* current scanline        */
02159     register int iPts = 0;           /* number of pts in buffer */
02160     register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
02161     register ScanLineList *pSLL;     /* current scanLineList    */
02162     register QPoint *pts;             /* output buffer           */
02163     EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
02164     EdgeTable ET;                    /* header node for ET      */
02165     EdgeTableEntry AET;              /* header node for AET     */
02166     EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
02167     ScanLineListBlock SLLBlock;      /* header for scanlinelist */
02168     int fixWAET = false;
02169     POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
02170     POINTBLOCK *tmpPtBlock;
02171     int numFullPtBlocks = 0;
02172 
02173     if (!(region = new QRegionPrivate))
02174         return 0;
02175 
02176     /* special case a rectangle */
02177     if (((Count == 4) ||
02178          ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
02179          && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
02180                && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
02181                && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
02182                && (Pts[3].y() == Pts[0].y())))) {
02183         int x = qMin(Pts[0].x(), Pts[2].x());
02184         region->extents.setLeft(x);
02185         int y = qMin(Pts[0].y(), Pts[2].y());
02186         region->extents.setTop(y);
02187         region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
02188         region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
02189         if ((region->extents.left() <= region->extents.right()) &&
02190             (region->extents.top() <= region->extents.bottom())) {
02191             region->numRects = 1;
02192             region->rects.resize(1);
02193             region->rects[0] = region->extents;
02194 #ifdef QT_EXPERIMENTAL_REGIONS
02195             region->innerRect = region->extents;
02196             region->innerArea = region->innerRect.width() * region->innerRect.height();
02197 #endif
02198         }
02199         return region;
02200     }
02201 
02202     if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count))))
02203         return 0;
02204 
02205     pts = FirstPtBlock.pts;
02206     CreateETandAET(Count, Pts, &ET, &AET, pETEs, &SLLBlock);
02207     pSLL = ET.scanlines.next;
02208     curPtBlock = &FirstPtBlock;
02209 
02210     if (rule == EvenOddRule) {
02211         /*
02212          *  for each scanline
02213          */
02214         for (y = ET.ymin; y < ET.ymax; ++y) {
02215             /*
02216              *  Add a new edge to the active edge table when we
02217              *  get to the next edge.
02218              */
02219             if (pSLL && y == pSLL->scanline) {
02220                 loadAET(&AET, pSLL->edgelist);
02221                 pSLL = pSLL->next;
02222             }
02223             pPrevAET = &AET;
02224             pAET = AET.next;
02225 
02226             /*
02227              *  for each active edge
02228              */
02229             while (pAET) {
02230                 pts->setX(pAET->bres.minor_axis);
02231                 pts->setY(y);
02232                 ++pts;
02233                 ++iPts;
02234 
02235                 /*
02236                  *  send out the buffer
02237                  */
02238                 if (iPts == NUMPTSTOBUFFER) {
02239                     tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
02240                     curPtBlock->next = tmpPtBlock;
02241                     curPtBlock = tmpPtBlock;
02242                     pts = curPtBlock->pts;
02243                     ++numFullPtBlocks;
02244                     iPts = 0;
02245                 }
02246                 EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
02247             }
02248             InsertionSort(&AET);
02249         }
02250     } else {
02251         /*
02252          *  for each scanline
02253          */
02254         for (y = ET.ymin; y < ET.ymax; ++y) {
02255             /*
02256              *  Add a new edge to the active edge table when we
02257              *  get to the next edge.
02258              */
02259             if (pSLL && y == pSLL->scanline) {
02260                 loadAET(&AET, pSLL->edgelist);
02261                 computeWAET(&AET);
02262                 pSLL = pSLL->next;
02263             }
02264             pPrevAET = &AET;
02265             pAET = AET.next;
02266             pWETE = pAET;
02267 
02268             /*
02269              *  for each active edge
02270              */
02271             while (pAET) {
02272                 /*
02273                  *  add to the buffer only those edges that
02274                  *  are in the Winding active edge table.
02275                  */
02276                 if (pWETE == pAET) {
02277                     pts->setX(pAET->bres.minor_axis);
02278                     pts->setY(y);
02279                     ++pts;
02280                     ++iPts;
02281 
02282                     /*
02283                      *  send out the buffer
02284                      */
02285                     if (iPts == NUMPTSTOBUFFER) {
02286                         tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
02287                         curPtBlock->next = tmpPtBlock;
02288                         curPtBlock = tmpPtBlock;
02289                         pts = curPtBlock->pts;
02290                         ++numFullPtBlocks;
02291                         iPts = 0;
02292                     }
02293                     pWETE = pWETE->nextWETE;
02294                 }
02295                 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
02296             }
02297 
02298             /*
02299              *  recompute the winding active edge table if
02300              *  we just resorted or have exited an edge.
02301              */
02302             if (InsertionSort(&AET) || fixWAET) {
02303                 computeWAET(&AET);
02304                 fixWAET = false;
02305             }
02306         }
02307     }
02308     FreeStorage(SLLBlock.next);
02309     PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
02310     for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
02311         tmpPtBlock = curPtBlock->next;
02312         free(curPtBlock);
02313         curPtBlock = tmpPtBlock;
02314     }
02315     free(pETEs);
02316     return region;
02317 }
02318 // END OF PolyReg.c extract
02319 
02320 QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
02321 {
02322     QImage image = bitmap.toImage();
02323 
02324     QRegionPrivate *region = new QRegionPrivate;
02325     QRect xr;
02326 
02327 #define AddSpan \
02328         { \
02329             xr.setCoords(prev1, y, x-1, y); \
02330             UnionRectWithRegion(&xr, region, *region); \
02331         }
02332 
02333     const uchar zero = 0;
02334     bool little = image.format() == QImage::Format_MonoLSB;
02335 
02336     int x,
02337         y;
02338     for (y = 0; y < image.height(); ++y) {
02339         uchar *line = image.scanLine(y);
02340         int w = image.width();
02341         uchar all = zero;
02342         int prev1 = -1;
02343         for (x = 0; x < w;) {
02344             uchar byte = line[x / 8];
02345             if (x > w - 8 || byte!=all) {
02346                 if (little) {
02347                     for (int b = 8; b > 0 && x < w; --b) {
02348                         if (!(byte & 0x01) == !all) {
02349                             // More of the same
02350                         } else {
02351                             // A change.
02352                             if (all!=zero) {
02353                                 AddSpan
02354                                 all = zero;
02355                             } else {
02356                                 prev1 = x;
02357                                 all = ~zero;
02358                             }
02359                         }
02360                         byte >>= 1;
02361                         ++x;
02362                     }
02363                 } else {
02364                     for (int b = 8; b > 0 && x < w; --b) {
02365                         if (!(byte & 0x80) == !all) {
02366                             // More of the same
02367                         } else {
02368                             // A change.
02369                             if (all != zero) {
02370                                 AddSpan
02371                                 all = zero;
02372                             } else {
02373                                 prev1 = x;
02374                                 all = ~zero;
02375                             }
02376                         }
02377                         byte <<= 1;
02378                         ++x;
02379                     }
02380                 }
02381             } else {
02382                 x += 8;
02383             }
02384         }
02385         if (all != zero) {
02386             AddSpan
02387         }
02388     }
02389 #undef AddSpan
02390 
02391     return region;
02392 }
02393 
02400 QRegion::QRegion()
02401     : d(&shared_empty)
02402 {
02403     d->ref.ref();
02404 }
02405 
02416 QRegion::QRegion(const QRect &r, RegionType t)
02417 {
02418     if (r.isEmpty()) {
02419         d = &shared_empty;
02420         d->ref.ref();
02421     } else {
02422         d = new QRegionData;
02423         d->ref.init(1);
02424 #if defined(Q_WS_X11)
02425         d->rgn = 0;
02426         d->xrectangles = 0;
02427 #elif defined(Q_WS_MAC)
02428         d->rgn = 0;
02429 #endif
02430         if (t == Rectangle) {
02431             d->qt_rgn = new QRegionPrivate(r);
02432         } else if (t == Ellipse) {
02433             QPainterPath path;
02434             path.addEllipse(r.x(), r.y(), r.width(), r.height());
02435             QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
02436             d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
02437         }
02438     }
02439 }
02440 
02453 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
02454 {
02455     if (a.count() > 2) {
02456         d =  new QRegionData;
02457         d->ref.init(1);
02458 #if defined(Q_WS_X11)
02459         d->rgn = 0;
02460         d->xrectangles = 0;
02461 #elif defined(Q_WS_MAC)
02462         d->rgn = 0;
02463 #endif
02464         d->qt_rgn = PolygonRegion(a.constData(), a.size(),
02465                                   fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
02466     } else {
02467         d = &shared_empty;
02468         d->ref.ref();
02469     }
02470 }
02471 
02472 
02477 QRegion::QRegion(const QRegion &r)
02478 {
02479     d = r.d;
02480     d->ref.ref();
02481 }
02482 
02483 
02494 QRegion::QRegion(const QBitmap &bm)
02495 {
02496     if (bm.isNull()) {
02497         d = &shared_empty;
02498         d->ref.ref();
02499     } else {
02500         d = new QRegionData;
02501         d->ref.init(1);
02502 #if defined(Q_WS_X11)
02503         d->rgn = 0;
02504         d->xrectangles = 0;
02505 #elif defined(Q_WS_MAC)
02506         d->rgn = 0;
02507 #endif
02508         d->qt_rgn = qt_bitmapToRegion(bm);
02509     }
02510 }
02511 
02512 void QRegion::cleanUp(QRegion::QRegionData *x)
02513 {
02514     delete x->qt_rgn;
02515 #if defined(Q_WS_X11)
02516     if (x->rgn)
02517         XDestroyRegion(x->rgn);
02518     if (x->xrectangles)
02519         free(x->xrectangles);
02520 #elif defined(Q_WS_MAC)
02521     if (x->rgn)
02522         qt_mac_dispose_rgn(x->rgn);
02523 #endif
02524     delete x;
02525 }
02526 
02531 QRegion::~QRegion()
02532 {
02533     if (!d->ref.deref())
02534         cleanUp(d);
02535 }
02536 
02537 
02542 QRegion &QRegion::operator=(const QRegion &r)
02543 {
02544     QRegionData *x = r.d;
02545     x->ref.ref();
02546     x = qAtomicSetPtr(&d, x);
02547     if (!x->ref.deref())
02548         cleanUp(x);
02549     return *this;
02550 }
02551 
02552 
02557 QRegion QRegion::copy() const
02558 {
02559     QRegion r;
02560     QRegionData *x = new QRegionData;
02561     x->ref.init(1);
02562 #if defined(Q_WS_X11)
02563     x->rgn = 0;
02564     x->xrectangles = 0;
02565 #elif defined(Q_WS_MAC)
02566     x->rgn = 0;
02567 #endif
02568     if (d->qt_rgn)
02569         x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
02570     else
02571         x->qt_rgn = new QRegionPrivate;
02572     x = qAtomicSetPtr(&r.d, x);
02573     if (!x->ref.deref())
02574         cleanUp(x);
02575     return r;
02576 }
02577 
02603 bool QRegion::isEmpty() const
02604 {
02605     return d == &shared_empty || d->qt_rgn->numRects == 0;
02606 }
02607 
02608 
02614 bool QRegion::contains(const QPoint &p) const
02615 {
02616     return PointInRegion(d->qt_rgn, p.x(), p.y());
02617 }
02618 
02626 bool QRegion::contains(const QRect &r) const
02627 {
02628     return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
02629 }
02630 
02631 
02632 
02638 void QRegion::translate(int dx, int dy)
02639 {
02640     detach();
02641     OffsetRegion(*d->qt_rgn, dx, dy);
02642 #if defined(Q_WS_X11)
02643     if (d->xrectangles) {
02644         free(d->xrectangles);
02645         d->xrectangles = 0;
02646     }
02647 #elif defined(Q_WS_MAC)
02648     if(d->rgn) {
02649         qt_mac_dispose_rgn(d->rgn);
02650         d->rgn = 0;
02651     }
02652 #endif
02653 }
02654 
02675 QRegion QRegion::unite(const QRegion &r) const
02676 {
02677     QRegion result;
02678     result.detach();
02679     UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
02680     return result;
02681 }
02682 
02683 #ifdef QT_EXPERIMENTAL_REGIONS
02684 QRegion& QRegion::operator+=(const QRegion &r)
02685 {
02686     if (isEmpty())
02687         return *this = r;
02688     if (r.isEmpty())
02689         return *this;
02690 
02691     if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
02692         detach();
02693         d->qt_rgn->append(r.d->qt_rgn);
02694         return *this;
02695     }
02696 
02697     return *this = unite(r);
02698 }
02699 #endif
02700 
02719 QRegion QRegion::intersect(const QRegion &r) const
02720 {
02721     QRegion result;
02722     if (::isEmpty(d->qt_rgn) || ::isEmpty(r.d->qt_rgn)
02723         || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
02724         return result;
02725 
02726 #ifdef QT_EXPERIMENTAL_REGIONS
02727     /* this is fully contained in r */
02728     if (r.d->qt_rgn->contains(*d->qt_rgn))
02729         return *this;
02730 
02731     /* r is fully contained in this */
02732     if (d->qt_rgn->contains(*r.d->qt_rgn))
02733         return r;
02734 #endif
02735 
02736     result.detach();
02737     miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, 0, 0);
02738 
02739     /*
02740      * Can't alter dest's extents before we call miRegionOp because
02741      * it might be one of the source regions and miRegionOp depends
02742      * on the extents of those regions being the same. Besides, this
02743      * way there's no checking against rectangles that will be nuked
02744      * due to coalescing, so we have to examine fewer rectangles.
02745      */
02746     miSetExtents(*result.d->qt_rgn);
02747     return result;
02748 }
02749 
02771 QRegion QRegion::subtract(const QRegion &r) const
02772 {
02773     QRegion result;
02774     result.detach();
02775     SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
02776     return result;
02777 }
02778 
02800 QRegion QRegion::eor(const QRegion &r) const
02801 {
02802     QRegion result;
02803     result.detach();
02804     XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
02805     return result;
02806 }
02807 
02813 QRect QRegion::boundingRect() const
02814 {
02815     if (isEmpty())
02816         return QRect();
02817     return d->qt_rgn->extents;
02818 }
02819 
02820 #ifdef QT_EXPERIMENTAL_REGIONS
02821 
02828 bool qt_region_strictContains(const QRegion &region, const QRect &rect)
02829 {
02830     if (region.isEmpty() || rect.isNull())
02831         return false;
02832 
02833 #if 0 // TEST_INNERRECT
02834     static bool guard = false;
02835     if (guard)
02836         return QRect();
02837     guard = true;
02838     QRegion inner = region.d->qt_rgn->innerRect;
02839     Q_ASSERT((inner - region).isEmpty());
02840     guard = false;
02841 
02842     int maxArea = 0;
02843     for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
02844         const QRect r = region.d->qt_rgn->rects.at(i);
02845         if (r.width() * r.height() > maxArea)
02846             maxArea = r.width() * r.height();
02847     }
02848 
02849     if (maxArea > region.d->qt_rgn->innerArea) {
02850         qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
02851     }
02852     Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
02853 #endif
02854 
02855     const QRect r1 = region.d->qt_rgn->innerRect;
02856     const QRect r2 = rect.normalized();
02857     return (r2.left() >= r1.left() && r2.right() <= r1.right()
02858             && r2.top() >= r1.top() && r2.bottom() <= r1.bottom());
02859 }
02860 #endif // QT_EXPERIMENTAL_REGIONS
02861 
02868 QVector<QRect> QRegion::rects() const
02869 {
02870     if (d->qt_rgn) {
02871         d->qt_rgn->rects.resize(d->qt_rgn->numRects);
02872         return d->qt_rgn->rects;
02873     } else {
02874         return QVector<QRect>();
02875     }
02876 }
02877 
02897 void QRegion::setRects(const QRect *rects, int num)
02898 {
02899     *this = QRegion();
02900     detach();
02901     if (!rects || (num == 1 && rects->isEmpty()))
02902         num = 0;
02903 
02904     d->qt_rgn->rects.resize(num);
02905     d->qt_rgn->numRects = num;
02906     if (num == 0) {
02907         d->qt_rgn->extents = QRect();
02908     } else {
02909         int left = INT_MAX,
02910             right = INT_MIN,
02911             top = INT_MAX,
02912             bottom = INT_MIN;
02913         for (int i = 0; i < num; ++i) {
02914             const QRect &rect = rects[i];
02915             d->qt_rgn->rects[i] = rect;
02916             left = qMin(rect.left(), left);
02917             right = qMax(rect.right(), right);
02918             top = qMin(rect.top(), top);
02919             bottom = qMax(rect.bottom(), bottom);
02920 #ifdef QT_EXPERIMENTAL_REGIONS
02921             d->qt_rgn->updateInnerRect(rect);
02922 #endif
02923         }
02924         d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
02925     }
02926 }
02927 
02933 bool QRegion::operator==(const QRegion &r) const
02934 {
02935     if (!d->qt_rgn || !r.d->qt_rgn)
02936         return r.d->qt_rgn == d->qt_rgn;
02937 
02938     if (d == r.d)
02939         return true;
02940     else
02941         return EqualRegion(d->qt_rgn, r.d->qt_rgn);
02942 }

Generated on Thu Mar 15 11:55:39 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1