Changeset 561 for trunk/src/gui/painting/qregion_win.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/painting/qregion_win.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** 40 40 ****************************************************************************/ 41 41 42 #include "qatomic.h" 42 43 #include "qbitmap.h" 43 44 #include "qbuffer.h" … … 46 47 #include "qregion.h" 47 48 #include "qt_windows.h" 49 #include "qpainterpath.h" 48 50 49 51 QT_BEGIN_NAMESPACE 50 52 53 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 }; 51 54 52 /*53 In Windows versions before Windows Vista CreateRectRgn - when called in a multi-threaded54 environment - might return an invalid handle. This function works around this limitation55 by verifying the handle with a quick GetRegionData() call and re-creates the region56 if necessary.57 */58 55 HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom) 59 56 { 60 57 const int tries = 10; 61 58 for (int i = 0; i < tries; ++i) { 62 HRGN region ;59 HRGN region = 0; 63 60 switch (type) { 64 61 case QRegion::Rectangle: … … 81 78 } 82 79 83 #ifndef Q_OS_WINCE 84 HRGN qt_tryCreatePolygonRegion(const QPolygon &a, Qt::FillRule fillRule) 80 QRegion qt_region_from_HRGN(HRGN rgn) 85 81 { 86 const int tries = 10; 87 for (int i = 0; i < tries; ++i) { 88 HRGN region = CreatePolygonRgn(reinterpret_cast<const POINT*>(a.data()), a.size(), 89 fillRule == Qt::OddEvenFill ? ALTERNATE : WINDING); 90 if (region) { 91 if (GetRegionData(region, 0, 0)) 92 return region; 93 else 94 DeleteObject(region); 95 } 96 } 97 return 0; 98 } 99 #endif 82 int numBytes = GetRegionData(rgn, 0, 0); 83 if (numBytes == 0) 84 return QRegion(); 100 85 101 QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 }; 86 char *buf = new char[numBytes]; 87 if (buf == 0) 88 return QRegion(); 102 89 103 QRegion::QRegion() 104 : d(&shared_empty) 105 { 106 d->ref.ref(); 107 } 108 109 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp 110 QRegion::QRegion(const QRect &r, RegionType t) 111 { 112 if (r.isEmpty()) { 113 d = &shared_empty; 114 d->ref.ref(); 115 } else { 116 d = new QRegionData; 117 d->ref = 1; 118 if (t == Rectangle) 119 d->rgn = qt_tryCreateRegion(t, r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); 120 else if (t == Ellipse) { 121 // need to add 1 to width/height for the ellipse to have correct boundingrect. 122 d->rgn = qt_tryCreateRegion(t, r.x(), r.y(), r.x() + r.width() + 1, r.y() + r.height() + 1); 123 } 124 } 125 } 126 #endif 127 128 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp 129 QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) 130 { 131 if (a.size() < 3) { 132 d = &shared_empty; 133 d->ref.ref(); 134 } else { 135 d = new QRegionData; 136 d->ref = 1; 137 d->rgn = qt_tryCreatePolygonRegion(a, fillRule); 138 } 139 } 140 #endif 141 142 QRegion::QRegion(const QRegion &r) 143 { 144 d = r.d; 145 d->ref.ref(); 146 } 147 148 HRGN qt_win_bitmapToRegion(const QBitmap& bitmap) 149 { 150 HRGN region=0; 151 QImage image = bitmap.toImage(); 152 const int MAXRECT = 256; 153 struct RData { 154 RGNDATAHEADER header; 155 RECT rect[MAXRECT]; 156 }; 157 RData data; 158 159 #define FlushSpans \ 160 { \ 161 data.header.dwSize = sizeof(RGNDATAHEADER); \ 162 data.header.iType = RDH_RECTANGLES; \ 163 data.header.nCount = n; \ 164 data.header.nRgnSize = 0; \ 165 data.header.rcBound.bottom = y; \ 166 HRGN r = ExtCreateRegion(0, \ 167 sizeof(RGNDATAHEADER)+n*sizeof(RECT),(RGNDATA*)&data); \ 168 if (region) { \ 169 CombineRgn(region, region, r, RGN_OR); \ 170 DeleteObject(r); \ 171 } else { \ 172 region = r; \ 173 } \ 174 data.header.rcBound.top = y; \ 175 } 176 177 #define AddSpan \ 178 { \ 179 data.rect[n].left=prev1; \ 180 data.rect[n].top=y; \ 181 data.rect[n].right=x-1+1; \ 182 data.rect[n].bottom=y+1; \ 183 n++; \ 184 if (n == MAXRECT) { \ 185 FlushSpans \ 186 n=0; \ 187 } \ 188 } 189 190 data.header.rcBound.top = 0; 191 data.header.rcBound.left = 0; 192 data.header.rcBound.right = image.width()-1; 193 int n = 0; 194 195 int zero = 0x00; 196 197 int x, y; 198 for (y = 0; y < image.height(); ++y) { 199 uchar *line = image.scanLine(y); 200 int w = image.width(); 201 uchar all=zero; 202 int prev1 = -1; 203 for (x = 0; x < w;) { 204 uchar byte = line[x/8]; 205 if (x > w - 8 || byte != all) { 206 for (int b = 8; b > 0 && x < w; --b) { 207 if (!(byte & 0x01) == !all) { 208 // More of the same 209 } else { 210 // A change. 211 if (all != zero) { 212 AddSpan; 213 all = zero; 214 } else { 215 prev1 = x; 216 all = ~zero; 217 } 218 } 219 byte >>= 1; 220 ++x; 221 } 222 } else { 223 x += 8; 224 } 225 } 226 if (all != zero) { 227 AddSpan; 228 } 229 } 230 if (n) { 231 FlushSpans; 90 RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf); 91 if (GetRegionData(rgn, numBytes, rd) == 0) { 92 delete [] buf; 93 return QRegion(); 232 94 } 233 95 234 if (!region) { 235 // Surely there is some better way. 236 region = qt_tryCreateRegion(QRegion::Rectangle, 0,0,1,1); 237 CombineRgn(region, region, region, RGN_XOR); 96 QRegion region; 97 RECT *r = reinterpret_cast<RECT*>(rd->Buffer); 98 for (uint i = 0; i < rd->rdh.nCount; ++i) { 99 QRect rect; 100 rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1); 101 ++r; 102 region |= rect; 238 103 } 104 105 delete [] buf; 106 239 107 return region; 240 108 } 241 109 242 #ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp 243 QRegion::QRegion(const QBitmap &bm) 110 void qt_win_dispose_rgn(HRGN r) 244 111 { 245 if (bm.isNull()) { 246 d = &shared_empty; 247 d->ref.ref(); 248 } else { 249 d = new QRegionData; 250 d->ref = 1; 251 d->rgn = qt_win_bitmapToRegion(bm); 252 } 253 } 254 #endif 255 256 void QRegion::cleanUp(QRegion::QRegionData *x) 257 { 258 if (x->rgn) 259 DeleteObject(x->rgn); 260 delete x; 112 if (r) 113 DeleteObject(r); 261 114 } 262 115 263 QRegion::~QRegion()116 static void qt_add_rect(HRGN &winRegion, QRect r) 264 117 { 265 if (!d->ref.deref()) 266 cleanUp(d); 267 } 268 269 QRegion &QRegion::operator=(const QRegion &r) 270 { 271 r.d->ref.ref(); 272 if (!d->ref.deref()) 273 cleanUp(d); 274 d = r.d; 275 return *this; 276 } 277 278 279 QRegion QRegion::copy() const 280 { 281 QRegion r; 282 QRegionData *x = new QRegionData; 283 x->ref = 1; 284 if (d->rgn) { 285 x->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 2, 2); 286 CombineRgn(x->rgn, d->rgn, 0, RGN_COPY); 287 } else { 288 x->rgn = 0; 118 HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height()); 119 if (rgn) { 120 HRGN dest = CreateRectRgn(0,0,0,0); 121 int result = CombineRgn(dest, winRegion, rgn, RGN_OR); 122 if (result) { 123 DeleteObject(winRegion); 124 winRegion = dest; 125 } 126 DeleteObject(rgn); 289 127 } 290 if (!r.d->ref.deref())291 cleanUp(r.d);292 r.d = x;293 return r;294 }295 296 bool QRegion::isEmpty() const297 {298 return (d == &shared_empty || boundingRect().isEmpty());299 }300 301 302 bool QRegion::contains(const QPoint &p) const303 {304 return d->rgn ? PtInRegion(d->rgn, p.x(), p.y()) : false;305 }306 307 bool QRegion::contains(const QRect &r) const308 {309 if (!d->rgn)310 return false;311 RECT rect;312 SetRect(&rect, r.left(), r.top(), r.right(), r.bottom());313 return RectInRegion(d->rgn, &rect);314 }315 316 317 void QRegion::translate(int dx, int dy)318 {319 if (!d->rgn || (dx == 0 && dy == 0))320 return;321 detach();322 OffsetRgn(d->rgn, dx, dy);323 }324 325 326 #define RGN_NOP -1327 328 // Duplicates of those in qregion.cpp329 #define QRGN_OR 6330 #define QRGN_AND 7331 #define QRGN_SUB 8332 #define QRGN_XOR 9333 334 /*335 Performs the actual OR, AND, SUB and XOR operation between regions.336 Sets the resulting region handle to 0 to indicate an empty region.337 */338 339 QRegion QRegion::winCombine(const QRegion &r, int op) const340 {341 int both=RGN_NOP,342 left=RGN_NOP,343 right=RGN_NOP;344 switch (op) {345 case QRGN_OR:346 both = RGN_OR;347 left = right = RGN_COPY;348 break;349 case QRGN_AND:350 both = RGN_AND;351 break;352 case QRGN_SUB:353 both = RGN_DIFF;354 left = RGN_COPY;355 break;356 case QRGN_XOR:357 both = RGN_XOR;358 left = right = RGN_COPY;359 break;360 default:361 qWarning("QRegion: Internal error in winCombine");362 }363 364 int allCombineRgnResults = NULLREGION;365 QRegion result;366 result.detach();367 result.d->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 0, 0);368 if (d->rgn && r.d->rgn)369 allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, r.d->rgn, both);370 else if (d->rgn && left != RGN_NOP)371 allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, d->rgn, left);372 else if (r.d->rgn && right != RGN_NOP)373 allCombineRgnResults = CombineRgn(result.d->rgn, r.d->rgn, r.d->rgn, right);374 375 if (allCombineRgnResults == NULLREGION || allCombineRgnResults == ERROR)376 result = QRegion();377 378 //##### do not delete this. A null pointer is different from an empty region in SelectClipRgn in qpainter_win! (M)379 // if (allCombineRgnResults == NULLREGION) {380 // if (result.data->rgn)381 // DeleteObject(result.data->rgn);382 // result.data->rgn = 0; // empty region383 // }384 return result;385 }386 387 QRegion QRegion::unite(const QRegion &r) const388 {389 if (!d->rgn)390 return r;391 if (!r.d->rgn)392 return *this;393 return winCombine(r, QRGN_OR);394 }395 396 QRegion QRegion::unite(const QRect &r) const397 {398 return unite(QRegion(r));399 }400 401 QRegion QRegion::intersect(const QRegion &r) const402 {403 if (!r.d->rgn || !d->rgn)404 return QRegion();405 return winCombine(r, QRGN_AND);406 }407 408 QRegion QRegion::subtract(const QRegion &r) const409 {410 if (!r.d->rgn || !d->rgn)411 return *this;412 return winCombine(r, QRGN_SUB);413 }414 415 QRegion QRegion::eor(const QRegion &r) const416 {417 if (!d->rgn)418 return r;419 if (!r.d->rgn)420 return *this;421 return winCombine(r, QRGN_XOR);422 }423 424 425 QRect QRegion::boundingRect() const426 {427 if (!d->rgn)428 return QRect();429 RECT r;430 if (GetRgnBox(d->rgn, &r) == NULLREGION)431 return QRect();432 else433 return QRect(r.left, r.top, r.right - r.left, r.bottom - r.top);434 }435 436 QVector<QRect> QRegion::rects() const437 {438 if (d->rgn == 0)439 return QVector<QRect>();440 441 int numBytes = GetRegionData(d->rgn, 0, 0);442 if (numBytes == 0)443 return QVector<QRect>();444 445 char *buf = new char[numBytes];446 if (buf == 0)447 return QVector<QRect>();448 449 RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);450 if (GetRegionData(d->rgn, numBytes, rd) == 0) {451 delete [] buf;452 return QVector<QRect>();453 }454 455 QVector<QRect> a(rd->rdh.nCount);456 RECT *r = reinterpret_cast<RECT*>(rd->Buffer);457 for (int i = 0; i < a.size(); ++i) {458 a[i].setCoords(r->left, r->top, r->right - 1, r->bottom - 1);459 ++r;460 }461 462 delete [] buf;463 return a;464 }465 466 void QRegion::setRects(const QRect *rects, int num)467 {468 *this = QRegion();469 if (!rects || num == 0 || (num == 1 && rects->isEmpty()))470 return;471 for (int i = 0; i < num; ++i)472 *this |= rects[i];473 }474 475 int QRegion::numRects() const476 {477 if (d->rgn == 0)478 return 0;479 480 const int numBytes = GetRegionData(d->rgn, 0, 0);481 if (numBytes == 0)482 return 0;483 484 char *buf = new char[numBytes];485 if (buf == 0)486 return 0;487 488 RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);489 if (GetRegionData(d->rgn, numBytes, rd) == 0) {490 delete[] buf;491 return 0;492 }493 494 const int n = rd->rdh.nCount;495 delete[] buf;496 497 return n;498 }499 500 bool QRegion::operator==(const QRegion &r) const501 {502 if (d == r.d)503 return true;504 if ((d->rgn == 0) ^ (r.d->rgn == 0)) // one is empty, not both505 return false;506 return d->rgn == 0 ? true // both empty507 : EqualRgn(d->rgn, r.d->rgn); // both non-empty508 }509 510 QRegion& QRegion::operator+=(const QRegion &r)511 {512 if (!r.d->rgn)513 return *this;514 515 if (!d->rgn) {516 *this = r;517 return *this;518 }519 520 detach();521 522 int result;523 result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_OR);524 if (result == NULLREGION || result == ERROR)525 *this = QRegion();526 527 return *this;528 }529 530 QRegion& QRegion::operator-=(const QRegion &r)531 {532 if (!r.d->rgn || !d->rgn)533 return *this;534 535 detach();536 537 int result;538 result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_DIFF);539 if (result == NULLREGION || result == ERROR)540 *this = QRegion();541 542 return *this;543 }544 545 QRegion& QRegion::operator&=(const QRegion &r)546 {547 if (!d->rgn)548 return *this;549 550 if (!r.d->rgn) {551 *this = QRegion();552 return *this;553 }554 555 detach();556 557 int result;558 result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_AND);559 if (result == NULLREGION || result == ERROR)560 *this = QRegion();561 562 return *this;563 }564 565 bool qt_region_strictContains(const QRegion ®ion, const QRect &rect)566 {567 Q_UNUSED(region);568 Q_UNUSED(rect);569 return false;570 128 } 571 129 572 130 void QRegion::ensureHandle() const 573 131 { 132 if (d->rgn) 133 DeleteObject(d->rgn); 134 d->rgn = CreateRectRgn(0,0,0,0); 135 if (d->qt_rgn) { 136 if (d->qt_rgn->numRects == 1) { 137 QRect r = d->qt_rgn->extents; 138 qt_add_rect(d->rgn, r); 139 return; 140 } 141 for (int i = 0;i < d->qt_rgn->numRects;i++) { 142 QRect r = d->qt_rgn->rects.at(i); 143 qt_add_rect(d->rgn, r); 144 } 145 } 574 146 } 575 147 148 576 149 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.