/*! * \internal * Updates the region handle so that it is suitable for selection to * a device with the given \a height. */ void QRegion::updateHandle( int target_height ) const { QRegion *that = const_cast< QRegion *>( this ); // we're const here if ( !data->rgn ) { // a handle of a null region is requested, allocate an empty region that->data->rgn = GpiCreateRegion( qt_display_ps(), 0, NULL ); that->data->hgt = target_height; } else if ( data->hgt != target_height ) { // align region y axis to the top of the device POINTL ptl = { 0, target_height - data->hgt }; GpiOffsetRegion( qt_display_ps(), data->rgn, &ptl ); that->data->hgt = target_height; } }
/*! \internal Updates the region handle so that it is suitable for selection to a device with the given \a height. */ void QRegion::updateHandle(int targetHeight) const { QRegion *self = const_cast<QRegion*>(this); // we're const here if (d->rgn != 0) { if (self->d->ref == 1) { // align region y axis to the top of the device POINTL ptl = { 0, targetHeight - d->height }; GpiOffsetRegion(qt_display_ps(), d->rgn, &ptl); self->d->height = targetHeight; return; } // create a copy since the hande may be in use (this will reset d->rgn) *self = copy(); } Q_ASSERT(d->rgn == 0); // new/updated/copied Qt region data, create a new HRGN for it self->d->height = targetHeight; if (d->qt_rgn) { if (d->qt_rgn->numRects > 0) { if (d->qt_rgn->numRects == 1) { // d->qt_rgn->rects is empty, use d->qt_rgn->extents instead const QRect r = d->qt_rgn->extents; RECTL rcl = { r.left(), d->height - (r.bottom() + 1), r.right() + 1, d->height - r.top() }; self->d->rgn = GpiCreateRegion(qt_display_ps(), 1, &rcl); } else { PRECTL rcls = new RECTL[d->qt_rgn->numRects]; for (int i = 0; i < d->qt_rgn->numRects; ++i) { QRect r = d->qt_rgn->rects.at(i); // note RECTL is inclusive-exclusive here rcls[i].xLeft = r.left(); rcls[i].yBottom = d->height - (r.bottom() + 1); rcls[i].xRight = r.right() + 1; rcls[i].yTop = d->height - r.top(); } self->d->rgn = GpiCreateRegion(qt_display_ps(), d->qt_rgn->numRects, rcls); delete[] rcls; } return; } } // create an empty region self->d->rgn = GpiCreateRegion(qt_display_ps(), 0, NULL); }
QRegion::QRegion( const QPointArray &a, bool winding ) { data = new QRegionData; Q_CHECK_PTR( data ); data->hgt = 0; data->is_null = FALSE; QRect r = a.boundingRect(); if ( a.isEmpty() || r.isEmpty() ) { data->rgn = 0; } else { HPS hps = qt_display_ps(); POINTL *pts = new POINTL[ a.size() ]; for ( uint i = 0; i < a.size(); ++ i ) { pts[i].x = a[i].x(); pts[i].y = - (a[i].y() + 1); } // GpiCreatePolygonRegion() is bogus and always starts a poligon from // the current position. Make the last point the current one and reduce // the number of points by one. GpiMove( hps, &pts[ a.size() - 1 ] ); POLYGON poly = { a.size() - 1, pts }; ULONG opts = winding ? POLYGON_WINDING : POLYGON_ALTERNATE; data->rgn = GpiCreatePolygonRegion( hps, 1, &poly, opts ); delete[] pts; } }
QRegion::QRegion( const QRect &r, RegionType t ) { data = new QRegionData; Q_CHECK_PTR( data ); data->hgt = 0; data->is_null = FALSE; if ( r.isEmpty() ) { data->rgn = 0; } else { HPS hps = qt_display_ps(); if ( t == Rectangle ) { // rectangular region RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() }; data->rgn = GpiCreateRegion( hps, 1, &rcl ); } else if ( t == Ellipse ) { // elliptic region // if the width or height of the ellipse is odd, GPI always // converts it to a nearest even value, which is obviously stupid // (see also QPainter::drawArcInternal()). So, we don't use // GpiCreateEllipticRegion(), but create an array of points to // call GpiCreatePolygonRegion() instead. QPointArray a; a.makeArc( r.x(), r.y(), r.width(), r.height(), 0, 360 * 16 ); for ( uint i = 0; i < a.size(); ++ i ) a[i].ry() = -(a[i].y() + 1); // GpiCreatePolygonRegion() is bogus and always starts a poligon from // the current position. Make the last point the current one and reduce // the number of points by one. GpiMove( hps, (PPOINTL) &a[ a.size() - 1 ] ); POLYGON poly = { a.size() - 1, (PPOINTL) a.data() }; data->rgn = GpiCreatePolygonRegion( hps, 1, &poly, POLYGON_ALTERNATE ); } } }
bool QRegion::isEmpty() const { if ( data->is_null || data->rgn == 0 ) return TRUE; RECTL rcl; return GpiQueryRegionBox( qt_display_ps(), data->rgn, &rcl ) == RGN_NULL; }
QMemArray<QRect> QRegion::rects() const { QMemArray<QRect> a; if ( !data->rgn ) return a; HPS hps = qt_display_ps(); RGNRECT ctl = {1, 0, 0, RECTDIR_LFRT_TOPBOT}; if ( !GpiQueryRegionRects( hps, data->rgn, NULL, &ctl, NULL ) ) return a; ctl.crc = ctl.crcReturned; PRECTL rcls = new RECTL[ctl.crcReturned]; if ( !GpiQueryRegionRects( hps, data->rgn, NULL, &ctl, rcls ) ) { delete [] rcls; return a; } a = QMemArray<QRect>( ctl.crcReturned ); PRECTL r = rcls; for ( int i=0; i<(int)a.size(); i++ ) { a[i].setRect( r->xLeft, data->hgt - r->yTop, r->xRight - r->xLeft, r->yTop - r->yBottom ); r++; } delete [] rcls; return a; }
QRegion::~QRegion() { if ( data->deref() ) { if ( data->rgn ) GpiDestroyRegion( qt_display_ps(), data->rgn ); delete data; } }
void QRegion::translate( int dx, int dy ) { if ( !data->rgn ) return; detach(); POINTL ptl = { dx, -dy }; GpiOffsetRegion( qt_display_ps(), data->rgn, &ptl); }
bool QRegion::contains( const QPoint &p ) const { LONG rc = PRGN_OUTSIDE; if ( data->rgn ) { POINTL ptl = { p.x(), data->hgt - (p.y() + 1) }; rc = GpiPtInRegion( qt_display_ps(), data->rgn, &ptl ); } return rc == PRGN_INSIDE; }
bool QRegion::contains( const QRect &r ) const { LONG rc = PRGN_OUTSIDE; if ( data->rgn ) { RECTL rcl = { r.left(), data->hgt - (r.bottom() + 1), r.right() + 1, data->hgt - r.top() }; rc = GpiRectInRegion( qt_display_ps(), data->rgn, &rcl ); } return rc == RRGN_INSIDE || rc == RRGN_PARTIAL; }
QRegion &QRegion::operator=( const QRegion &r ) { r.data->ref(); // beware of r = r if ( data->deref() ) { if ( data->rgn ) GpiDestroyRegion( qt_display_ps(), data->rgn ); delete data; } data = r.data; return *this; }
QRect QRegion::boundingRect() const { RECTL rcl; LONG rc = RGN_NULL; if ( data->rgn ) rc = GpiQueryRegionBox( qt_display_ps(), data->rgn, &rcl ); if ( rc == RGN_NULL || rc == RGN_ERROR ) return QRect(0,0,0,0); else return QRect( rcl.xLeft, data->hgt - rcl.yTop, rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom ); }
QRegion QRegion::copy() const { QRegion r ( data->is_null ); r.data->hgt = 0; if ( !data->is_null && data->rgn ) { HPS hps = qt_display_ps(); r.data->rgn = GpiCreateRegion( hps, 0, NULL ); GpiCombineRegion( hps, r.data->rgn, data->rgn, NULL, CRGN_COPY ); r.data->hgt = data->hgt; } return r; }
bool QRegion::operator==( const QRegion &r ) const { if ( data == r.data ) // share the same data return TRUE; bool is_empty = data->is_null || data->rgn == 0; bool r_is_empty = r.data->is_null || r.data->rgn == 0; if ( (is_empty ^ r_is_empty ) ) // one is empty, not both return FALSE; if ( is_empty ) // both empty return TRUE; updateHandle( r.data->hgt ); // bring to the same coordinate space return GpiEqualRegion( qt_display_ps(), data->rgn, r.data->rgn ) == EQRGN_EQUAL; }
QRegion QRegion::pmCombine( const QRegion &r, int op ) const { LONG both = CRGN_NOP, left = CRGN_NOP, right = CRGN_NOP; switch ( op ) { case QRGN_OR: both = CRGN_OR; left = right = CRGN_COPY; break; case QRGN_AND: both = CRGN_AND; break; case QRGN_SUB: both = CRGN_DIFF; left = CRGN_COPY; break; case QRGN_XOR: both = CRGN_XOR; left = right = CRGN_COPY; break; default: #if defined(QT_CHECK_RANGE) qWarning( "QRegion: Internal error in pmCombine" ); #else ; #endif } QRegion result( FALSE ); if ( !data->rgn && !r.data->rgn ) return result; HPS hps = qt_display_ps(); result.data->rgn = GpiCreateRegion( hps, 0, NULL ); LONG rc = RGN_NULL; if ( data->rgn && r.data->rgn ) { updateHandle( r.data->hgt ); // bring to the same coordinate space rc = GpiCombineRegion( hps, result.data->rgn, data->rgn, r.data->rgn, both ); result.data->hgt = r.data->hgt; } else if ( data->rgn && left != CRGN_NOP ) { rc = GpiCombineRegion( hps, result.data->rgn, data->rgn, 0, left ); result.data->hgt = data->hgt; } else if ( r.data->rgn && right != CRGN_NOP ) { rc = GpiCombineRegion( hps, result.data->rgn, r.data->rgn, 0, right ); result.data->hgt = r.data->hgt; } if ( rc == RGN_NULL || rc == RGN_ERROR ) { GpiDestroyRegion( hps, result.data->rgn ); result.data->rgn = result.data->hgt = 0; } return result; }
/*! \internal Deletes the given region handle. */ void QRegion::disposeHandle(HRGN hrgn) { if (hrgn != 0) GpiDestroyRegion(qt_display_ps(), hrgn); }
HRGN qt_pm_bitmapToRegion( const QBitmap& bitmap ) { HRGN region = 0; QImage image = bitmap.convertToImage(); const int maxrect = 256; RECTL rects[maxrect]; HPS hps = qt_display_ps(); #define FlushSpans \ { \ HRGN r = GpiCreateRegion( hps, n, rects ); \ if ( region ) { \ GpiCombineRegion( hps, region, region, r, CRGN_OR ); \ GpiDestroyRegion( hps, r ); \ } else { \ region = r; \ } \ } #define AddSpan \ { \ rects[n].xLeft = prev1; \ rects[n].yBottom = -(y+1); \ rects[n].xRight = x-1+1; \ rects[n].yTop = -y; \ n++; \ if ( n == maxrect ) { \ FlushSpans \ n = 0; \ } \ } int n = 0; int zero = 0x00; int x, y; for ( y = 0; y < image.height(); y++ ) { uchar *line = image.scanLine(y); int w = image.width(); uchar all = zero; int prev1 = -1; for ( x = 0; x < w; ) { uchar byte = line[x/8]; if ( x > w-8 || byte != all ) { for ( int b = 8; b > 0 && x < w; b-- ) { if ( !(byte & 0x80) == !all ) { // More of the same } else { // A change. if ( all != zero ) { AddSpan; all = zero; } else { prev1 = x; all = ~zero; } } byte <<= 1; x++; } } else { x += 8; } } if ( all != zero ) { AddSpan; } } if ( n ) { FlushSpans; } if ( !region ) region = GpiCreateRegion( hps, 0, NULL ); return region; }