- Timestamp:
- Aug 14, 2009, 11:18:30 PM (16 years ago)
- Location:
- trunk/src/gui
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/kernel/qwindowdefs_pm.h
r108 r113 60 60 typedef LHANDLE HPS; 61 61 typedef LHANDLE HPOINTER; 62 typedef LHANDLE HRGN; 62 63 typedef struct _QMSG QMSG; 63 64 typedef void *MRESULT; 64 65 65 66 typedef HWND WId; 67 68 #define NULLHANDLE ((LHANDLE)0) 66 69 67 70 Q_GUI_EXPORT HPS qt_display_ps(); -
trunk/src/gui/painting/qregion.h
r2 r113 144 144 #if defined(Q_WS_WIN) 145 145 inline HRGN handle() const { ensureHandle(); return d->rgn; } 146 #elif defined(Q_WS_PM) 147 inline HRGN handle(int targetHeight = 0) const { 148 if (d->rgn == NULLHANDLE || d->height != targetHeight) 149 updateHandle(targetHeight); 150 return d->rgn; 151 } 146 152 #elif defined(Q_WS_X11) 147 153 inline Region handle() const { if(!d->rgn) updateX11Region(); return d->rgn; } … … 175 181 void ensureHandle() const; 176 182 QRegion winCombine(const QRegion &r, int num) const; 183 #elif defined(Q_WS_PM) 184 QRegion pmCombine(const QRegion &r, int op) const; 185 void updateHandle(int targetHeight) const; 177 186 #elif defined(Q_WS_X11) 178 187 void updateX11Region() const; … … 194 203 #if defined(Q_WS_WIN) 195 204 HRGN rgn; 205 #elif defined(Q_WS_PM) 206 HRGN rgn; 207 int height; 196 208 #elif defined(Q_WS_X11) 197 209 Region rgn; -
trunk/src/gui/painting/qregion_pm.cpp
r100 r113 48 48 #include "qregion.h" 49 49 50 #include "qt_os2.h" 51 50 52 QT_BEGIN_NAMESPACE 51 53 52 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1) }; // @todo, 0 }; 54 // To compensate the difference between Qt (where y axis goes downwards) and 55 // GPI (where y axis goes upwards) coordinate spaces when dealing with regions 56 // we use the following technique: when a GPI resource is allocated for a Qt 57 // region, we simply change the sign of all y coordinates to quickly flip it 58 // top to bottom in a manner that doesn't depend on the target device height. 59 // All we have to do to apply the created GPI region to a particular GPI device 60 // is to align its y axis to the top of the device (i.e. offset the region 61 // up by the height of the device), and unalign it afterwards to bring it back 62 // to the coordinate space of other device-independent (unaligned) regions. 63 // To optimize this, we remember (in data->hgt) the last height value used to 64 // align the region, and align it again only if the target device height 65 // changes. Zero height indicates a device-independent target (such as other 66 // unaligned Qt region). 67 // 68 // The handle() function, used for external access to the region, takes an 69 // 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 84 85 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 86 NULLHANDLE, 0 }; 53 87 54 88 QRegion::QRegion() … … 60 94 QRegion::QRegion(const QRect &r, RegionType t) 61 95 { 62 d = new QRegionData; 63 d->ref = 1; 64 // @todo implement 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 } 65 125 } 66 126 67 127 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) 68 128 { 69 d = new QRegionData; 70 d->ref = 1; 71 // @todo implement 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 } 72 151 } 73 152 … … 78 157 } 79 158 159 static HRGN bitmapToRegion(const QBitmap& bitmap) 160 { 161 HRGN region = 0; 162 QImage image = bitmap.convertToImage(); 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 80 237 QRegion::QRegion(const QBitmap &bm) 81 238 { 82 d = new QRegionData; 83 d->ref = 1; 84 // @todo implement 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 } 85 248 } 86 249 87 250 void QRegion::cleanUp(QRegion::QRegionData *x) 88 251 { 252 if (x->rgn != NULLHANDLE) 253 GpiDestroyRegion(qt_display_ps(), x->rgn); 89 254 delete x; 90 // @todo implement91 255 } 92 256 … … 109 273 QRegion QRegion::copy() const 110 274 { 111 // @todo implement 112 return QRegion(); 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; 113 291 } 114 292 … … 118 296 } 119 297 120 121 298 bool QRegion::contains(const QPoint &p) const 122 299 { 123 // @todo implement 124 return false; 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; 125 306 } 126 307 127 308 bool QRegion::contains(const QRect &r) const 128 309 { 129 // @todo implement 130 return false; 131 } 132 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 } 133 318 134 319 void QRegion::translate(int dx, int dy) 135 320 { 136 // @todo implement 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; 137 386 } 138 387 139 388 QRegion QRegion::unite(const QRegion &r) const 140 389 { 141 // @todo implement 142 return QRegion(); 390 if (d->rgn == NULLHANDLE) 391 return r; 392 if (r.d->rgn == NULLHANDLE) 393 return *this; 394 return pmCombine(r, QRGN_OR); 143 395 } 144 396 … … 150 402 QRegion QRegion::intersect(const QRegion &r) const 151 403 { 152 // @todo implement 153 return QRegion(); 404 if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE) 405 return QRegion(); 406 return pmCombine(r, QRGN_AND); 154 407 } 155 408 156 409 QRegion QRegion::subtract(const QRegion &r) const 157 410 { 158 // @todo implement 159 return QRegion(); 411 if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE) 412 return *this; 413 return pmCombine(r, QRGN_SUB); 160 414 } 161 415 162 416 QRegion QRegion::eor(const QRegion &r) const 163 417 { 164 // @todo implement 165 return QRegion(); 166 } 167 418 if (d->rgn == NULLHANDLE) 419 return r; 420 if (r.d->rgn == NULLHANDLE) 421 return *this; 422 return pmCombine(r, QRGN_XOR); 423 } 168 424 169 425 QRect QRegion::boundingRect() const 170 426 { 171 // @todo implement 172 return QRect(); 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); 173 439 } 174 440 175 441 QVector<QRect> QRegion::rects() const 176 442 { 177 // @todo implement 178 return QVector<QRect>(); 179 } 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 } 180 473 181 474 void QRegion::setRects(const QRect *rects, int num) … … 190 483 int QRegion::numRects() const 191 484 { 192 // @todo implement 193 return 0; 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; 194 493 } 195 494 196 495 bool QRegion::operator==(const QRegion &r) const 197 496 { 198 // @todo implement 199 return false; 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; 200 506 } 201 507 202 508 QRegion& QRegion::operator+=(const QRegion &r) 203 509 { 204 // @todo implement 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); 205 519 return *this; 206 520 } … … 208 522 QRegion& QRegion::operator-=(const QRegion &r) 209 523 { 210 // @todo implement 524 if (r.d->rgn == NULLHANDLE || d->rgn == NULLHANDLE) 525 return *this; 526 527 *this = subtract(r); 211 528 return *this; 212 529 } … … 214 531 QRegion& QRegion::operator&=(const QRegion &r) 215 532 { 216 // @todo implement 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); 217 542 return *this; 218 543 } … … 225 550 } 226 551 552 /*! 553 \internal 554 555 Updates the region handle so that it is suitable for selection to 556 a device with the given \a height. 557 */ 558 void QRegion::updateHandle(int targetHeight) const 559 { 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; 572 } 573 } 574 227 575 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.