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 39 namespace android { 40 // ---------------------------------------------------------------------------- 41 42 enum { 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 Region()51 Region::Region() 52 : mBounds(0,0) 53 { 54 } 55 Region(const Region & rhs)56 Region::Region(const Region& rhs) 57 : mBounds(rhs.mBounds), mStorage(rhs.mStorage) 58 { 59 #if VALIDATE_REGIONS 60 validate(rhs, "rhs copy-ctor"); 61 #endif 62 } 63 Region(const Rect & rhs)64 Region::Region(const Rect& rhs) 65 : mBounds(rhs) 66 { 67 } 68 Region(const void * buffer)69 Region::Region(const void* buffer) 70 { 71 status_t err = read(buffer); 72 ALOGE_IF(err<0, "error %s reading Region from buffer", strerror(err)); 73 } 74 ~Region()75 Region::~Region() 76 { 77 } 78 operator =(const Region & rhs)79 Region& Region::operator = (const Region& rhs) 80 { 81 #if VALIDATE_REGIONS 82 validate(*this, "this->operator="); 83 validate(rhs, "rhs.operator="); 84 #endif 85 mBounds = rhs.mBounds; 86 mStorage = rhs.mStorage; 87 return *this; 88 } 89 makeBoundsSelf()90 Region& Region::makeBoundsSelf() 91 { 92 mStorage.clear(); 93 return *this; 94 } 95 clear()96 void Region::clear() 97 { 98 mBounds.clear(); 99 mStorage.clear(); 100 } 101 set(const Rect & r)102 void Region::set(const Rect& r) 103 { 104 mBounds = r; 105 mStorage.clear(); 106 } 107 set(uint32_t w,uint32_t h)108 void Region::set(uint32_t w, uint32_t h) 109 { 110 mBounds = Rect(int(w), int(h)); 111 mStorage.clear(); 112 } 113 114 // ---------------------------------------------------------------------------- 115 addRectUnchecked(int l,int t,int r,int b)116 void Region::addRectUnchecked(int l, int t, int r, int b) 117 { 118 mStorage.add(Rect(l,t,r,b)); 119 #if VALIDATE_REGIONS 120 validate(*this, "addRectUnchecked"); 121 #endif 122 } 123 124 // ---------------------------------------------------------------------------- 125 orSelf(const Rect & r)126 Region& Region::orSelf(const Rect& r) { 127 return operationSelf(r, op_or); 128 } xorSelf(const Rect & r)129 Region& Region::xorSelf(const Rect& r) { 130 return operationSelf(r, op_xor); 131 } andSelf(const Rect & r)132 Region& Region::andSelf(const Rect& r) { 133 return operationSelf(r, op_and); 134 } subtractSelf(const Rect & r)135 Region& Region::subtractSelf(const Rect& r) { 136 return operationSelf(r, op_nand); 137 } operationSelf(const Rect & r,int op)138 Region& Region::operationSelf(const Rect& r, int op) { 139 Region lhs(*this); 140 boolean_operation(op, *this, lhs, r); 141 return *this; 142 } 143 144 // ---------------------------------------------------------------------------- 145 orSelf(const Region & rhs)146 Region& Region::orSelf(const Region& rhs) { 147 return operationSelf(rhs, op_or); 148 } xorSelf(const Region & rhs)149 Region& Region::xorSelf(const Region& rhs) { 150 return operationSelf(rhs, op_xor); 151 } andSelf(const Region & rhs)152 Region& Region::andSelf(const Region& rhs) { 153 return operationSelf(rhs, op_and); 154 } subtractSelf(const Region & rhs)155 Region& Region::subtractSelf(const Region& rhs) { 156 return operationSelf(rhs, op_nand); 157 } operationSelf(const Region & rhs,int op)158 Region& Region::operationSelf(const Region& rhs, int op) { 159 Region lhs(*this); 160 boolean_operation(op, *this, lhs, rhs); 161 return *this; 162 } 163 translateSelf(int x,int y)164 Region& Region::translateSelf(int x, int y) { 165 if (x|y) translate(*this, x, y); 166 return *this; 167 } 168 169 // ---------------------------------------------------------------------------- 170 merge(const Rect & rhs) const171 const Region Region::merge(const Rect& rhs) const { 172 return operation(rhs, op_or); 173 } mergeExclusive(const Rect & rhs) const174 const Region Region::mergeExclusive(const Rect& rhs) const { 175 return operation(rhs, op_xor); 176 } intersect(const Rect & rhs) const177 const Region Region::intersect(const Rect& rhs) const { 178 return operation(rhs, op_and); 179 } subtract(const Rect & rhs) const180 const Region Region::subtract(const Rect& rhs) const { 181 return operation(rhs, op_nand); 182 } operation(const Rect & rhs,int op) const183 const Region Region::operation(const Rect& rhs, int op) const { 184 Region result; 185 boolean_operation(op, result, *this, rhs); 186 return result; 187 } 188 189 // ---------------------------------------------------------------------------- 190 merge(const Region & rhs) const191 const Region Region::merge(const Region& rhs) const { 192 return operation(rhs, op_or); 193 } mergeExclusive(const Region & rhs) const194 const Region Region::mergeExclusive(const Region& rhs) const { 195 return operation(rhs, op_xor); 196 } intersect(const Region & rhs) const197 const Region Region::intersect(const Region& rhs) const { 198 return operation(rhs, op_and); 199 } subtract(const Region & rhs) const200 const Region Region::subtract(const Region& rhs) const { 201 return operation(rhs, op_nand); 202 } operation(const Region & rhs,int op) const203 const Region Region::operation(const Region& rhs, int op) const { 204 Region result; 205 boolean_operation(op, result, *this, rhs); 206 return result; 207 } 208 translate(int x,int y) const209 const Region Region::translate(int x, int y) const { 210 Region result; 211 translate(result, *this, x, y); 212 return result; 213 } 214 215 // ---------------------------------------------------------------------------- 216 orSelf(const Region & rhs,int dx,int dy)217 Region& Region::orSelf(const Region& rhs, int dx, int dy) { 218 return operationSelf(rhs, dx, dy, op_or); 219 } xorSelf(const Region & rhs,int dx,int dy)220 Region& Region::xorSelf(const Region& rhs, int dx, int dy) { 221 return operationSelf(rhs, dx, dy, op_xor); 222 } andSelf(const Region & rhs,int dx,int dy)223 Region& Region::andSelf(const Region& rhs, int dx, int dy) { 224 return operationSelf(rhs, dx, dy, op_and); 225 } subtractSelf(const Region & rhs,int dx,int dy)226 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { 227 return operationSelf(rhs, dx, dy, op_nand); 228 } operationSelf(const Region & rhs,int dx,int dy,int op)229 Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) { 230 Region lhs(*this); 231 boolean_operation(op, *this, lhs, rhs, dx, dy); 232 return *this; 233 } 234 235 // ---------------------------------------------------------------------------- 236 merge(const Region & rhs,int dx,int dy) const237 const Region Region::merge(const Region& rhs, int dx, int dy) const { 238 return operation(rhs, dx, dy, op_or); 239 } mergeExclusive(const Region & rhs,int dx,int dy) const240 const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { 241 return operation(rhs, dx, dy, op_xor); 242 } intersect(const Region & rhs,int dx,int dy) const243 const Region Region::intersect(const Region& rhs, int dx, int dy) const { 244 return operation(rhs, dx, dy, op_and); 245 } subtract(const Region & rhs,int dx,int dy) const246 const Region Region::subtract(const Region& rhs, int dx, int dy) const { 247 return operation(rhs, dx, dy, op_nand); 248 } operation(const Region & rhs,int dx,int dy,int op) const249 const Region Region::operation(const Region& rhs, int dx, int dy, int op) const { 250 Region result; 251 boolean_operation(op, result, *this, rhs, dx, dy); 252 return result; 253 } 254 255 // ---------------------------------------------------------------------------- 256 257 // This is our region rasterizer, which merges rects and spans together 258 // to obtain an optimal region. 259 class Region::rasterizer : public region_operator<Rect>::region_rasterizer 260 { 261 Rect& bounds; 262 Vector<Rect>& storage; 263 Rect* head; 264 Rect* tail; 265 Vector<Rect> span; 266 Rect* cur; 267 public: rasterizer(Region & reg)268 rasterizer(Region& reg) 269 : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() { 270 bounds.top = bounds.bottom = 0; 271 bounds.left = INT_MAX; 272 bounds.right = INT_MIN; 273 storage.clear(); 274 } 275 ~rasterizer()276 ~rasterizer() { 277 if (span.size()) { 278 flushSpan(); 279 } 280 if (storage.size()) { 281 bounds.top = storage.itemAt(0).top; 282 bounds.bottom = storage.top().bottom; 283 if (storage.size() == 1) { 284 storage.clear(); 285 } 286 } else { 287 bounds.left = 0; 288 bounds.right = 0; 289 } 290 } 291 operator ()(const Rect & rect)292 virtual void operator()(const Rect& rect) { 293 //ALOGD(">>> %3d, %3d, %3d, %3d", 294 // rect.left, rect.top, rect.right, rect.bottom); 295 if (span.size()) { 296 if (cur->top != rect.top) { 297 flushSpan(); 298 } else if (cur->right == rect.left) { 299 cur->right = rect.right; 300 return; 301 } 302 } 303 span.add(rect); 304 cur = span.editArray() + (span.size() - 1); 305 } 306 private: 307 template<typename T> min(T rhs,T lhs)308 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } 309 template<typename T> max(T rhs,T lhs)310 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } flushSpan()311 void flushSpan() { 312 bool merge = false; 313 if (tail-head == ssize_t(span.size())) { 314 Rect const* p = span.editArray(); 315 Rect const* q = head; 316 if (p->top == q->bottom) { 317 merge = true; 318 while (q != tail) { 319 if ((p->left != q->left) || (p->right != q->right)) { 320 merge = false; 321 break; 322 } 323 p++, q++; 324 } 325 } 326 } 327 if (merge) { 328 const int bottom = span[0].bottom; 329 Rect* r = head; 330 while (r != tail) { 331 r->bottom = bottom; 332 r++; 333 } 334 } else { 335 bounds.left = min(span.itemAt(0).left, bounds.left); 336 bounds.right = max(span.top().right, bounds.right); 337 storage.appendVector(span); 338 tail = storage.editArray() + storage.size(); 339 head = tail - span.size(); 340 } 341 span.clear(); 342 } 343 }; 344 validate(const Region & reg,const char * name)345 bool Region::validate(const Region& reg, const char* name) 346 { 347 bool result = true; 348 const_iterator cur = reg.begin(); 349 const_iterator const tail = reg.end(); 350 const_iterator prev = cur++; 351 Rect b(*prev); 352 while (cur != tail) { 353 b.left = b.left < cur->left ? b.left : cur->left; 354 b.top = b.top < cur->top ? b.top : cur->top; 355 b.right = b.right > cur->right ? b.right : cur->right; 356 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; 357 if (cur->top == prev->top) { 358 if (cur->bottom != prev->bottom) { 359 ALOGE("%s: invalid span %p", name, cur); 360 result = false; 361 } else if (cur->left < prev->right) { 362 ALOGE("%s: spans overlap horizontally prev=%p, cur=%p", 363 name, prev, cur); 364 result = false; 365 } 366 } else if (cur->top < prev->bottom) { 367 ALOGE("%s: spans overlap vertically prev=%p, cur=%p", 368 name, prev, cur); 369 result = false; 370 } 371 prev = cur; 372 cur++; 373 } 374 if (b != reg.getBounds()) { 375 result = false; 376 ALOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, 377 b.left, b.top, b.right, b.bottom, 378 reg.getBounds().left, reg.getBounds().top, 379 reg.getBounds().right, reg.getBounds().bottom); 380 } 381 if (result == false) { 382 reg.dump(name); 383 } 384 return result; 385 } 386 boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)387 void Region::boolean_operation(int op, Region& dst, 388 const Region& lhs, 389 const Region& rhs, int dx, int dy) 390 { 391 #if VALIDATE_REGIONS 392 validate(lhs, "boolean_operation (before): lhs"); 393 validate(rhs, "boolean_operation (before): rhs"); 394 validate(dst, "boolean_operation (before): dst"); 395 #endif 396 397 size_t lhs_count; 398 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 399 400 size_t rhs_count; 401 Rect const * const rhs_rects = rhs.getArray(&rhs_count); 402 403 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 404 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); 405 region_operator<Rect> operation(op, lhs_region, rhs_region); 406 { // scope for rasterizer (dtor has side effects) 407 rasterizer r(dst); 408 operation(r); 409 } 410 411 #if VALIDATE_REGIONS 412 validate(lhs, "boolean_operation: lhs"); 413 validate(rhs, "boolean_operation: rhs"); 414 validate(dst, "boolean_operation: dst"); 415 #endif 416 417 #if VALIDATE_WITH_CORECG 418 SkRegion sk_lhs; 419 SkRegion sk_rhs; 420 SkRegion sk_dst; 421 422 for (size_t i=0 ; i<lhs_count ; i++) 423 sk_lhs.op( 424 lhs_rects[i].left + dx, 425 lhs_rects[i].top + dy, 426 lhs_rects[i].right + dx, 427 lhs_rects[i].bottom + dy, 428 SkRegion::kUnion_Op); 429 430 for (size_t i=0 ; i<rhs_count ; i++) 431 sk_rhs.op( 432 rhs_rects[i].left + dx, 433 rhs_rects[i].top + dy, 434 rhs_rects[i].right + dx, 435 rhs_rects[i].bottom + dy, 436 SkRegion::kUnion_Op); 437 438 const char* name = "---"; 439 SkRegion::Op sk_op; 440 switch (op) { 441 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; 442 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; 443 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; 444 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; 445 } 446 sk_dst.op(sk_lhs, sk_rhs, sk_op); 447 448 if (sk_dst.isEmpty() && dst.isEmpty()) 449 return; 450 451 bool same = true; 452 Region::const_iterator head = dst.begin(); 453 Region::const_iterator const tail = dst.end(); 454 SkRegion::Iterator it(sk_dst); 455 while (!it.done()) { 456 if (head != tail) { 457 if ( 458 head->left != it.rect().fLeft || 459 head->top != it.rect().fTop || 460 head->right != it.rect().fRight || 461 head->bottom != it.rect().fBottom 462 ) { 463 same = false; 464 break; 465 } 466 } else { 467 same = false; 468 break; 469 } 470 head++; 471 it.next(); 472 } 473 474 if (head != tail) { 475 same = false; 476 } 477 478 if(!same) { 479 ALOGD("---\nregion boolean %s failed", name); 480 lhs.dump("lhs"); 481 rhs.dump("rhs"); 482 dst.dump("dst"); 483 ALOGD("should be"); 484 SkRegion::Iterator it(sk_dst); 485 while (!it.done()) { 486 ALOGD(" [%3d, %3d, %3d, %3d]", 487 it.rect().fLeft, 488 it.rect().fTop, 489 it.rect().fRight, 490 it.rect().fBottom); 491 it.next(); 492 } 493 } 494 #endif 495 } 496 boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)497 void Region::boolean_operation(int op, Region& dst, 498 const Region& lhs, 499 const Rect& rhs, int dx, int dy) 500 { 501 if (!rhs.isValid()) { 502 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", 503 op, rhs.left, rhs.top, rhs.right, rhs.bottom); 504 return; 505 } 506 507 #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS 508 boolean_operation(op, dst, lhs, Region(rhs), dx, dy); 509 #else 510 size_t lhs_count; 511 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 512 513 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 514 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); 515 region_operator<Rect> operation(op, lhs_region, rhs_region); 516 { // scope for rasterizer (dtor has side effects) 517 rasterizer r(dst); 518 operation(r); 519 } 520 521 #endif 522 } 523 boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs)524 void Region::boolean_operation(int op, Region& dst, 525 const Region& lhs, const Region& rhs) 526 { 527 boolean_operation(op, dst, lhs, rhs, 0, 0); 528 } 529 boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs)530 void Region::boolean_operation(int op, Region& dst, 531 const Region& lhs, const Rect& rhs) 532 { 533 boolean_operation(op, dst, lhs, rhs, 0, 0); 534 } 535 translate(Region & reg,int dx,int dy)536 void Region::translate(Region& reg, int dx, int dy) 537 { 538 if (!reg.isEmpty()) { 539 #if VALIDATE_REGIONS 540 validate(reg, "translate (before)"); 541 #endif 542 reg.mBounds.translate(dx, dy); 543 size_t count = reg.mStorage.size(); 544 Rect* rects = reg.mStorage.editArray(); 545 while (count) { 546 rects->translate(dx, dy); 547 rects++; 548 count--; 549 } 550 #if VALIDATE_REGIONS 551 validate(reg, "translate (after)"); 552 #endif 553 } 554 } 555 translate(Region & dst,const Region & reg,int dx,int dy)556 void Region::translate(Region& dst, const Region& reg, int dx, int dy) 557 { 558 dst = reg; 559 translate(dst, dx, dy); 560 } 561 562 // ---------------------------------------------------------------------------- 563 write(void * buffer,size_t size) const564 ssize_t Region::write(void* buffer, size_t size) const 565 { 566 #if VALIDATE_REGIONS 567 validate(*this, "write(buffer)"); 568 #endif 569 const size_t count = mStorage.size(); 570 const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect); 571 if (buffer != NULL) { 572 if (sizeNeeded > size) return NO_MEMORY; 573 int32_t* const p = static_cast<int32_t*>(buffer); 574 *p = count; 575 memcpy(p+1, &mBounds, sizeof(Rect)); 576 if (count) { 577 memcpy(p+5, mStorage.array(), count*sizeof(Rect)); 578 } 579 } 580 return ssize_t(sizeNeeded); 581 } 582 read(const void * buffer)583 ssize_t Region::read(const void* buffer) 584 { 585 int32_t const* const p = static_cast<int32_t const*>(buffer); 586 const size_t count = *p; 587 memcpy(&mBounds, p+1, sizeof(Rect)); 588 mStorage.clear(); 589 if (count) { 590 mStorage.insertAt(0, count); 591 memcpy(mStorage.editArray(), p+5, count*sizeof(Rect)); 592 } 593 #if VALIDATE_REGIONS 594 validate(*this, "read(buffer)"); 595 #endif 596 return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect)); 597 } 598 writeEmpty(void * buffer,size_t size)599 ssize_t Region::writeEmpty(void* buffer, size_t size) 600 { 601 const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect); 602 if (sizeNeeded > size) return NO_MEMORY; 603 int32_t* const p = static_cast<int32_t*>(buffer); 604 memset(p, 0, sizeNeeded); 605 return ssize_t(sizeNeeded); 606 } 607 isEmpty(void * buffer)608 bool Region::isEmpty(void* buffer) 609 { 610 int32_t const* const p = static_cast<int32_t const*>(buffer); 611 Rect const* const b = reinterpret_cast<Rect const *>(p+1); 612 return b->isEmpty(); 613 } 614 615 // ---------------------------------------------------------------------------- 616 begin() const617 Region::const_iterator Region::begin() const { 618 return isRect() ? &mBounds : mStorage.array(); 619 } 620 end() const621 Region::const_iterator Region::end() const { 622 if (isRect()) { 623 if (isEmpty()) { 624 return &mBounds; 625 } else { 626 return &mBounds + 1; 627 } 628 } else { 629 return mStorage.array() + mStorage.size(); 630 } 631 } 632 getArray(size_t * count) const633 Rect const* Region::getArray(size_t* count) const { 634 const_iterator const b(begin()); 635 const_iterator const e(end()); 636 if (count) *count = e-b; 637 return b; 638 } 639 getRects(Vector<Rect> & rectList) const640 size_t Region::getRects(Vector<Rect>& rectList) const 641 { 642 rectList = mStorage; 643 if (rectList.isEmpty()) { 644 rectList.clear(); 645 rectList.add(mBounds); 646 } 647 return rectList.size(); 648 } 649 650 // ---------------------------------------------------------------------------- 651 dump(String8 & out,const char * what,uint32_t flags) const652 void Region::dump(String8& out, const char* what, uint32_t flags) const 653 { 654 (void)flags; 655 const_iterator head = begin(); 656 const_iterator const tail = end(); 657 658 size_t SIZE = 256; 659 char buffer[SIZE]; 660 661 snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", 662 what, this, tail-head); 663 out.append(buffer); 664 while (head != tail) { 665 snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n", 666 head->left, head->top, head->right, head->bottom); 667 out.append(buffer); 668 head++; 669 } 670 } 671 dump(const char * what,uint32_t flags) const672 void Region::dump(const char* what, uint32_t flags) const 673 { 674 (void)flags; 675 const_iterator head = begin(); 676 const_iterator const tail = end(); 677 ALOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head); 678 while (head != tail) { 679 ALOGD(" [%3d, %3d, %3d, %3d]\n", 680 head->left, head->top, head->right, head->bottom); 681 head++; 682 } 683 } 684 685 // ---------------------------------------------------------------------------- 686 687 }; // namespace android 688