Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/painting/qregion_win.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the QtGui module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
    4040****************************************************************************/
    4141
     42#include "qatomic.h"
    4243#include "qbitmap.h"
    4344#include "qbuffer.h"
     
    4647#include "qregion.h"
    4748#include "qt_windows.h"
     49#include "qpainterpath.h"
    4850
    4951QT_BEGIN_NAMESPACE
    5052
     53QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 };
    5154
    52 /*
    53     In Windows versions before Windows Vista CreateRectRgn - when called in a multi-threaded
    54     environment - might return an invalid handle. This function works around this limitation
    55     by verifying the handle with a quick GetRegionData() call and re-creates the region
    56     if necessary.
    57 */
    5855HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom)
    5956{
    6057    const int tries = 10;
    6158    for (int i = 0; i < tries; ++i) {
    62         HRGN region;
     59        HRGN region = 0;
    6360        switch (type) {
    6461        case QRegion::Rectangle:
     
    8178}
    8279
    83 #ifndef Q_OS_WINCE
    84 HRGN qt_tryCreatePolygonRegion(const QPolygon &a, Qt::FillRule fillRule)
     80QRegion qt_region_from_HRGN(HRGN rgn)
    8581{
    86     const int tries = 10;
    87     for (int i = 0; i < tries; ++i) {
    88         HRGN region = CreatePolygonRgn(reinterpret_cast<const POINT*>(a.data()), a.size(),
    89                                        fillRule == Qt::OddEvenFill ? ALTERNATE : WINDING);
    90         if (region) {
    91             if (GetRegionData(region, 0, 0))
    92                 return region;
    93             else
    94                 DeleteObject(region);
    95         }
    96     }
    97     return 0;
    98 }
    99 #endif
     82    int numBytes = GetRegionData(rgn, 0, 0);
     83    if (numBytes == 0)
     84        return QRegion();
    10085
    101 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 };
     86    char *buf = new char[numBytes];
     87    if (buf == 0)
     88        return QRegion();
    10289
    103 QRegion::QRegion()
    104     : d(&shared_empty)
    105 {
    106     d->ref.ref();
    107 }
    108 
    109 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
    110 QRegion::QRegion(const QRect &r, RegionType t)
    111 {
    112     if (r.isEmpty()) {
    113         d = &shared_empty;
    114         d->ref.ref();
    115     } else {
    116         d = new QRegionData;
    117         d->ref = 1;
    118         if (t == Rectangle)
    119             d->rgn = qt_tryCreateRegion(t, r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
    120         else if (t == Ellipse) {
    121             // need to add 1 to width/height for the ellipse to have correct boundingrect.
    122             d->rgn = qt_tryCreateRegion(t, r.x(), r.y(), r.x() + r.width() + 1, r.y() + r.height() + 1);
    123         }
    124     }
    125 }
    126 #endif
    127 
    128 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
    129 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
    130 {
    131     if (a.size() < 3) {
    132         d = &shared_empty;
    133         d->ref.ref();
    134     } else {
    135         d = new QRegionData;
    136         d->ref = 1;
    137         d->rgn = qt_tryCreatePolygonRegion(a, fillRule);
    138     }
    139 }
    140 #endif
    141 
    142 QRegion::QRegion(const QRegion &r)
    143 {
    144     d = r.d;
    145     d->ref.ref();
    146 }
    147 
    148 HRGN qt_win_bitmapToRegion(const QBitmap& bitmap)
    149 {
    150     HRGN region=0;
    151     QImage image = bitmap.toImage();
    152     const int MAXRECT = 256;
    153     struct RData {
    154         RGNDATAHEADER header;
    155         RECT rect[MAXRECT];
    156     };
    157     RData data;
    158 
    159 #define FlushSpans \
    160     { \
    161                 data.header.dwSize = sizeof(RGNDATAHEADER); \
    162                 data.header.iType = RDH_RECTANGLES; \
    163                 data.header.nCount = n; \
    164                 data.header.nRgnSize = 0; \
    165                 data.header.rcBound.bottom = y; \
    166                 HRGN r = ExtCreateRegion(0, \
    167                     sizeof(RGNDATAHEADER)+n*sizeof(RECT),(RGNDATA*)&data); \
    168                 if (region) { \
    169                     CombineRgn(region, region, r, RGN_OR); \
    170                     DeleteObject(r); \
    171                 } else { \
    172                     region = r; \
    173                 } \
    174                 data.header.rcBound.top = y; \
    175         }
    176 
    177 #define AddSpan \
    178         { \
    179             data.rect[n].left=prev1; \
    180             data.rect[n].top=y; \
    181             data.rect[n].right=x-1+1; \
    182             data.rect[n].bottom=y+1; \
    183             n++; \
    184             if (n == MAXRECT) { \
    185                 FlushSpans \
    186                 n=0; \
    187             } \
    188         }
    189 
    190     data.header.rcBound.top = 0;
    191     data.header.rcBound.left = 0;
    192     data.header.rcBound.right = image.width()-1;
    193     int n = 0;
    194 
    195     int zero = 0x00;
    196 
    197     int x, y;
    198     for (y = 0; y < image.height(); ++y) {
    199         uchar *line = image.scanLine(y);
    200         int w = image.width();
    201         uchar all=zero;
    202         int prev1 = -1;
    203         for (x = 0; x < w;) {
    204             uchar byte = line[x/8];
    205             if (x > w - 8 || byte != all) {
    206                 for (int b = 8; b > 0 && x < w; --b) {
    207                     if (!(byte & 0x01) == !all) {
    208                         // More of the same
    209                     } else {
    210                         // A change.
    211                         if (all != zero) {
    212                             AddSpan;
    213                             all = zero;
    214                         } else {
    215                             prev1 = x;
    216                             all = ~zero;
    217                         }
    218                     }
    219                     byte >>= 1;
    220                     ++x;
    221                 }
    222             } else {
    223                 x += 8;
    224             }
    225         }
    226         if (all != zero) {
    227             AddSpan;
    228         }
    229     }
    230     if (n) {
    231         FlushSpans;
     90    RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
     91    if (GetRegionData(rgn, numBytes, rd) == 0) {
     92        delete [] buf;
     93        return QRegion();
    23294    }
    23395
    234     if (!region) {
    235         // Surely there is some better way.
    236         region = qt_tryCreateRegion(QRegion::Rectangle, 0,0,1,1);
    237         CombineRgn(region, region, region, RGN_XOR);
     96    QRegion region;
     97    RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
     98    for (uint i = 0; i < rd->rdh.nCount; ++i) {
     99        QRect rect;
     100        rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
     101        ++r;
     102        region |= rect;
    238103    }
     104
     105    delete [] buf;
     106
    239107    return region;
    240108}
    241109
    242 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
    243 QRegion::QRegion(const QBitmap &bm)
     110void qt_win_dispose_rgn(HRGN r)
    244111{
    245     if (bm.isNull()) {
    246         d = &shared_empty;
    247         d->ref.ref();
    248     } else {
    249         d = new QRegionData;
    250         d->ref = 1;
    251         d->rgn = qt_win_bitmapToRegion(bm);
    252     }
    253 }
    254 #endif
    255 
    256 void QRegion::cleanUp(QRegion::QRegionData *x)
    257 {
    258     if (x->rgn)
    259         DeleteObject(x->rgn);
    260     delete x;
     112    if (r)
     113        DeleteObject(r);
    261114}
    262115
    263 QRegion::~QRegion()
     116static void qt_add_rect(HRGN &winRegion, QRect r)
    264117{
    265     if (!d->ref.deref())
    266         cleanUp(d);
    267 }
    268 
    269 QRegion &QRegion::operator=(const QRegion &r)
    270 {
    271     r.d->ref.ref();
    272     if (!d->ref.deref())
    273         cleanUp(d);
    274     d = r.d;
    275     return *this;
    276 }
    277 
    278 
    279 QRegion QRegion::copy() const
    280 {
    281     QRegion r;
    282     QRegionData *x = new QRegionData;
    283     x->ref = 1;
    284     if (d->rgn) {
    285         x->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 2, 2);
    286         CombineRgn(x->rgn, d->rgn, 0, RGN_COPY);
    287     } else {
    288         x->rgn = 0;
     118    HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
     119    if (rgn) {
     120        HRGN dest = CreateRectRgn(0,0,0,0);
     121        int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
     122        if (result) {
     123            DeleteObject(winRegion);
     124            winRegion = dest;
     125        }
     126        DeleteObject(rgn);
    289127    }
    290     if (!r.d->ref.deref())
    291         cleanUp(r.d);
    292     r.d = x;
    293     return r;
    294 }
    295 
    296 bool QRegion::isEmpty() const
    297 {
    298     return (d == &shared_empty || boundingRect().isEmpty());
    299 }
    300 
    301 
    302 bool QRegion::contains(const QPoint &p) const
    303 {
    304     return d->rgn ? PtInRegion(d->rgn, p.x(), p.y()) : false;
    305 }
    306 
    307 bool QRegion::contains(const QRect &r) const
    308 {
    309     if (!d->rgn)
    310         return false;
    311     RECT rect;
    312     SetRect(&rect, r.left(), r.top(), r.right(), r.bottom());
    313     return RectInRegion(d->rgn, &rect);
    314 }
    315 
    316 
    317 void QRegion::translate(int dx, int dy)
    318 {
    319     if (!d->rgn || (dx == 0 && dy == 0))
    320         return;
    321     detach();
    322     OffsetRgn(d->rgn, dx, dy);
    323 }
    324 
    325 
    326 #define RGN_NOP -1
    327 
    328 // Duplicates of those in qregion.cpp
    329 #define QRGN_OR               6
    330 #define QRGN_AND              7
    331 #define QRGN_SUB              8
    332 #define QRGN_XOR              9
    333 
    334 /*
    335   Performs the actual OR, AND, SUB and XOR operation between regions.
    336   Sets the resulting region handle to 0 to indicate an empty region.
    337 */
    338 
    339 QRegion QRegion::winCombine(const QRegion &r, int op) const
    340 {
    341     int both=RGN_NOP,
    342         left=RGN_NOP,
    343         right=RGN_NOP;
    344     switch (op) {
    345         case QRGN_OR:
    346             both = RGN_OR;
    347             left = right = RGN_COPY;
    348             break;
    349         case QRGN_AND:
    350             both = RGN_AND;
    351             break;
    352         case QRGN_SUB:
    353             both = RGN_DIFF;
    354             left = RGN_COPY;
    355             break;
    356         case QRGN_XOR:
    357             both = RGN_XOR;
    358             left = right = RGN_COPY;
    359             break;
    360         default:
    361             qWarning("QRegion: Internal error in winCombine");
    362     }
    363 
    364     int allCombineRgnResults = NULLREGION;
    365     QRegion result;
    366     result.detach();
    367     result.d->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 0, 0);
    368     if (d->rgn && r.d->rgn)
    369         allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, r.d->rgn, both);
    370     else if (d->rgn && left != RGN_NOP)
    371         allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, d->rgn, left);
    372     else if (r.d->rgn && right != RGN_NOP)
    373         allCombineRgnResults = CombineRgn(result.d->rgn, r.d->rgn, r.d->rgn, right);
    374 
    375     if (allCombineRgnResults == NULLREGION || allCombineRgnResults == ERROR)
    376         result = QRegion();
    377 
    378     //##### do not delete this. A null pointer is different from an empty region in SelectClipRgn in qpainter_win! (M)
    379 //     if (allCombineRgnResults == NULLREGION) {
    380 //         if (result.data->rgn)
    381 //             DeleteObject(result.data->rgn);
    382 //         result.data->rgn = 0;                        // empty region
    383 //     }
    384     return result;
    385 }
    386 
    387 QRegion QRegion::unite(const QRegion &r) const
    388 {
    389     if (!d->rgn)
    390         return r;
    391     if (!r.d->rgn)
    392         return *this;
    393     return winCombine(r, QRGN_OR);
    394 }
    395 
    396 QRegion QRegion::unite(const QRect &r) const
    397 {
    398     return unite(QRegion(r));
    399 }
    400 
    401 QRegion QRegion::intersect(const QRegion &r) const
    402 {
    403     if (!r.d->rgn || !d->rgn)
    404         return QRegion();
    405      return winCombine(r, QRGN_AND);
    406 }
    407 
    408 QRegion QRegion::subtract(const QRegion &r) const
    409 {
    410     if (!r.d->rgn || !d->rgn)
    411         return *this;
    412     return winCombine(r, QRGN_SUB);
    413 }
    414 
    415 QRegion QRegion::eor(const QRegion &r) const
    416 {
    417     if (!d->rgn)
    418         return r;
    419     if (!r.d->rgn)
    420         return *this;
    421     return winCombine(r, QRGN_XOR);
    422 }
    423 
    424 
    425 QRect QRegion::boundingRect() const
    426 {
    427     if (!d->rgn)
    428         return QRect();
    429     RECT r;
    430     if (GetRgnBox(d->rgn, &r) == NULLREGION)
    431         return QRect();
    432     else
    433         return QRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
    434 }
    435 
    436 QVector<QRect> QRegion::rects() const
    437 {
    438     if (d->rgn == 0)
    439         return QVector<QRect>();
    440 
    441     int numBytes = GetRegionData(d->rgn, 0, 0);
    442     if (numBytes == 0)
    443         return QVector<QRect>();
    444 
    445     char *buf = new char[numBytes];
    446     if (buf == 0)
    447         return QVector<QRect>();
    448 
    449     RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
    450     if (GetRegionData(d->rgn, numBytes, rd) == 0) {
    451         delete [] buf;
    452         return QVector<QRect>();
    453     }
    454 
    455     QVector<QRect> a(rd->rdh.nCount);
    456     RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
    457     for (int i = 0; i < a.size(); ++i) {
    458         a[i].setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
    459         ++r;
    460     }
    461 
    462     delete [] buf;
    463     return a;
    464 }
    465 
    466 void QRegion::setRects(const QRect *rects, int num)
    467 {
    468     *this = QRegion();
    469     if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
    470         return;
    471     for (int i = 0; i < num; ++i)
    472         *this |= rects[i];
    473 }
    474 
    475 int QRegion::numRects() const
    476 {
    477     if (d->rgn == 0)
    478         return 0;
    479 
    480     const int numBytes = GetRegionData(d->rgn, 0, 0);
    481     if (numBytes == 0)
    482         return 0;
    483 
    484     char *buf = new char[numBytes];
    485     if (buf == 0)
    486         return 0;
    487 
    488     RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
    489     if (GetRegionData(d->rgn, numBytes, rd) == 0) {
    490         delete[] buf;
    491         return 0;
    492     }
    493 
    494     const int n = rd->rdh.nCount;
    495     delete[] buf;
    496 
    497     return n;
    498 }
    499 
    500 bool QRegion::operator==(const QRegion &r) const
    501 {
    502     if (d == r.d)
    503         return true;
    504     if ((d->rgn == 0) ^ (r.d->rgn == 0)) // one is empty, not both
    505         return false;
    506     return d->rgn == 0 ? true // both empty
    507                        : EqualRgn(d->rgn, r.d->rgn); // both non-empty
    508 }
    509 
    510 QRegion& QRegion::operator+=(const QRegion &r)
    511 {
    512     if (!r.d->rgn)
    513         return *this;
    514 
    515     if (!d->rgn) {
    516         *this = r;
    517         return *this;
    518     }
    519 
    520     detach();
    521 
    522     int result;
    523     result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_OR);
    524     if (result == NULLREGION || result == ERROR)
    525         *this = QRegion();
    526 
    527     return *this;
    528 }
    529 
    530 QRegion& QRegion::operator-=(const QRegion &r)
    531 {
    532     if (!r.d->rgn || !d->rgn)
    533         return *this;
    534 
    535     detach();
    536 
    537     int result;
    538     result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_DIFF);
    539     if (result == NULLREGION || result == ERROR)
    540         *this = QRegion();
    541 
    542     return *this;
    543 }
    544 
    545 QRegion& QRegion::operator&=(const QRegion &r)
    546 {
    547     if (!d->rgn)
    548         return *this;
    549 
    550     if (!r.d->rgn) {
    551         *this = QRegion();
    552         return *this;
    553     }
    554 
    555     detach();
    556 
    557     int result;
    558     result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_AND);
    559     if (result == NULLREGION || result == ERROR)
    560         *this = QRegion();
    561 
    562     return *this;
    563 }
    564 
    565 bool qt_region_strictContains(const QRegion &region, const QRect &rect)
    566 {
    567     Q_UNUSED(region);
    568     Q_UNUSED(rect);
    569     return false;
    570128}
    571129
    572130void QRegion::ensureHandle() const
    573131{
     132    if (d->rgn)
     133        DeleteObject(d->rgn);
     134    d->rgn = CreateRectRgn(0,0,0,0);
     135    if (d->qt_rgn) {
     136        if (d->qt_rgn->numRects == 1) {
     137            QRect r = d->qt_rgn->extents;
     138            qt_add_rect(d->rgn, r);
     139            return;
     140        }
     141        for (int i = 0;i < d->qt_rgn->numRects;i++) {
     142            QRect r = d->qt_rgn->rects.at(i);
     143            qt_add_rect(d->rgn, r);
     144        }
     145    }
    574146}
    575147
     148
    576149QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.