Changeset 113 for trunk/src/gui/painting/qregion_pm.cpp
- Timestamp:
- Aug 14, 2009, 11:18:30 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/painting/qregion_pm.cpp
r100 r113 48 48 #include "qregion.h" 49 49 50 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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 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 253 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 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 227 575 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.