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 <inttypes.h> 20 #include <limits.h> 21 22 #include <utils/Log.h> 23 #include <utils/String8.h> 24 #include <utils/CallStack.h> 25 26 #include <ui/Rect.h> 27 #include <ui/Region.h> 28 #include <ui/Point.h> 29 30 #include <private/ui/RegionHelper.h> 31 32 // ---------------------------------------------------------------------------- 33 #define VALIDATE_REGIONS (false) 34 #define VALIDATE_WITH_CORECG (false) 35 // ---------------------------------------------------------------------------- 36 37 #if VALIDATE_WITH_CORECG 38 #include <core/SkRegion.h> 39 #endif 40 41 namespace android { 42 // ---------------------------------------------------------------------------- 43 44 enum { 45 op_nand = region_operator<Rect>::op_nand, 46 op_and = region_operator<Rect>::op_and, 47 op_or = region_operator<Rect>::op_or, 48 op_xor = region_operator<Rect>::op_xor 49 }; 50 51 enum { 52 direction_LTR, 53 direction_RTL 54 }; 55 56 const Region Region::INVALID_REGION(Rect::INVALID_RECT); 57 58 // ---------------------------------------------------------------------------- 59 60 Region::Region() { 61 mStorage.add(Rect(0,0)); 62 } 63 64 Region::Region(const Region& rhs) 65 : mStorage(rhs.mStorage) 66 { 67 #if VALIDATE_REGIONS 68 validate(rhs, "rhs copy-ctor"); 69 #endif 70 } 71 72 Region::Region(const Rect& rhs) { 73 mStorage.add(rhs); 74 } 75 76 Region::~Region() 77 { 78 } 79 80 /** 81 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way 82 * 83 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst 84 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be 85 * compared with the span directly below, and subdivided as needed to resolve T-junctions. 86 * 87 * The resulting temporary vector will be a completely reversed copy of the original, without any 88 * bottom-up T-junctions. 89 * 90 * Second pass through, divideSpanRTL will be false since the previous span will index into the 91 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly 92 * above it, and subdivided to resolve any remaining T-junctions. 93 */ 94 static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, 95 Vector<Rect>& dst, int spanDirection) { 96 dst.clear(); 97 98 const Rect* current = end - 1; 99 int lastTop = current->top; 100 101 // add first span immediately 102 do { 103 dst.add(*current); 104 current--; 105 } while (current->top == lastTop && current >= begin); 106 107 int beginLastSpan = -1; 108 int endLastSpan = -1; 109 int top = -1; 110 int bottom = -1; 111 112 // for all other spans, split if a t-junction exists in the span directly above 113 while (current >= begin) { 114 if (current->top != (current + 1)->top) { 115 // new span 116 if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) || 117 (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) { 118 // previous span not directly adjacent, don't check for T junctions 119 beginLastSpan = INT_MAX; 120 } else { 121 beginLastSpan = endLastSpan + 1; 122 } 123 endLastSpan = static_cast<int>(dst.size()) - 1; 124 125 top = current->top; 126 bottom = current->bottom; 127 } 128 int left = current->left; 129 int right = current->right; 130 131 for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { 132 // prevIndex can't be -1 here because if endLastSpan is set to a 133 // value greater than -1 (allowing the loop to execute), 134 // beginLastSpan (and therefore prevIndex) will also be increased 135 const Rect prev = dst[static_cast<size_t>(prevIndex)]; 136 if (spanDirection == direction_RTL) { 137 // iterating over previous span RTL, quit if it's too far left 138 if (prev.right <= left) break; 139 140 if (prev.right > left && prev.right < right) { 141 dst.add(Rect(prev.right, top, right, bottom)); 142 right = prev.right; 143 } 144 145 if (prev.left > left && prev.left < right) { 146 dst.add(Rect(prev.left, top, right, bottom)); 147 right = prev.left; 148 } 149 150 // if an entry in the previous span is too far right, nothing further left in the 151 // current span will need it 152 if (prev.left >= right) { 153 beginLastSpan = prevIndex; 154 } 155 } else { 156 // iterating over previous span LTR, quit if it's too far right 157 if (prev.left >= right) break; 158 159 if (prev.left > left && prev.left < right) { 160 dst.add(Rect(left, top, prev.left, bottom)); 161 left = prev.left; 162 } 163 164 if (prev.right > left && prev.right < right) { 165 dst.add(Rect(left, top, prev.right, bottom)); 166 left = prev.right; 167 } 168 // if an entry in the previous span is too far left, nothing further right in the 169 // current span will need it 170 if (prev.right <= left) { 171 beginLastSpan = prevIndex; 172 } 173 } 174 } 175 176 if (left < right) { 177 dst.add(Rect(left, top, right, bottom)); 178 } 179 180 current--; 181 } 182 } 183 184 /** 185 * Creates a new region with the same data as the argument, but divides rectangles as necessary to 186 * remove T-Junctions 187 * 188 * Note: the output will not necessarily be a very efficient representation of the region, since it 189 * may be that a triangle-based approach would generate significantly simpler geometry 190 */ 191 Region Region::createTJunctionFreeRegion(const Region& r) { 192 if (r.isEmpty()) return r; 193 if (r.isRect()) return r; 194 195 Vector<Rect> reversed; 196 reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); 197 198 Region outputRegion; 199 reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), 200 outputRegion.mStorage, direction_LTR); 201 outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds 202 203 #if VALIDATE_REGIONS 204 validate(outputRegion, "T-Junction free region"); 205 #endif 206 207 return outputRegion; 208 } 209 210 Region& Region::operator = (const Region& rhs) 211 { 212 #if VALIDATE_REGIONS 213 validate(*this, "this->operator="); 214 validate(rhs, "rhs.operator="); 215 #endif 216 mStorage = rhs.mStorage; 217 return *this; 218 } 219 220 Region& Region::makeBoundsSelf() 221 { 222 if (mStorage.size() >= 2) { 223 const Rect bounds(getBounds()); 224 mStorage.clear(); 225 mStorage.add(bounds); 226 } 227 return *this; 228 } 229 230 bool Region::contains(const Point& point) const { 231 return contains(point.x, point.y); 232 } 233 234 bool Region::contains(int x, int y) const { 235 const_iterator cur = begin(); 236 const_iterator const tail = end(); 237 while (cur != tail) { 238 if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) { 239 return true; 240 } 241 cur++; 242 } 243 return false; 244 } 245 246 void Region::clear() 247 { 248 mStorage.clear(); 249 mStorage.add(Rect(0,0)); 250 } 251 252 void Region::set(const Rect& r) 253 { 254 mStorage.clear(); 255 mStorage.add(r); 256 } 257 258 void Region::set(int32_t w, int32_t h) 259 { 260 mStorage.clear(); 261 mStorage.add(Rect(w, h)); 262 } 263 264 void Region::set(uint32_t w, uint32_t h) 265 { 266 mStorage.clear(); 267 mStorage.add(Rect(w, h)); 268 } 269 270 bool Region::isTriviallyEqual(const Region& region) const { 271 return begin() == region.begin(); 272 } 273 274 // ---------------------------------------------------------------------------- 275 276 void Region::addRectUnchecked(int l, int t, int r, int b) 277 { 278 Rect rect(l,t,r,b); 279 size_t where = mStorage.size() - 1; 280 mStorage.insertAt(rect, where, 1); 281 } 282 283 // ---------------------------------------------------------------------------- 284 285 Region& Region::orSelf(const Rect& r) { 286 return operationSelf(r, op_or); 287 } 288 Region& Region::xorSelf(const Rect& r) { 289 return operationSelf(r, op_xor); 290 } 291 Region& Region::andSelf(const Rect& r) { 292 return operationSelf(r, op_and); 293 } 294 Region& Region::subtractSelf(const Rect& r) { 295 return operationSelf(r, op_nand); 296 } 297 Region& Region::operationSelf(const Rect& r, uint32_t op) { 298 Region lhs(*this); 299 boolean_operation(op, *this, lhs, r); 300 return *this; 301 } 302 303 // ---------------------------------------------------------------------------- 304 305 Region& Region::orSelf(const Region& rhs) { 306 return operationSelf(rhs, op_or); 307 } 308 Region& Region::xorSelf(const Region& rhs) { 309 return operationSelf(rhs, op_xor); 310 } 311 Region& Region::andSelf(const Region& rhs) { 312 return operationSelf(rhs, op_and); 313 } 314 Region& Region::subtractSelf(const Region& rhs) { 315 return operationSelf(rhs, op_nand); 316 } 317 Region& Region::operationSelf(const Region& rhs, uint32_t op) { 318 Region lhs(*this); 319 boolean_operation(op, *this, lhs, rhs); 320 return *this; 321 } 322 323 Region& Region::translateSelf(int x, int y) { 324 if (x|y) translate(*this, x, y); 325 return *this; 326 } 327 328 // ---------------------------------------------------------------------------- 329 330 const Region Region::merge(const Rect& rhs) const { 331 return operation(rhs, op_or); 332 } 333 const Region Region::mergeExclusive(const Rect& rhs) const { 334 return operation(rhs, op_xor); 335 } 336 const Region Region::intersect(const Rect& rhs) const { 337 return operation(rhs, op_and); 338 } 339 const Region Region::subtract(const Rect& rhs) const { 340 return operation(rhs, op_nand); 341 } 342 const Region Region::operation(const Rect& rhs, uint32_t op) const { 343 Region result; 344 boolean_operation(op, result, *this, rhs); 345 return result; 346 } 347 348 // ---------------------------------------------------------------------------- 349 350 const Region Region::merge(const Region& rhs) const { 351 return operation(rhs, op_or); 352 } 353 const Region Region::mergeExclusive(const Region& rhs) const { 354 return operation(rhs, op_xor); 355 } 356 const Region Region::intersect(const Region& rhs) const { 357 return operation(rhs, op_and); 358 } 359 const Region Region::subtract(const Region& rhs) const { 360 return operation(rhs, op_nand); 361 } 362 const Region Region::operation(const Region& rhs, uint32_t op) const { 363 Region result; 364 boolean_operation(op, result, *this, rhs); 365 return result; 366 } 367 368 const Region Region::translate(int x, int y) const { 369 Region result; 370 translate(result, *this, x, y); 371 return result; 372 } 373 374 // ---------------------------------------------------------------------------- 375 376 Region& Region::orSelf(const Region& rhs, int dx, int dy) { 377 return operationSelf(rhs, dx, dy, op_or); 378 } 379 Region& Region::xorSelf(const Region& rhs, int dx, int dy) { 380 return operationSelf(rhs, dx, dy, op_xor); 381 } 382 Region& Region::andSelf(const Region& rhs, int dx, int dy) { 383 return operationSelf(rhs, dx, dy, op_and); 384 } 385 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { 386 return operationSelf(rhs, dx, dy, op_nand); 387 } 388 Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) { 389 Region lhs(*this); 390 boolean_operation(op, *this, lhs, rhs, dx, dy); 391 return *this; 392 } 393 394 // ---------------------------------------------------------------------------- 395 396 const Region Region::merge(const Region& rhs, int dx, int dy) const { 397 return operation(rhs, dx, dy, op_or); 398 } 399 const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { 400 return operation(rhs, dx, dy, op_xor); 401 } 402 const Region Region::intersect(const Region& rhs, int dx, int dy) const { 403 return operation(rhs, dx, dy, op_and); 404 } 405 const Region Region::subtract(const Region& rhs, int dx, int dy) const { 406 return operation(rhs, dx, dy, op_nand); 407 } 408 const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const { 409 Region result; 410 boolean_operation(op, result, *this, rhs, dx, dy); 411 return result; 412 } 413 414 // ---------------------------------------------------------------------------- 415 416 // This is our region rasterizer, which merges rects and spans together 417 // to obtain an optimal region. 418 class Region::rasterizer : public region_operator<Rect>::region_rasterizer 419 { 420 Rect bounds; 421 Vector<Rect>& storage; 422 Rect* head; 423 Rect* tail; 424 Vector<Rect> span; 425 Rect* cur; 426 public: 427 explicit rasterizer(Region& reg) 428 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { 429 storage.clear(); 430 } 431 432 virtual ~rasterizer(); 433 434 virtual void operator()(const Rect& rect); 435 436 private: 437 template<typename T> 438 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } 439 template<typename T> 440 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } 441 442 void flushSpan(); 443 }; 444 445 Region::rasterizer::~rasterizer() 446 { 447 if (span.size()) { 448 flushSpan(); 449 } 450 if (storage.size()) { 451 bounds.top = storage.itemAt(0).top; 452 bounds.bottom = storage.top().bottom; 453 if (storage.size() == 1) { 454 storage.clear(); 455 } 456 } else { 457 bounds.left = 0; 458 bounds.right = 0; 459 } 460 storage.add(bounds); 461 } 462 463 void Region::rasterizer::operator()(const Rect& rect) 464 { 465 //ALOGD(">>> %3d, %3d, %3d, %3d", 466 // rect.left, rect.top, rect.right, rect.bottom); 467 if (span.size()) { 468 if (cur->top != rect.top) { 469 flushSpan(); 470 } else if (cur->right == rect.left) { 471 cur->right = rect.right; 472 return; 473 } 474 } 475 span.add(rect); 476 cur = span.editArray() + (span.size() - 1); 477 } 478 479 void Region::rasterizer::flushSpan() 480 { 481 bool merge = false; 482 if (tail-head == ssize_t(span.size())) { 483 Rect const* p = span.editArray(); 484 Rect const* q = head; 485 if (p->top == q->bottom) { 486 merge = true; 487 while (q != tail) { 488 if ((p->left != q->left) || (p->right != q->right)) { 489 merge = false; 490 break; 491 } 492 p++; 493 q++; 494 } 495 } 496 } 497 if (merge) { 498 const int bottom = span[0].bottom; 499 Rect* r = head; 500 while (r != tail) { 501 r->bottom = bottom; 502 r++; 503 } 504 } else { 505 bounds.left = min(span.itemAt(0).left, bounds.left); 506 bounds.right = max(span.top().right, bounds.right); 507 storage.appendVector(span); 508 tail = storage.editArray() + storage.size(); 509 head = tail - span.size(); 510 } 511 span.clear(); 512 } 513 514 bool Region::validate(const Region& reg, const char* name, bool silent) 515 { 516 if (reg.mStorage.isEmpty()) { 517 ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name); 518 // return immediately as the code below assumes mStorage is non-empty 519 return false; 520 } 521 522 bool result = true; 523 const_iterator cur = reg.begin(); 524 const_iterator const tail = reg.end(); 525 const_iterator prev = cur; 526 Rect b(*prev); 527 while (cur != tail) { 528 if (cur->isValid() == false) { 529 // We allow this particular flavor of invalid Rect, since it is used 530 // as a signal value in various parts of the system 531 if (*cur != Rect::INVALID_RECT) { 532 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); 533 result = false; 534 } 535 } 536 if (cur->right > region_operator<Rect>::max_value) { 537 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 538 result = false; 539 } 540 if (cur->bottom > region_operator<Rect>::max_value) { 541 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 542 result = false; 543 } 544 if (prev != cur) { 545 b.left = b.left < cur->left ? b.left : cur->left; 546 b.top = b.top < cur->top ? b.top : cur->top; 547 b.right = b.right > cur->right ? b.right : cur->right; 548 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; 549 if ((*prev < *cur) == false) { 550 ALOGE_IF(!silent, "%s: region's Rects not sorted", name); 551 result = false; 552 } 553 if (cur->top == prev->top) { 554 if (cur->bottom != prev->bottom) { 555 ALOGE_IF(!silent, "%s: invalid span %p", name, cur); 556 result = false; 557 } else if (cur->left < prev->right) { 558 ALOGE_IF(!silent, 559 "%s: spans overlap horizontally prev=%p, cur=%p", 560 name, prev, cur); 561 result = false; 562 } 563 } else if (cur->top < prev->bottom) { 564 ALOGE_IF(!silent, 565 "%s: spans overlap vertically prev=%p, cur=%p", 566 name, prev, cur); 567 result = false; 568 } 569 prev = cur; 570 } 571 cur++; 572 } 573 if (b != reg.getBounds()) { 574 result = false; 575 ALOGE_IF(!silent, 576 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, 577 b.left, b.top, b.right, b.bottom, 578 reg.getBounds().left, reg.getBounds().top, 579 reg.getBounds().right, reg.getBounds().bottom); 580 } 581 if (reg.mStorage.size() == 2) { 582 result = false; 583 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name); 584 } 585 if (result == false && !silent) { 586 reg.dump(name); 587 CallStack stack(LOG_TAG); 588 } 589 return result; 590 } 591 592 void Region::boolean_operation(uint32_t op, Region& dst, 593 const Region& lhs, 594 const Region& rhs, int dx, int dy) 595 { 596 #if VALIDATE_REGIONS 597 validate(lhs, "boolean_operation (before): lhs"); 598 validate(rhs, "boolean_operation (before): rhs"); 599 validate(dst, "boolean_operation (before): dst"); 600 #endif 601 602 size_t lhs_count; 603 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 604 605 size_t rhs_count; 606 Rect const * const rhs_rects = rhs.getArray(&rhs_count); 607 608 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 609 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); 610 region_operator<Rect> operation(op, lhs_region, rhs_region); 611 { // scope for rasterizer (dtor has side effects) 612 rasterizer r(dst); 613 operation(r); 614 } 615 616 #if VALIDATE_REGIONS 617 validate(lhs, "boolean_operation: lhs"); 618 validate(rhs, "boolean_operation: rhs"); 619 validate(dst, "boolean_operation: dst"); 620 #endif 621 622 #if VALIDATE_WITH_CORECG 623 SkRegion sk_lhs; 624 SkRegion sk_rhs; 625 SkRegion sk_dst; 626 627 for (size_t i=0 ; i<lhs_count ; i++) 628 sk_lhs.op( 629 lhs_rects[i].left + dx, 630 lhs_rects[i].top + dy, 631 lhs_rects[i].right + dx, 632 lhs_rects[i].bottom + dy, 633 SkRegion::kUnion_Op); 634 635 for (size_t i=0 ; i<rhs_count ; i++) 636 sk_rhs.op( 637 rhs_rects[i].left + dx, 638 rhs_rects[i].top + dy, 639 rhs_rects[i].right + dx, 640 rhs_rects[i].bottom + dy, 641 SkRegion::kUnion_Op); 642 643 const char* name = "---"; 644 SkRegion::Op sk_op; 645 switch (op) { 646 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; 647 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; 648 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; 649 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; 650 } 651 sk_dst.op(sk_lhs, sk_rhs, sk_op); 652 653 if (sk_dst.isEmpty() && dst.isEmpty()) 654 return; 655 656 bool same = true; 657 Region::const_iterator head = dst.begin(); 658 Region::const_iterator const tail = dst.end(); 659 SkRegion::Iterator it(sk_dst); 660 while (!it.done()) { 661 if (head != tail) { 662 if ( 663 head->left != it.rect().fLeft || 664 head->top != it.rect().fTop || 665 head->right != it.rect().fRight || 666 head->bottom != it.rect().fBottom 667 ) { 668 same = false; 669 break; 670 } 671 } else { 672 same = false; 673 break; 674 } 675 head++; 676 it.next(); 677 } 678 679 if (head != tail) { 680 same = false; 681 } 682 683 if(!same) { 684 ALOGD("---\nregion boolean %s failed", name); 685 lhs.dump("lhs"); 686 rhs.dump("rhs"); 687 dst.dump("dst"); 688 ALOGD("should be"); 689 SkRegion::Iterator it(sk_dst); 690 while (!it.done()) { 691 ALOGD(" [%3d, %3d, %3d, %3d]", 692 it.rect().fLeft, 693 it.rect().fTop, 694 it.rect().fRight, 695 it.rect().fBottom); 696 it.next(); 697 } 698 } 699 #endif 700 } 701 702 void Region::boolean_operation(uint32_t op, Region& dst, 703 const Region& lhs, 704 const Rect& rhs, int dx, int dy) 705 { 706 // We allow this particular flavor of invalid Rect, since it is used as a 707 // signal value in various parts of the system 708 if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { 709 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", 710 op, rhs.left, rhs.top, rhs.right, rhs.bottom); 711 return; 712 } 713 714 #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS 715 boolean_operation(op, dst, lhs, Region(rhs), dx, dy); 716 #else 717 size_t lhs_count; 718 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 719 720 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 721 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); 722 region_operator<Rect> operation(op, lhs_region, rhs_region); 723 { // scope for rasterizer (dtor has side effects) 724 rasterizer r(dst); 725 operation(r); 726 } 727 728 #endif 729 } 730 731 void Region::boolean_operation(uint32_t op, Region& dst, 732 const Region& lhs, const Region& rhs) 733 { 734 boolean_operation(op, dst, lhs, rhs, 0, 0); 735 } 736 737 void Region::boolean_operation(uint32_t op, Region& dst, 738 const Region& lhs, const Rect& rhs) 739 { 740 boolean_operation(op, dst, lhs, rhs, 0, 0); 741 } 742 743 void Region::translate(Region& reg, int dx, int dy) 744 { 745 if ((dx || dy) && !reg.isEmpty()) { 746 #if VALIDATE_REGIONS 747 validate(reg, "translate (before)"); 748 #endif 749 size_t count = reg.mStorage.size(); 750 Rect* rects = reg.mStorage.editArray(); 751 while (count) { 752 rects->offsetBy(dx, dy); 753 rects++; 754 count--; 755 } 756 #if VALIDATE_REGIONS 757 validate(reg, "translate (after)"); 758 #endif 759 } 760 } 761 762 void Region::translate(Region& dst, const Region& reg, int dx, int dy) 763 { 764 dst = reg; 765 translate(dst, dx, dy); 766 } 767 768 // ---------------------------------------------------------------------------- 769 770 size_t Region::getFlattenedSize() const { 771 return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); 772 } 773 774 status_t Region::flatten(void* buffer, size_t size) const { 775 #if VALIDATE_REGIONS 776 validate(*this, "Region::flatten"); 777 #endif 778 if (size < getFlattenedSize()) { 779 return NO_MEMORY; 780 } 781 // Cast to uint32_t since the size of a size_t can vary between 32- and 782 // 64-bit processes 783 FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); 784 for (auto rect : mStorage) { 785 status_t result = rect.flatten(buffer, size); 786 if (result != NO_ERROR) { 787 return result; 788 } 789 FlattenableUtils::advance(buffer, size, sizeof(rect)); 790 } 791 return NO_ERROR; 792 } 793 794 status_t Region::unflatten(void const* buffer, size_t size) { 795 if (size < sizeof(uint32_t)) { 796 return NO_MEMORY; 797 } 798 799 uint32_t numRects = 0; 800 FlattenableUtils::read(buffer, size, numRects); 801 if (size < numRects * sizeof(Rect)) { 802 return NO_MEMORY; 803 } 804 805 if (numRects > (UINT32_MAX / sizeof(Rect))) { 806 android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); 807 return NO_MEMORY; 808 } 809 810 Region result; 811 result.mStorage.clear(); 812 for (size_t r = 0; r < numRects; ++r) { 813 Rect rect(Rect::EMPTY_RECT); 814 status_t status = rect.unflatten(buffer, size); 815 if (status != NO_ERROR) { 816 return status; 817 } 818 FlattenableUtils::advance(buffer, size, sizeof(rect)); 819 result.mStorage.push_back(rect); 820 } 821 822 #if VALIDATE_REGIONS 823 validate(result, "Region::unflatten"); 824 #endif 825 826 if (!result.validate(result, "Region::unflatten", true)) { 827 ALOGE("Region::unflatten() failed, invalid region"); 828 return BAD_VALUE; 829 } 830 mStorage = result.mStorage; 831 return NO_ERROR; 832 } 833 834 // ---------------------------------------------------------------------------- 835 836 Region::const_iterator Region::begin() const { 837 return mStorage.array(); 838 } 839 840 Region::const_iterator Region::end() const { 841 // Workaround for b/77643177 842 // mStorage should never be empty, but somehow it is and it's causing 843 // an abort in ubsan 844 if (mStorage.isEmpty()) return mStorage.array(); 845 846 size_t numRects = isRect() ? 1 : mStorage.size() - 1; 847 return mStorage.array() + numRects; 848 } 849 850 Rect const* Region::getArray(size_t* count) const { 851 if (count) *count = static_cast<size_t>(end() - begin()); 852 return begin(); 853 } 854 855 // ---------------------------------------------------------------------------- 856 857 void Region::dump(String8& out, const char* what, uint32_t /* flags */) const 858 { 859 const_iterator head = begin(); 860 const_iterator const tail = end(); 861 862 out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", 863 what, this, tail - head); 864 while (head != tail) { 865 out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, 866 head->right, head->bottom); 867 ++head; 868 } 869 } 870 871 void Region::dump(const char* what, uint32_t /* flags */) const 872 { 873 const_iterator head = begin(); 874 const_iterator const tail = end(); 875 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); 876 while (head != tail) { 877 ALOGD(" [%3d, %3d, %3d, %3d]\n", 878 head->left, head->top, head->right, head->bottom); 879 head++; 880 } 881 } 882 883 // ---------------------------------------------------------------------------- 884 885 }; // namespace android 886