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, int 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, int 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, int 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, int 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, int 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, int 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 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++, q++; 493 } 494 } 495 } 496 if (merge) { 497 const int bottom = span[0].bottom; 498 Rect* r = head; 499 while (r != tail) { 500 r->bottom = bottom; 501 r++; 502 } 503 } else { 504 bounds.left = min(span.itemAt(0).left, bounds.left); 505 bounds.right = max(span.top().right, bounds.right); 506 storage.appendVector(span); 507 tail = storage.editArray() + storage.size(); 508 head = tail - span.size(); 509 } 510 span.clear(); 511 } 512 513 bool Region::validate(const Region& reg, const char* name, bool silent) 514 { 515 bool result = true; 516 const_iterator cur = reg.begin(); 517 const_iterator const tail = reg.end(); 518 const_iterator prev = cur; 519 Rect b(*prev); 520 while (cur != tail) { 521 if (cur->isValid() == false) { 522 // We allow this particular flavor of invalid Rect, since it is used 523 // as a signal value in various parts of the system 524 if (*cur != Rect::INVALID_RECT) { 525 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); 526 result = false; 527 } 528 } 529 if (cur->right > region_operator<Rect>::max_value) { 530 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 531 result = false; 532 } 533 if (cur->bottom > region_operator<Rect>::max_value) { 534 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 535 result = false; 536 } 537 if (prev != cur) { 538 b.left = b.left < cur->left ? b.left : cur->left; 539 b.top = b.top < cur->top ? b.top : cur->top; 540 b.right = b.right > cur->right ? b.right : cur->right; 541 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; 542 if ((*prev < *cur) == false) { 543 ALOGE_IF(!silent, "%s: region's Rects not sorted", name); 544 result = false; 545 } 546 if (cur->top == prev->top) { 547 if (cur->bottom != prev->bottom) { 548 ALOGE_IF(!silent, "%s: invalid span %p", name, cur); 549 result = false; 550 } else if (cur->left < prev->right) { 551 ALOGE_IF(!silent, 552 "%s: spans overlap horizontally prev=%p, cur=%p", 553 name, prev, cur); 554 result = false; 555 } 556 } else if (cur->top < prev->bottom) { 557 ALOGE_IF(!silent, 558 "%s: spans overlap vertically prev=%p, cur=%p", 559 name, prev, cur); 560 result = false; 561 } 562 prev = cur; 563 } 564 cur++; 565 } 566 if (b != reg.getBounds()) { 567 result = false; 568 ALOGE_IF(!silent, 569 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, 570 b.left, b.top, b.right, b.bottom, 571 reg.getBounds().left, reg.getBounds().top, 572 reg.getBounds().right, reg.getBounds().bottom); 573 } 574 if (reg.mStorage.size() == 2) { 575 result = false; 576 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name); 577 } 578 if (result == false && !silent) { 579 reg.dump(name); 580 CallStack stack(LOG_TAG); 581 } 582 return result; 583 } 584 585 void Region::boolean_operation(int op, Region& dst, 586 const Region& lhs, 587 const Region& rhs, int dx, int dy) 588 { 589 #if VALIDATE_REGIONS 590 validate(lhs, "boolean_operation (before): lhs"); 591 validate(rhs, "boolean_operation (before): rhs"); 592 validate(dst, "boolean_operation (before): dst"); 593 #endif 594 595 size_t lhs_count; 596 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 597 598 size_t rhs_count; 599 Rect const * const rhs_rects = rhs.getArray(&rhs_count); 600 601 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 602 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); 603 region_operator<Rect> operation(op, lhs_region, rhs_region); 604 { // scope for rasterizer (dtor has side effects) 605 rasterizer r(dst); 606 operation(r); 607 } 608 609 #if VALIDATE_REGIONS 610 validate(lhs, "boolean_operation: lhs"); 611 validate(rhs, "boolean_operation: rhs"); 612 validate(dst, "boolean_operation: dst"); 613 #endif 614 615 #if VALIDATE_WITH_CORECG 616 SkRegion sk_lhs; 617 SkRegion sk_rhs; 618 SkRegion sk_dst; 619 620 for (size_t i=0 ; i<lhs_count ; i++) 621 sk_lhs.op( 622 lhs_rects[i].left + dx, 623 lhs_rects[i].top + dy, 624 lhs_rects[i].right + dx, 625 lhs_rects[i].bottom + dy, 626 SkRegion::kUnion_Op); 627 628 for (size_t i=0 ; i<rhs_count ; i++) 629 sk_rhs.op( 630 rhs_rects[i].left + dx, 631 rhs_rects[i].top + dy, 632 rhs_rects[i].right + dx, 633 rhs_rects[i].bottom + dy, 634 SkRegion::kUnion_Op); 635 636 const char* name = "---"; 637 SkRegion::Op sk_op; 638 switch (op) { 639 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; 640 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; 641 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; 642 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; 643 } 644 sk_dst.op(sk_lhs, sk_rhs, sk_op); 645 646 if (sk_dst.isEmpty() && dst.isEmpty()) 647 return; 648 649 bool same = true; 650 Region::const_iterator head = dst.begin(); 651 Region::const_iterator const tail = dst.end(); 652 SkRegion::Iterator it(sk_dst); 653 while (!it.done()) { 654 if (head != tail) { 655 if ( 656 head->left != it.rect().fLeft || 657 head->top != it.rect().fTop || 658 head->right != it.rect().fRight || 659 head->bottom != it.rect().fBottom 660 ) { 661 same = false; 662 break; 663 } 664 } else { 665 same = false; 666 break; 667 } 668 head++; 669 it.next(); 670 } 671 672 if (head != tail) { 673 same = false; 674 } 675 676 if(!same) { 677 ALOGD("---\nregion boolean %s failed", name); 678 lhs.dump("lhs"); 679 rhs.dump("rhs"); 680 dst.dump("dst"); 681 ALOGD("should be"); 682 SkRegion::Iterator it(sk_dst); 683 while (!it.done()) { 684 ALOGD(" [%3d, %3d, %3d, %3d]", 685 it.rect().fLeft, 686 it.rect().fTop, 687 it.rect().fRight, 688 it.rect().fBottom); 689 it.next(); 690 } 691 } 692 #endif 693 } 694 695 void Region::boolean_operation(int op, Region& dst, 696 const Region& lhs, 697 const Rect& rhs, int dx, int dy) 698 { 699 // We allow this particular flavor of invalid Rect, since it is used as a 700 // signal value in various parts of the system 701 if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { 702 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", 703 op, rhs.left, rhs.top, rhs.right, rhs.bottom); 704 return; 705 } 706 707 #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS 708 boolean_operation(op, dst, lhs, Region(rhs), dx, dy); 709 #else 710 size_t lhs_count; 711 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 712 713 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 714 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); 715 region_operator<Rect> operation(op, lhs_region, rhs_region); 716 { // scope for rasterizer (dtor has side effects) 717 rasterizer r(dst); 718 operation(r); 719 } 720 721 #endif 722 } 723 724 void Region::boolean_operation(int op, Region& dst, 725 const Region& lhs, const Region& rhs) 726 { 727 boolean_operation(op, dst, lhs, rhs, 0, 0); 728 } 729 730 void Region::boolean_operation(int op, Region& dst, 731 const Region& lhs, const Rect& rhs) 732 { 733 boolean_operation(op, dst, lhs, rhs, 0, 0); 734 } 735 736 void Region::translate(Region& reg, int dx, int dy) 737 { 738 if ((dx || dy) && !reg.isEmpty()) { 739 #if VALIDATE_REGIONS 740 validate(reg, "translate (before)"); 741 #endif 742 size_t count = reg.mStorage.size(); 743 Rect* rects = reg.mStorage.editArray(); 744 while (count) { 745 rects->offsetBy(dx, dy); 746 rects++; 747 count--; 748 } 749 #if VALIDATE_REGIONS 750 validate(reg, "translate (after)"); 751 #endif 752 } 753 } 754 755 void Region::translate(Region& dst, const Region& reg, int dx, int dy) 756 { 757 dst = reg; 758 translate(dst, dx, dy); 759 } 760 761 // ---------------------------------------------------------------------------- 762 763 size_t Region::getFlattenedSize() const { 764 return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); 765 } 766 767 status_t Region::flatten(void* buffer, size_t size) const { 768 #if VALIDATE_REGIONS 769 validate(*this, "Region::flatten"); 770 #endif 771 if (size < getFlattenedSize()) { 772 return NO_MEMORY; 773 } 774 // Cast to uint32_t since the size of a size_t can vary between 32- and 775 // 64-bit processes 776 FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); 777 for (auto rect : mStorage) { 778 status_t result = rect.flatten(buffer, size); 779 if (result != NO_ERROR) { 780 return result; 781 } 782 FlattenableUtils::advance(buffer, size, sizeof(rect)); 783 } 784 return NO_ERROR; 785 } 786 787 status_t Region::unflatten(void const* buffer, size_t size) { 788 if (size < sizeof(uint32_t)) { 789 return NO_MEMORY; 790 } 791 792 uint32_t numRects = 0; 793 FlattenableUtils::read(buffer, size, numRects); 794 if (size < numRects * sizeof(Rect)) { 795 return NO_MEMORY; 796 } 797 798 if (numRects > (UINT32_MAX / sizeof(Rect))) { 799 android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); 800 return NO_MEMORY; 801 } 802 803 Region result; 804 result.mStorage.clear(); 805 for (size_t r = 0; r < numRects; ++r) { 806 Rect rect(Rect::EMPTY_RECT); 807 status_t status = rect.unflatten(buffer, size); 808 if (status != NO_ERROR) { 809 return status; 810 } 811 FlattenableUtils::advance(buffer, size, sizeof(rect)); 812 result.mStorage.push_back(rect); 813 } 814 815 #if VALIDATE_REGIONS 816 validate(result, "Region::unflatten"); 817 #endif 818 819 if (!result.validate(result, "Region::unflatten", true)) { 820 ALOGE("Region::unflatten() failed, invalid region"); 821 return BAD_VALUE; 822 } 823 mStorage = result.mStorage; 824 return NO_ERROR; 825 } 826 827 // ---------------------------------------------------------------------------- 828 829 Region::const_iterator Region::begin() const { 830 return mStorage.array(); 831 } 832 833 Region::const_iterator Region::end() const { 834 size_t numRects = isRect() ? 1 : mStorage.size() - 1; 835 return mStorage.array() + numRects; 836 } 837 838 Rect const* Region::getArray(size_t* count) const { 839 if (count) *count = static_cast<size_t>(end() - begin()); 840 return begin(); 841 } 842 843 // ---------------------------------------------------------------------------- 844 845 void Region::dump(String8& out, const char* what, uint32_t /* flags */) const 846 { 847 const_iterator head = begin(); 848 const_iterator const tail = end(); 849 850 out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", 851 what, this, tail - head); 852 while (head != tail) { 853 out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, 854 head->right, head->bottom); 855 ++head; 856 } 857 } 858 859 void Region::dump(const char* what, uint32_t /* flags */) const 860 { 861 const_iterator head = begin(); 862 const_iterator const tail = end(); 863 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); 864 while (head != tail) { 865 ALOGD(" [%3d, %3d, %3d, %3d]\n", 866 head->left, head->top, head->right, head->bottom); 867 head++; 868 } 869 } 870 871 // ---------------------------------------------------------------------------- 872 873 }; // namespace android 874