Ignore:
Timestamp:
Feb 13, 2010, 6:36:55 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: Adopted to 4.6.1 changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/painting/qregion_pm.cpp

    r564 r569  
    6868//  The handle() function, used for external access to the region, takes an
    6969//  argument that must be always set to the height of the target device to
    70 //  guarantee the correct coordinate space alignment.
    71 
    72 #if defined(__GNUC__) && defined(__INNOTEK_LIBC__)
    73 
    74 // Innotek GCC lacks some API functions in its version of OS/2 Toolkit headers
    75 
    76 extern "C" HRGN APIENTRY GpiCreateEllipticRegion(HPS hps,
    77                                                  PRECTL prclRect);
    78 
    79 extern "C" HRGN APIENTRY GpiCreatePolygonRegion(HPS hps,
    80                                                 ULONG ulCount,
    81                                                 PPOLYGON paplgn,
    82                                                 ULONG flOptions);
    83 #endif
     70//  guarantee the correct y axis alignment.
    8471
    8572QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1),
    8673                                               NULLHANDLE, 0 };
    8774
    88 QRegion::QRegion()
    89     : d(&shared_empty)
     75/*!
     76    \internal
     77
     78    Deletes the given region handle.
     79 */
     80void QRegion::disposeHandle(HRGN hrgn)
    9081{
    91     d->ref.ref();
    92 }
    93 
    94 QRegion::QRegion(const QRect &r, RegionType t)
    95 {
    96     if (r.isEmpty()) {
    97         d = &shared_empty;
    98         d->ref.ref();
    99     } else {
    100         d = new QRegionData;
    101         d->ref = 1;
    102         d->height = 0;
    103         HPS hps = qt_display_ps();
    104         if (t == Rectangle) {
    105             RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
    106             d->rgn = GpiCreateRegion(hps, 1, &rcl);
    107         } else if (t == Ellipse) {
    108             // if the width or height of the ellipse is odd, GPI always
    109             // converts it to a nearest even value, which is obviously stupid
    110             // So, we don't use GpiCreateEllipticRegion(), but create an array
    111             // of points to call GpiCreatePolygonRegion() instead.
    112             QPainterPath p(QPointF(r.x(), r.y()));
    113             p.arcTo(r.x(), r.y(), r.width(), r.height(), 0, 360);
    114             QPolygon a = p.toFillPolygon().toPolygon();
    115             for (int i = 0; i < a.size(); ++ i)
    116                 a[i].ry() = -(a[i].y() + 1);
    117             // GpiCreatePolygonRegion() is bogus and always starts a poligon from
    118             // the current position. Make the last point the current one and reduce
    119             // the number of points by one.
    120             GpiMove(hps, reinterpret_cast<PPOINTL>(&a[a.size() - 1]));
    121             POLYGON poly = { a.size() - 1, reinterpret_cast<PPOINTL>(a.data()) };
    122             d->rgn = GpiCreatePolygonRegion(hps, 1, &poly, POLYGON_ALTERNATE);
    123         }
    124     }
    125 }
    126 
    127 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
    128 {
    129     if (a.size() < 3) {
    130         d = &shared_empty;
    131         d->ref.ref();
    132     } else {
    133         d = new QRegionData;
    134         d->ref = 1;
    135         d->height = 0;
    136         HPS hps = qt_display_ps();
    137         POINTL *pts = new POINTL[a.size()];
    138         for (int i = 0; i < a.size(); ++ i) {
    139             pts[i].x = a[i].x();
    140             pts[i].y = - (a[i].y() + 1);
    141         }
    142         // GpiCreatePolygonRegion() is bogus and always starts a poligon from
    143         // the current position. Make the last point the current one and reduce
    144         // the number of points by one.
    145         GpiMove(hps, &pts[a.size() - 1]);
    146         POLYGON poly = { a.size() - 1, pts };
    147         ULONG opts = Qt::OddEvenFill ? POLYGON_ALTERNATE : POLYGON_WINDING;
    148         d->rgn = GpiCreatePolygonRegion(hps, 1, &poly, opts);
    149         delete[] pts;
    150     }
    151 }
    152 
    153 QRegion::QRegion(const QRegion &r)
    154 {
    155     d = r.d;
    156     d->ref.ref();
    157 }
    158 
    159 static HRGN bitmapToRegion(const QBitmap& bitmap)
    160 {
    161     HRGN region = 0;
    162     QImage image = bitmap.toImage();
    163     const int maxrect = 256;
    164     RECTL rects[maxrect];
    165     HPS hps = qt_display_ps();
    166 
    167 #define FlushSpans \
    168     { \
    169         HRGN r = GpiCreateRegion(hps, n, rects); \
    170             if (region) { \
    171                 GpiCombineRegion(hps, region, region, r, CRGN_OR); \
    172                 GpiDestroyRegion(hps, r); \
    173         } else { \
    174             region = r; \
    175         } \
    176     }
    177 
    178 #define AddSpan \
    179     { \
    180         rects[n].xLeft = prev1; \
    181         rects[n].yBottom = -(y+1); \
    182         rects[n].xRight = x-1+1; \
    183         rects[n].yTop = -y; \
    184         n++; \
    185         if (n == maxrect) { \
    186             FlushSpans \
    187             n = 0; \
    188         } \
    189     }
    190 
    191     int n = 0;
    192     int zero = 0x00;
    193 
    194     int x, y;
    195     for (y = 0; y < image.height(); y++) {
    196         uchar *line = image.scanLine(y);
    197         int w = image.width();
    198         uchar all = zero;
    199         int prev1 = -1;
    200         for (x = 0; x < w;) {
    201             uchar byte = line[x/8];
    202             if (x > w-8 || byte != all) {
    203                 for (int b = 8; b > 0 && x < w; b--) {
    204                     if (!(byte & 0x80) == !all) {
    205                     // More of the same
    206                     } else {
    207                                 // A change.
    208                                 if (all != zero) {
    209                                     AddSpan;
    210                                     all = zero;
    211                                 } else {
    212                                     prev1 = x;
    213                                     all = ~zero;
    214                                 }
    215                     }
    216                     byte <<= 1;
    217                     x++;
    218                 }
    219             } else {
    220                 x += 8;
    221             }
    222         }
    223         if (all != zero) {
    224             AddSpan;
    225         }
    226     }
    227     if (n) {
    228         FlushSpans;
    229     }
    230 
    231     if (!region)
    232         region = GpiCreateRegion(hps, 0, NULL);
    233 
    234     return region;
    235 }
    236 
    237 QRegion::QRegion(const QBitmap &bm)
    238 {
    239     if (bm.isNull()) {
    240         d = &shared_empty;
    241         d->ref.ref();
    242     } else {
    243         d = new QRegionData;
    244         d->ref = 1;
    245         d->height = 0;
    246         d->rgn = bitmapToRegion(bm);
    247     }
    248 }
    249 
    250 void QRegion::cleanUp(QRegion::QRegionData *x)
    251 {
    252     if (x->rgn != NULLHANDLE)
    253         GpiDestroyRegion(qt_display_ps(), x->rgn);
    254     delete x;
    255 }
    256 
    257 QRegion::~QRegion()
    258 {
    259     if (!d->ref.deref())
    260         cleanUp(d);
    261 }
    262 
    263 QRegion &QRegion::operator=(const QRegion &r)
    264 {
    265     r.d->ref.ref();
    266     if (!d->ref.deref())
    267         cleanUp(d);
    268     d = r.d;
    269     return *this;
    270 }
    271 
    272 
    273 QRegion QRegion::copy() const
    274 {
    275     QRegion r;
    276     QRegionData *x = new QRegionData;
    277     x->ref = 1;
    278     if (d->rgn != NULLHANDLE) {
    279         x->height = d->height;
    280         HPS hps = qt_display_ps();
    281         x->rgn = GpiCreateRegion(hps, 0, NULL);
    282         GpiCombineRegion(hps, x->rgn, d->rgn, NULL, CRGN_COPY);
    283     } else {
    284         x->height = 0;
    285         x->rgn = NULLHANDLE;
    286     }
    287     if (!r.d->ref.deref())
    288         cleanUp(r.d);
    289     r.d = x;
    290     return r;
    291 }
    292 
    293 bool QRegion::isEmpty() const
    294 {
    295     return (d == &shared_empty || boundingRect().isEmpty());
    296 }
    297 
    298 bool QRegion::contains(const QPoint &p) const
    299 {
    300     LONG rc = PRGN_OUTSIDE;
    301     if (d->rgn != NULLHANDLE) {
    302         POINTL ptl = { p.x(), d->height - (p.y() + 1) };
    303         rc = GpiPtInRegion(qt_display_ps(), d->rgn, &ptl);
    304     }
    305     return rc == PRGN_INSIDE;
    306 }
    307 
    308 bool QRegion::contains(const QRect &r) const
    309 {
    310     LONG rc = PRGN_OUTSIDE;
    311     if (d->rgn != NULLHANDLE) {
    312         RECTL rcl = { r.left(), d->height - (r.bottom() + 1),
    313                       r.right() + 1, d->height - r.top() };
    314         rc = GpiRectInRegion(qt_display_ps(), d->rgn, &rcl);
    315     }
    316     return rc == RRGN_INSIDE || rc == RRGN_PARTIAL;
    317 }
    318 
    319 void QRegion::translate(int dx, int dy)
    320 {
    321     if (d->rgn == NULLHANDLE || (dx == 0 && dy == 0))
    322         return;
    323     detach();
    324     POINTL ptl = { dx, -dy };
    325     GpiOffsetRegion(qt_display_ps(), d->rgn, &ptl);
    326 }
    327 
    328 #define CRGN_NOP -1
    329 
    330 // Duplicates of those in qregion.cpp
    331 #define QRGN_OR               6
    332 #define QRGN_AND              7
    333 #define QRGN_SUB              8
    334 #define QRGN_XOR              9
    335 
    336 /*
    337   Performs the actual OR, AND, SUB and XOR operation between regions.
    338   Sets the resulting region handle to 0 to indicate an empty region.
    339 */
    340 
    341 QRegion QRegion::pmCombine(const QRegion &r, int op) const
    342 {
    343     LONG both = CRGN_NOP, left = CRGN_NOP, right = CRGN_NOP;
    344     switch (op) {
    345     case QRGN_OR:
    346         both = CRGN_OR;
    347         left = right = CRGN_COPY;
    348         break;
    349     case QRGN_AND:
    350         both = CRGN_AND;
    351         break;
    352     case QRGN_SUB:
    353         both = CRGN_DIFF;
    354         left = CRGN_COPY;
    355         break;
    356     case QRGN_XOR:
    357         both = CRGN_XOR;
    358         left = right = CRGN_COPY;
    359         break;
    360     default:
    361         qWarning( "QRegion: Internal error in pmCombine" );
    362     }
    363 
    364     QRegion result;
    365     if (d->rgn == NULLHANDLE && r.d->rgn == NULLHANDLE)
    366         return result;
    367     HPS hps = qt_display_ps();
    368     result.detach();
    369     result.d->rgn = GpiCreateRegion(hps, 0, NULL);
    370     LONG rc = RGN_NULL;
    371     if (d->rgn != NULLHANDLE && r.d->rgn != NULLHANDLE) {
    372         updateHandle(r.d->height); // bring to the same coordinate space
    373         rc = GpiCombineRegion(hps, result.d->rgn, d->rgn, r.d->rgn, both);
    374         result.d->height = r.d->height;
    375     } else if (d->rgn && left != CRGN_NOP) {
    376         rc = GpiCombineRegion(hps, result.d->rgn, d->rgn, 0, left);
    377         result.d->height = d->height;
    378     } else if (r.d->rgn != NULLHANDLE && right != CRGN_NOP) {
    379         rc = GpiCombineRegion(hps, result.d->rgn, r.d->rgn, 0, right);
    380         result.d->height = r.d->height;
    381     }
    382     if (rc == RGN_NULL || rc == RGN_ERROR) {
    383         result = QRegion(); // shared_empty
    384     }
    385     return result;
    386 }
    387 
    388 QRegion QRegion::unite(const QRegion &r) const
    389 {
    390     if (d->rgn == NULLHANDLE)
    391         return r;
    392     if (r.d->rgn == NULLHANDLE)
    393         return *this;
    394     return pmCombine(r, QRGN_OR);
    395 }
    396 
    397 QRegion QRegion::unite(const QRect &r) const
    398 {
    399     return unite(QRegion(r));
    400 }
    401 
    402 QRegion QRegion::intersect(const QRegion &r) const
    403 {
    404     if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE)
    405         return QRegion();
    406      return pmCombine(r, QRGN_AND);
    407 }
    408 
    409 QRegion QRegion::subtract(const QRegion &r) const
    410 {
    411     if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE)
    412         return *this;
    413     return pmCombine(r, QRGN_SUB);
    414 }
    415 
    416 QRegion QRegion::eor(const QRegion &r) const
    417 {
    418     if (d->rgn == NULLHANDLE)
    419         return r;
    420     if (r.d->rgn == NULLHANDLE)
    421         return *this;
    422     return pmCombine(r, QRGN_XOR);
    423 }
    424 
    425 QRect QRegion::boundingRect() const
    426 {
    427     if (!d->rgn)
    428         return QRect();
    429 
    430     RECTL rcl;
    431     LONG rc = RGN_NULL;
    432     if (d->rgn != NULLHANDLE)
    433         rc = GpiQueryRegionBox(qt_display_ps(), d->rgn, &rcl);
    434     if (rc == RGN_NULL || rc == RGN_ERROR)
    435         return QRect();
    436     else
    437         return QRect(rcl.xLeft, d->height - rcl.yTop,
    438                      rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom);
    439 }
    440 
    441 QVector<QRect> QRegion::rects() const
    442 {
    443     QVector<QRect> a;
    444 
    445     if (d->rgn == NULLHANDLE)
    446         return a;
    447 
    448     HPS hps = qt_display_ps();
    449     RGNRECT ctl = {1, 0, 0, RECTDIR_LFRT_TOPBOT};
    450     if (!GpiQueryRegionRects(hps, d->rgn, NULL, &ctl, NULL))
    451         return a;
    452 
    453     ctl.crc = ctl.crcReturned;
    454     PRECTL rcls = new RECTL[ctl.crcReturned];
    455     if (rcls == 0)
    456         return a;
    457     if (!GpiQueryRegionRects(hps, d->rgn, NULL, &ctl, rcls)) {
    458         delete [] rcls;
    459         return a;
    460     }
    461 
    462     a = QVector<QRect>(ctl.crcReturned);
    463     PRECTL r = rcls;
    464     for (int i = 0; i < a.size(); ++i) {
    465         a[i].setRect(r->xLeft, d->height - r->yTop,
    466                      r->xRight - r->xLeft, r->yTop - r->yBottom);
    467         ++r;
    468     }
    469 
    470     delete [] rcls;
    471     return a;
    472  }
    473 
    474 void QRegion::setRects(const QRect *rects, int num)
    475 {
    476     *this = QRegion();
    477     if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
    478         return;
    479     for (int i = 0; i < num; ++i)
    480         *this |= rects[i];
    481 }
    482 
    483 int QRegion::numRects() const
    484 {
    485     if (d->rgn == NULLHANDLE)
    486         return 0;
    487 
    488     RGNRECT ctl = {1, 0, 0, RECTDIR_LFRT_TOPBOT};
    489     if (!GpiQueryRegionRects(qt_display_ps(), d->rgn, NULL, &ctl, NULL))
    490         return 0;
    491 
    492     return ctl.crcReturned;
    493 }
    494 
    495 bool QRegion::operator==(const QRegion &r) const
    496 {
    497     if (d == r.d)
    498         return true;
    499     if ((d->rgn == NULLHANDLE) ^ (r.d->rgn == NULLHANDLE)) // one is empty, not both
    500         return false;
    501     if (d->rgn == NULLHANDLE) // both empty
    502         return true;
    503     updateHandle(r.d->height); // bring to the same coordinate space
    504     return // both not empty
    505         GpiEqualRegion(qt_display_ps(), d->rgn, r.d->rgn) == EQRGN_EQUAL;
    506 }
    507 
    508 QRegion& QRegion::operator+=(const QRegion &r)
    509 {
    510     if (r.d->rgn == NULLHANDLE)
    511         return *this;
    512 
    513     if (d->rgn == NULLHANDLE) {
    514         *this = r;
    515         return *this;
    516     }
    517 
    518     *this = unite(r);
    519     return *this;
    520 }
    521 
    522 QRegion& QRegion::operator-=(const QRegion &r)
    523 {
    524     if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE)
    525         return *this;
    526 
    527     *this = subtract(r);
    528     return *this;
    529 }
    530 
    531 QRegion& QRegion::operator&=(const QRegion &r)
    532 {
    533     if (d->rgn == NULLHANDLE)
    534         return *this;
    535 
    536     if (r.d->rgn == NULLHANDLE) {
    537         *this = QRegion();
    538         return *this;
    539     }
    540 
    541     *this = intersect(r);
    542     return *this;
    543 }
    544 
    545 bool qt_region_strictContains(const QRegion &region, const QRect &rect)
    546 {
    547     Q_UNUSED(region);
    548     Q_UNUSED(rect);
    549     return false;
     82    if (hrgn != 0)
     83        GpiDestroyRegion(qt_display_ps(), hrgn);
    55084}
    55185
     
    55892void QRegion::updateHandle(int targetHeight) const
    55993{
    560     QRegion *that = const_cast<QRegion*>(this); // we're const here
    561     if (d->rgn == NULLHANDLE) {
    562         // a handle of a null region is requested, allocate an empty region
    563         that->detach();
    564         that->d->rgn = GpiCreateRegion(qt_display_ps(), 0, NULL);
    565         that->d->height = targetHeight;
    566     } else if (d->height != targetHeight) {
    567         // align region y axis to the top of the device
    568         that->detach();
    569         POINTL ptl = { 0, targetHeight - d->height };
    570         GpiOffsetRegion(qt_display_ps(), d->rgn, &ptl);
    571         that->d->height = targetHeight;
     94    QRegion * = const_cast<QRegion*>(this); // we're const here
     95
     96   
     97       
     98       
     99        ;
     100   
     101       
     102        ;
     103       
     104       
     105        ;
    572106    }
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
     117
     118
     119
     120
     121
     122
     123
     124
     125
     126
     127
     128
     129
     130
    573131}
    574132
Note: See TracChangeset for help on using the changeset viewer.