Ignore:
Timestamp:
Feb 6, 2006, 10:43:39 PM (20 years ago)
Author:
dmik
Message:

Implemented QRegion(..., QRegion::Eclipse) and QRegion(QPointArray &,...) constructors.
Improved Qt<->GPI region coordinates translation (it's now implicit), QRegion::handle() takes a height of the target devise as an argument (defaults to 0).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel/qregion_pm.cpp

    r8 r61  
    4343#include "qt_os2.h"
    4444
    45 // We always create a GPI resuorce for a region with top and bottom corner
    46 // points made negative and swapped. This gives us no-cost top to bottom
    47 // flipping but requires to call GpiOffsetRegion() to offset the region up by
    48 // the height of the presentation space viewport before it is actually used on
    49 // that presentation space (usually for clipping) and, on the contrary, offset
    50 // the region got from GPI down before it is stored in QRegion.
     45//  To compensate the difference between Qt (where y axis goes downwards) and
     46//  GPI (where y axis goes upwards) coordinate spaces when dealing with regions
     47//  we use the following technique: when a GPI resource is allocated for a Qt
     48//  region, we simply change the sign of all y coordinates to quickly flip it
     49//  top to bottom in a manner that doesn't depend on the target device height.
     50//  All we have to do to apply the created GPI region to a particular GPI device
     51//  is to align its y axis to the top of the device (i.e. offset the region
     52//  up by the height of the device), and unalign it afterwards to bring it back
     53//  to the coordinate space of other device-independent (unaligned) regions.
     54//  To optimize this, we remember (in data->hgt) the last height value used to
     55//  align the region, and align it again only if the target device height
     56//  changes. Zero height indicates a device-independent target (such as other
     57//  unaligned Qt region).
     58//
     59//  The handle() function, used for external access to the region, takes an
     60//  argument that must be always set to the height of the target device to
     61//  guarantee the correct coordinate space alignment.
     62
     63#if defined(Q_CC_GNU) && !defined(USE_OS2_TOOLKIT_HEADERS)
     64
     65// Innotek GCC lacks some API functions in its version of OS/2 Toolkit headers
     66
     67extern "C" HRGN APIENTRY GpiCreateEllipticRegion( HPS hps,
     68                                                  PRECTL prclRect );
     69
     70extern "C" HRGN APIENTRY GpiCreatePolygonRegion( HPS hps,
     71                                                 ULONG ulCount,
     72                                                 PPOLYGON paplgn,
     73                                                 ULONG flOptions );
     74#endif
    5175
    5276QRegion::QRegion()
     
    5579    Q_CHECK_PTR( data );
    5680    data->rgn = 0;
     81    data->hgt = 0;
    5782    data->is_null = TRUE;
    5883}
     
    6388    Q_CHECK_PTR( data );
    6489    data->rgn = 0;
     90    data->hgt = 0;
    6591    data->is_null = is_null;
    6692}
    6793
    68 QRegion::QRegion( const QRect &r, RegionType t )
     94QRegion::QRegion( HRGN hrgn, int target_height )
    6995{
    7096    data = new QRegionData;
    7197    Q_CHECK_PTR( data );
     98    data->rgn = hrgn;
     99    data->hgt = target_height;
     100    data->is_null = FALSE;
     101}
     102
     103QRegion::QRegion( const QRect &r, RegionType t )
     104{
     105    data = new QRegionData;
     106    Q_CHECK_PTR( data );
     107    data->hgt = 0;
    72108    data->is_null = FALSE;
    73109    if ( r.isEmpty() ) {
     
    79115            data->rgn = GpiCreateRegion( hps, 1, &rcl );
    80116        } else if ( t == Ellipse ) {            // elliptic region
    81 //@@TODO (dmik): create elliptic regions using GpiCreateEllipticRegion() later.
    82 //  now simply create it as rectangular.
    83             RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
    84             data->rgn = GpiCreateRegion( hps, 1, &rcl );
     117            // if the width or height of the ellipse is odd, GPI always
     118            // converts it to a nearest even value, which is obviously stupid
     119            // (see also QPainter::drawArcInternal()). So, we don't use
     120            // GpiCreateEllipticRegion(), but create an array of points to
     121            // call GpiCreatePolygonRegion() instead.
     122            QPointArray a;
     123            a.makeArc( r.x(), r.y(), r.width(), r.height(), 0, 360 * 16 );
     124            for ( uint i = 0; i < a.size(); ++ i )
     125                a[i].ry() = -(a[i].y() + 1);
     126            // GpiCreatePolygonRegion() is bogus and always starts a poligon from
     127            // the current position. Make the last point the current one and reduce
     128            // the number of points by one.
     129            GpiMove( hps, (PPOINTL) &a[ a.size() - 1 ] );
     130            POLYGON poly = { a.size() - 1, (PPOINTL) a.data() };
     131            data->rgn = GpiCreatePolygonRegion( hps, 1, &poly, POLYGON_ALTERNATE );
    85132        }
    86133    }
     
    91138    data = new QRegionData;
    92139    Q_CHECK_PTR( data );
     140    data->hgt = 0;
    93141    data->is_null = FALSE;
    94142    QRect r = a.boundingRect();
     
    96144        data->rgn = 0;
    97145    } else {
    98 //@@TODO (dmik): create poligonal regions using GpiCreatePolygonRegion() later.
    99 //  now simply create as bounding rectangle.
    100         RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
    101         data->rgn = GpiCreateRegion( qt_display_ps(), 1, &rcl );
     146        HPS hps = qt_display_ps();
     147        POINTL *pts = new POINTL[ a.size() ];
     148        for ( uint i = 0; i < a.size(); ++ i ) {
     149            pts[i].x = a[i].x();
     150            pts[i].y = - (a[i].y() + 1);
     151        }
     152        // GpiCreatePolygonRegion() is bogus and always starts a poligon from
     153        // the current position. Make the last point the current one and reduce
     154        // the number of points by one.
     155        GpiMove( hps, &pts[ a.size() - 1 ] );
     156        POLYGON poly = { a.size() - 1, pts };
     157        ULONG opts = winding ? POLYGON_WINDING : POLYGON_ALTERNATE;
     158        data->rgn = GpiCreatePolygonRegion( hps, 1, &poly, opts );
     159        delete[] pts;
    102160    }
    103161}
     
    192250    data = new QRegionData;
    193251    Q_CHECK_PTR( data );
     252    data->hgt = 0;
    194253    data->is_null = FALSE;
    195254    if ( bm.isNull() )
     
    225284{
    226285    QRegion r ( data->is_null );
     286    r.data->hgt = 0;
    227287    if ( !data->is_null && data->rgn ) {
    228288        HPS hps = qt_display_ps();
    229289        r.data->rgn = GpiCreateRegion( hps, 0, NULL );
    230290        GpiCombineRegion( hps, r.data->rgn, data->rgn, NULL, CRGN_COPY );
     291        r.data->hgt = data->hgt;
    231292    }
    232293    return r;
     
    252313    LONG rc = PRGN_OUTSIDE;
    253314    if ( data->rgn ) {
    254         POINTL ptl = { p.x(), -(p.y()+1) };
     315        POINTL ptl = { p.x(), data->hgt - (p.y() + 1) };
    255316        rc = GpiPtInRegion( qt_display_ps(), data->rgn, &ptl );
    256317    }
     
    262323    LONG rc = PRGN_OUTSIDE;
    263324    if ( data->rgn ) {
    264         RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
     325        RECTL rcl = { r.left(), data->hgt - (r.bottom() + 1),
     326                      r.right() + 1, data->hgt - r.top() };
    265327        rc = GpiRectInRegion( qt_display_ps(), data->rgn, &rcl );
    266328    }
     
    318380    HPS hps = qt_display_ps();
    319381    result.data->rgn = GpiCreateRegion( hps, 0, NULL );
    320     if ( data->rgn && r.data->rgn )
    321         GpiCombineRegion( hps, result.data->rgn, data->rgn, r.data->rgn, both );
    322     else if ( data->rgn && left != CRGN_NOP )
    323         GpiCombineRegion( hps, result.data->rgn, data->rgn, NULL, left );
    324     else if ( r.data->rgn && right != CRGN_NOP )
    325         GpiCombineRegion( hps, result.data->rgn, r.data->rgn, NULL, right );
     382    LONG rc = RGN_NULL;
     383    if ( data->rgn && r.data->rgn ) {
     384        updateHandle( r.data->hgt ); // bring to the same coordinate space
     385        rc = GpiCombineRegion( hps, result.data->rgn, data->rgn, r.data->rgn, both );
     386        result.data->hgt = r.data->hgt;
     387    } else if ( data->rgn && left != CRGN_NOP ) {
     388        rc = GpiCombineRegion( hps, result.data->rgn, data->rgn, 0, left );
     389        result.data->hgt = data->hgt;
     390    } else if ( r.data->rgn && right != CRGN_NOP ) {
     391        rc = GpiCombineRegion( hps, result.data->rgn, r.data->rgn, 0, right );
     392        result.data->hgt = r.data->hgt;
     393    }
     394    if ( rc == RGN_NULL || rc == RGN_ERROR ) {
     395        GpiDestroyRegion( hps, result.data->rgn );
     396        result.data->rgn = result.data->hgt = 0;
     397    }
    326398    return result;
    327399}
     
    354426    if ( data->rgn )
    355427        rc = GpiQueryRegionBox( qt_display_ps(), data->rgn, &rcl );
    356     if ( rc == RGN_NULL )
     428    if ( rc == RGN_NULL || rc == RGN_ERROR )
    357429        return QRect(0,0,0,0);
    358430    else
    359         return QRect(rcl.xLeft, -rcl.yTop, rcl.xRight-rcl.xLeft, rcl.yTop-rcl.yBottom );
     431        return QRect( rcl.xLeft, data->hgt - rcl.yTop,
     432                      rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom );
    360433}
    361434
     
    382455    PRECTL r = rcls;
    383456    for ( int i=0; i<(int)a.size(); i++ ) {
    384         a[i].setRect( r->xLeft, -r->yTop, r->xRight-r->xLeft, r->yTop-r->yBottom );
     457        a[i].setRect( r->xLeft, data->hgt - r->yTop,
     458                      r->xRight - r->xLeft, r->yTop - r->yBottom );
    385459        r++;
    386460    }
     
    407481    if ( (is_empty ^ r_is_empty ) )             // one is empty, not both
    408482        return FALSE;
    409     return is_empty ?
    410         TRUE :                                  // both empty
    411         GpiEqualRegion( qt_display_ps(), data->rgn, r.data->rgn ) == EQRGN_EQUAL;
    412 }
    413 
    414 void QRegion::update() const
    415 {
    416     // lazy initialization. this method should be called only from handle()
    417     data->rgn = GpiCreateRegion( qt_display_ps(), 0, NULL );
    418 }
     483    if ( is_empty )                             // both empty
     484        return TRUE;
     485    updateHandle( r.data->hgt ); // bring to the same coordinate space
     486    return
     487        GpiEqualRegion( qt_display_ps(), data->rgn, r.data->rgn ) == EQRGN_EQUAL;
     488}
     489
     490/*!
     491 *  \internal
     492 *  Updates the region handle so that it is suitable for selection to
     493 *  a device with the given \a height.
     494 */
     495void QRegion::updateHandle( int target_height ) const
     496{
     497    QRegion *that = const_cast< QRegion *>( this ); // we're const here
     498    if ( !data->rgn ) {
     499        // a handle of a null region is requested, allocate an empty region
     500        that->data->rgn = GpiCreateRegion( qt_display_ps(), 0, NULL );
     501        that->data->hgt = target_height;
     502    } else if ( data->hgt != target_height ) {
     503        // align region y axis to the top of the device
     504        POINTL ptl = { 0, target_height - data->hgt };
     505        GpiOffsetRegion( qt_display_ps(), data->rgn, &ptl );
     506        that->data->hgt = target_height;
     507    }
     508}
Note: See TracChangeset for help on using the changeset viewer.