Region.cpp revision 2401ead70099c982796ecc3ec63ec8a5570948fc
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "Region" 18 19#include <limits.h> 20 21#include <utils/Log.h> 22#include <utils/String8.h> 23 24#include <ui/Rect.h> 25#include <ui/Region.h> 26#include <ui/Point.h> 27 28#include <private/ui/RegionHelper.h> 29 30// ---------------------------------------------------------------------------- 31#define VALIDATE_REGIONS (false) 32#define VALIDATE_WITH_CORECG (false) 33// ---------------------------------------------------------------------------- 34 35#if VALIDATE_WITH_CORECG 36#include <core/SkRegion.h> 37#endif 38 39namespace android { 40// ---------------------------------------------------------------------------- 41 42enum { 43 op_nand = region_operator<Rect>::op_nand, 44 op_and = region_operator<Rect>::op_and, 45 op_or = region_operator<Rect>::op_or, 46 op_xor = region_operator<Rect>::op_xor 47}; 48 49// ---------------------------------------------------------------------------- 50 51Region::Region() { 52 mStorage.add(Rect(0,0)); 53} 54 55Region::Region(const Region& rhs) 56 : mStorage(rhs.mStorage) 57{ 58#if VALIDATE_REGIONS 59 validate(rhs, "rhs copy-ctor"); 60#endif 61} 62 63Region::Region(const Rect& rhs) { 64 mStorage.add(rhs); 65} 66 67Region::~Region() 68{ 69} 70 71Region& Region::operator = (const Region& rhs) 72{ 73#if VALIDATE_REGIONS 74 validate(*this, "this->operator="); 75 validate(rhs, "rhs.operator="); 76#endif 77 mStorage = rhs.mStorage; 78 return *this; 79} 80 81Region& Region::makeBoundsSelf() 82{ 83 if (mStorage.size() >= 2) { 84 const Rect bounds(getBounds()); 85 mStorage.clear(); 86 mStorage.add(bounds); 87 } 88 return *this; 89} 90 91void Region::clear() 92{ 93 mStorage.clear(); 94 mStorage.add(Rect(0,0)); 95} 96 97void Region::set(const Rect& r) 98{ 99 mStorage.clear(); 100 mStorage.add(r); 101} 102 103void Region::set(uint32_t w, uint32_t h) 104{ 105 mStorage.clear(); 106 mStorage.add(Rect(w,h)); 107} 108 109// ---------------------------------------------------------------------------- 110 111void Region::addRectUnchecked(int l, int t, int r, int b) 112{ 113 Rect rect(l,t,r,b); 114 size_t where = mStorage.size() - 1; 115 mStorage.insertAt(rect, where, 1); 116 117#if VALIDATE_REGIONS 118 validate(*this, "addRectUnchecked"); 119#endif 120} 121 122// ---------------------------------------------------------------------------- 123 124Region& Region::orSelf(const Rect& r) { 125 return operationSelf(r, op_or); 126} 127Region& Region::xorSelf(const Rect& r) { 128 return operationSelf(r, op_xor); 129} 130Region& Region::andSelf(const Rect& r) { 131 return operationSelf(r, op_and); 132} 133Region& Region::subtractSelf(const Rect& r) { 134 return operationSelf(r, op_nand); 135} 136Region& Region::operationSelf(const Rect& r, int op) { 137 Region lhs(*this); 138 boolean_operation(op, *this, lhs, r); 139 return *this; 140} 141 142// ---------------------------------------------------------------------------- 143 144Region& Region::orSelf(const Region& rhs) { 145 return operationSelf(rhs, op_or); 146} 147Region& Region::xorSelf(const Region& rhs) { 148 return operationSelf(rhs, op_xor); 149} 150Region& Region::andSelf(const Region& rhs) { 151 return operationSelf(rhs, op_and); 152} 153Region& Region::subtractSelf(const Region& rhs) { 154 return operationSelf(rhs, op_nand); 155} 156Region& Region::operationSelf(const Region& rhs, int op) { 157 Region lhs(*this); 158 boolean_operation(op, *this, lhs, rhs); 159 return *this; 160} 161 162Region& Region::translateSelf(int x, int y) { 163 if (x|y) translate(*this, x, y); 164 return *this; 165} 166 167// ---------------------------------------------------------------------------- 168 169const Region Region::merge(const Rect& rhs) const { 170 return operation(rhs, op_or); 171} 172const Region Region::mergeExclusive(const Rect& rhs) const { 173 return operation(rhs, op_xor); 174} 175const Region Region::intersect(const Rect& rhs) const { 176 return operation(rhs, op_and); 177} 178const Region Region::subtract(const Rect& rhs) const { 179 return operation(rhs, op_nand); 180} 181const Region Region::operation(const Rect& rhs, int op) const { 182 Region result; 183 boolean_operation(op, result, *this, rhs); 184 return result; 185} 186 187// ---------------------------------------------------------------------------- 188 189const Region Region::merge(const Region& rhs) const { 190 return operation(rhs, op_or); 191} 192const Region Region::mergeExclusive(const Region& rhs) const { 193 return operation(rhs, op_xor); 194} 195const Region Region::intersect(const Region& rhs) const { 196 return operation(rhs, op_and); 197} 198const Region Region::subtract(const Region& rhs) const { 199 return operation(rhs, op_nand); 200} 201const Region Region::operation(const Region& rhs, int op) const { 202 Region result; 203 boolean_operation(op, result, *this, rhs); 204 return result; 205} 206 207const Region Region::translate(int x, int y) const { 208 Region result; 209 translate(result, *this, x, y); 210 return result; 211} 212 213// ---------------------------------------------------------------------------- 214 215Region& Region::orSelf(const Region& rhs, int dx, int dy) { 216 return operationSelf(rhs, dx, dy, op_or); 217} 218Region& Region::xorSelf(const Region& rhs, int dx, int dy) { 219 return operationSelf(rhs, dx, dy, op_xor); 220} 221Region& Region::andSelf(const Region& rhs, int dx, int dy) { 222 return operationSelf(rhs, dx, dy, op_and); 223} 224Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { 225 return operationSelf(rhs, dx, dy, op_nand); 226} 227Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) { 228 Region lhs(*this); 229 boolean_operation(op, *this, lhs, rhs, dx, dy); 230 return *this; 231} 232 233// ---------------------------------------------------------------------------- 234 235const Region Region::merge(const Region& rhs, int dx, int dy) const { 236 return operation(rhs, dx, dy, op_or); 237} 238const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { 239 return operation(rhs, dx, dy, op_xor); 240} 241const Region Region::intersect(const Region& rhs, int dx, int dy) const { 242 return operation(rhs, dx, dy, op_and); 243} 244const Region Region::subtract(const Region& rhs, int dx, int dy) const { 245 return operation(rhs, dx, dy, op_nand); 246} 247const Region Region::operation(const Region& rhs, int dx, int dy, int op) const { 248 Region result; 249 boolean_operation(op, result, *this, rhs, dx, dy); 250 return result; 251} 252 253// ---------------------------------------------------------------------------- 254 255// This is our region rasterizer, which merges rects and spans together 256// to obtain an optimal region. 257class Region::rasterizer : public region_operator<Rect>::region_rasterizer 258{ 259 Rect bounds; 260 Vector<Rect>& storage; 261 Rect* head; 262 Rect* tail; 263 Vector<Rect> span; 264 Rect* cur; 265public: 266 rasterizer(Region& reg) 267 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { 268 storage.clear(); 269 } 270 271 ~rasterizer() { 272 if (span.size()) { 273 flushSpan(); 274 } 275 if (storage.size()) { 276 bounds.top = storage.itemAt(0).top; 277 bounds.bottom = storage.top().bottom; 278 if (storage.size() == 1) { 279 storage.clear(); 280 } 281 } else { 282 bounds.left = 0; 283 bounds.right = 0; 284 } 285 storage.add(bounds); 286 } 287 288 virtual void operator()(const Rect& rect) { 289 //ALOGD(">>> %3d, %3d, %3d, %3d", 290 // rect.left, rect.top, rect.right, rect.bottom); 291 if (span.size()) { 292 if (cur->top != rect.top) { 293 flushSpan(); 294 } else if (cur->right == rect.left) { 295 cur->right = rect.right; 296 return; 297 } 298 } 299 span.add(rect); 300 cur = span.editArray() + (span.size() - 1); 301 } 302private: 303 template<typename T> 304 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } 305 template<typename T> 306 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } 307 void flushSpan() { 308 bool merge = false; 309 if (tail-head == ssize_t(span.size())) { 310 Rect const* p = span.editArray(); 311 Rect const* q = head; 312 if (p->top == q->bottom) { 313 merge = true; 314 while (q != tail) { 315 if ((p->left != q->left) || (p->right != q->right)) { 316 merge = false; 317 break; 318 } 319 p++, q++; 320 } 321 } 322 } 323 if (merge) { 324 const int bottom = span[0].bottom; 325 Rect* r = head; 326 while (r != tail) { 327 r->bottom = bottom; 328 r++; 329 } 330 } else { 331 bounds.left = min(span.itemAt(0).left, bounds.left); 332 bounds.right = max(span.top().right, bounds.right); 333 storage.appendVector(span); 334 tail = storage.editArray() + storage.size(); 335 head = tail - span.size(); 336 } 337 span.clear(); 338 } 339}; 340 341bool Region::validate(const Region& reg, const char* name) 342{ 343 bool result = true; 344 const_iterator cur = reg.begin(); 345 const_iterator const tail = reg.end(); 346 const_iterator prev = cur++; 347 Rect b(*prev); 348 while (cur != tail) { 349 b.left = b.left < cur->left ? b.left : cur->left; 350 b.top = b.top < cur->top ? b.top : cur->top; 351 b.right = b.right > cur->right ? b.right : cur->right; 352 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; 353 if (cur->top == prev->top) { 354 if (cur->bottom != prev->bottom) { 355 ALOGE("%s: invalid span %p", name, cur); 356 result = false; 357 } else if (cur->left < prev->right) { 358 ALOGE("%s: spans overlap horizontally prev=%p, cur=%p", 359 name, prev, cur); 360 result = false; 361 } 362 } else if (cur->top < prev->bottom) { 363 ALOGE("%s: spans overlap vertically prev=%p, cur=%p", 364 name, prev, cur); 365 result = false; 366 } 367 prev = cur; 368 cur++; 369 } 370 if (b != reg.getBounds()) { 371 result = false; 372 ALOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, 373 b.left, b.top, b.right, b.bottom, 374 reg.getBounds().left, reg.getBounds().top, 375 reg.getBounds().right, reg.getBounds().bottom); 376 } 377 if (reg.mStorage.size() == 2) { 378 ALOGE("mStorage size is 2, which is never valid"); 379 } 380 if (result == false) { 381 reg.dump(name); 382 } 383 return result; 384} 385 386void Region::boolean_operation(int op, Region& dst, 387 const Region& lhs, 388 const Region& rhs, int dx, int dy) 389{ 390#if VALIDATE_REGIONS 391 validate(lhs, "boolean_operation (before): lhs"); 392 validate(rhs, "boolean_operation (before): rhs"); 393 validate(dst, "boolean_operation (before): dst"); 394#endif 395 396 size_t lhs_count; 397 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 398 399 size_t rhs_count; 400 Rect const * const rhs_rects = rhs.getArray(&rhs_count); 401 402 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 403 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); 404 region_operator<Rect> operation(op, lhs_region, rhs_region); 405 { // scope for rasterizer (dtor has side effects) 406 rasterizer r(dst); 407 operation(r); 408 } 409 410#if VALIDATE_REGIONS 411 validate(lhs, "boolean_operation: lhs"); 412 validate(rhs, "boolean_operation: rhs"); 413 validate(dst, "boolean_operation: dst"); 414#endif 415 416#if VALIDATE_WITH_CORECG 417 SkRegion sk_lhs; 418 SkRegion sk_rhs; 419 SkRegion sk_dst; 420 421 for (size_t i=0 ; i<lhs_count ; i++) 422 sk_lhs.op( 423 lhs_rects[i].left + dx, 424 lhs_rects[i].top + dy, 425 lhs_rects[i].right + dx, 426 lhs_rects[i].bottom + dy, 427 SkRegion::kUnion_Op); 428 429 for (size_t i=0 ; i<rhs_count ; i++) 430 sk_rhs.op( 431 rhs_rects[i].left + dx, 432 rhs_rects[i].top + dy, 433 rhs_rects[i].right + dx, 434 rhs_rects[i].bottom + dy, 435 SkRegion::kUnion_Op); 436 437 const char* name = "---"; 438 SkRegion::Op sk_op; 439 switch (op) { 440 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; 441 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; 442 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; 443 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; 444 } 445 sk_dst.op(sk_lhs, sk_rhs, sk_op); 446 447 if (sk_dst.isEmpty() && dst.isEmpty()) 448 return; 449 450 bool same = true; 451 Region::const_iterator head = dst.begin(); 452 Region::const_iterator const tail = dst.end(); 453 SkRegion::Iterator it(sk_dst); 454 while (!it.done()) { 455 if (head != tail) { 456 if ( 457 head->left != it.rect().fLeft || 458 head->top != it.rect().fTop || 459 head->right != it.rect().fRight || 460 head->bottom != it.rect().fBottom 461 ) { 462 same = false; 463 break; 464 } 465 } else { 466 same = false; 467 break; 468 } 469 head++; 470 it.next(); 471 } 472 473 if (head != tail) { 474 same = false; 475 } 476 477 if(!same) { 478 ALOGD("---\nregion boolean %s failed", name); 479 lhs.dump("lhs"); 480 rhs.dump("rhs"); 481 dst.dump("dst"); 482 ALOGD("should be"); 483 SkRegion::Iterator it(sk_dst); 484 while (!it.done()) { 485 ALOGD(" [%3d, %3d, %3d, %3d]", 486 it.rect().fLeft, 487 it.rect().fTop, 488 it.rect().fRight, 489 it.rect().fBottom); 490 it.next(); 491 } 492 } 493#endif 494} 495 496void Region::boolean_operation(int op, Region& dst, 497 const Region& lhs, 498 const Rect& rhs, int dx, int dy) 499{ 500 if (!rhs.isValid()) { 501 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", 502 op, rhs.left, rhs.top, rhs.right, rhs.bottom); 503 return; 504 } 505 506#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS 507 boolean_operation(op, dst, lhs, Region(rhs), dx, dy); 508#else 509 size_t lhs_count; 510 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 511 512 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 513 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); 514 region_operator<Rect> operation(op, lhs_region, rhs_region); 515 { // scope for rasterizer (dtor has side effects) 516 rasterizer r(dst); 517 operation(r); 518 } 519 520#endif 521} 522 523void Region::boolean_operation(int op, Region& dst, 524 const Region& lhs, const Region& rhs) 525{ 526 boolean_operation(op, dst, lhs, rhs, 0, 0); 527} 528 529void Region::boolean_operation(int op, Region& dst, 530 const Region& lhs, const Rect& rhs) 531{ 532 boolean_operation(op, dst, lhs, rhs, 0, 0); 533} 534 535void Region::translate(Region& reg, int dx, int dy) 536{ 537 if ((dx || dy) && !reg.isEmpty()) { 538#if VALIDATE_REGIONS 539 validate(reg, "translate (before)"); 540#endif 541 size_t count = reg.mStorage.size(); 542 Rect* rects = reg.mStorage.editArray(); 543 while (count) { 544 rects->translate(dx, dy); 545 rects++; 546 count--; 547 } 548#if VALIDATE_REGIONS 549 validate(reg, "translate (after)"); 550#endif 551 } 552} 553 554void Region::translate(Region& dst, const Region& reg, int dx, int dy) 555{ 556 dst = reg; 557 translate(dst, dx, dy); 558} 559 560// ---------------------------------------------------------------------------- 561 562size_t Region::getSize() const { 563 return mStorage.size() * sizeof(Rect); 564} 565 566status_t Region::flatten(void* buffer) const { 567 Rect* rects = reinterpret_cast<Rect*>(buffer); 568 memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect)); 569 return NO_ERROR; 570} 571 572status_t Region::unflatten(void const* buffer, size_t size) { 573 mStorage.clear(); 574 if (size >= sizeof(Rect)) { 575 Rect const* rects = reinterpret_cast<Rect const*>(buffer); 576 size_t count = size / sizeof(Rect); 577 if (count > 0) { 578 ssize_t err = mStorage.insertAt(0, count); 579 if (err < 0) { 580 return status_t(err); 581 } 582 memcpy(mStorage.editArray(), rects, count*sizeof(Rect)); 583 } 584 } 585#if VALIDATE_REGIONS 586 validate(*this, "Region::unflatten"); 587#endif 588 return NO_ERROR; 589} 590 591// ---------------------------------------------------------------------------- 592 593Region::const_iterator Region::begin() const { 594 return mStorage.array(); 595} 596 597Region::const_iterator Region::end() const { 598 size_t numRects = isRect() ? 1 : mStorage.size() - 1; 599 return mStorage.array() + numRects; 600} 601 602Rect const* Region::getArray(size_t* count) const { 603 const_iterator const b(begin()); 604 const_iterator const e(end()); 605 if (count) *count = e-b; 606 return b; 607} 608 609SharedBuffer const* Region::getSharedBuffer(size_t* count) const { 610 // We can get to the SharedBuffer of a Vector<Rect> because Rect has 611 // a trivial destructor. 612 SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array()); 613 if (count) { 614 size_t numRects = isRect() ? 1 : mStorage.size() - 1; 615 count[0] = numRects; 616 } 617 sb->acquire(); 618 return sb; 619} 620 621// ---------------------------------------------------------------------------- 622 623void Region::dump(String8& out, const char* what, uint32_t flags) const 624{ 625 (void)flags; 626 const_iterator head = begin(); 627 const_iterator const tail = end(); 628 629 size_t SIZE = 256; 630 char buffer[SIZE]; 631 632 snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", 633 what, this, tail-head); 634 out.append(buffer); 635 while (head != tail) { 636 snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n", 637 head->left, head->top, head->right, head->bottom); 638 out.append(buffer); 639 head++; 640 } 641} 642 643void Region::dump(const char* what, uint32_t flags) const 644{ 645 (void)flags; 646 const_iterator head = begin(); 647 const_iterator const tail = end(); 648 ALOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head); 649 while (head != tail) { 650 ALOGD(" [%3d, %3d, %3d, %3d]\n", 651 head->left, head->top, head->right, head->bottom); 652 head++; 653 } 654} 655 656// ---------------------------------------------------------------------------- 657 658}; // namespace android 659