Changeset 569 for trunk/src/gui/painting/qregion_pm.cpp
- Timestamp:
- Feb 13, 2010, 6:36:55 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/painting/qregion_pm.cpp
r564 r569 68 68 // The handle() function, used for external access to the region, takes an 69 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 70 // guarantee the correct y axis alignment. 84 71 85 72 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 86 73 NULLHANDLE, 0 }; 87 74 88 QRegion::QRegion() 89 : d(&shared_empty) 75 /*! 76 \internal 77 78 Deletes the given region handle. 79 */ 80 void QRegion::disposeHandle(HRGN hrgn) 90 81 { 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 ®ion, 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); 550 84 } 551 85 … … 558 92 void QRegion::updateHandle(int targetHeight) const 559 93 { 560 QRegion * that= const_cast<QRegion*>(this); // we're const here561 if (d->rgn == NULLHANDLE) { 562 // a handle of a null region is requested, allocate an empty region563 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 device568 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 ; 572 106 } 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 573 131 } 574 132
Note:
See TracChangeset
for help on using the changeset viewer.