Region.cpp revision e2347b7953f70232541bdc1b392230d6231aaeb9
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 41namespace android { 42// ---------------------------------------------------------------------------- 43 44enum { 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 51enum { 52 direction_LTR, 53 direction_RTL 54}; 55 56const Region Region::INVALID_REGION(Rect::INVALID_RECT); 57 58// ---------------------------------------------------------------------------- 59 60Region::Region() { 61 mStorage.add(Rect(0,0)); 62} 63 64Region::Region(const Region& rhs) 65 : mStorage(rhs.mStorage) 66{ 67#if VALIDATE_REGIONS 68 validate(rhs, "rhs copy-ctor"); 69#endif 70} 71 72Region::Region(const Rect& rhs) { 73 mStorage.add(rhs); 74} 75 76Region::~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 */ 94static 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 */ 191Region 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 210Region& 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 220Region& 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 230bool Region::contains(const Point& point) const { 231 return contains(point.x, point.y); 232} 233 234bool 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 246void Region::clear() 247{ 248 mStorage.clear(); 249 mStorage.add(Rect(0,0)); 250} 251 252void Region::set(const Rect& r) 253{ 254 mStorage.clear(); 255 mStorage.add(r); 256} 257 258void Region::set(int32_t w, int32_t h) 259{ 260 mStorage.clear(); 261 mStorage.add(Rect(w, h)); 262} 263 264void Region::set(uint32_t w, uint32_t h) 265{ 266 mStorage.clear(); 267 mStorage.add(Rect(w, h)); 268} 269 270bool Region::isTriviallyEqual(const Region& region) const { 271 return begin() == region.begin(); 272} 273 274// ---------------------------------------------------------------------------- 275 276void 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 285Region& Region::orSelf(const Rect& r) { 286 return operationSelf(r, op_or); 287} 288Region& Region::xorSelf(const Rect& r) { 289 return operationSelf(r, op_xor); 290} 291Region& Region::andSelf(const Rect& r) { 292 return operationSelf(r, op_and); 293} 294Region& Region::subtractSelf(const Rect& r) { 295 return operationSelf(r, op_nand); 296} 297Region& 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 305Region& Region::orSelf(const Region& rhs) { 306 return operationSelf(rhs, op_or); 307} 308Region& Region::xorSelf(const Region& rhs) { 309 return operationSelf(rhs, op_xor); 310} 311Region& Region::andSelf(const Region& rhs) { 312 return operationSelf(rhs, op_and); 313} 314Region& Region::subtractSelf(const Region& rhs) { 315 return operationSelf(rhs, op_nand); 316} 317Region& Region::operationSelf(const Region& rhs, int op) { 318 Region lhs(*this); 319 boolean_operation(op, *this, lhs, rhs); 320 return *this; 321} 322 323Region& Region::translateSelf(int x, int y) { 324 if (x|y) translate(*this, x, y); 325 return *this; 326} 327 328// ---------------------------------------------------------------------------- 329 330const Region Region::merge(const Rect& rhs) const { 331 return operation(rhs, op_or); 332} 333const Region Region::mergeExclusive(const Rect& rhs) const { 334 return operation(rhs, op_xor); 335} 336const Region Region::intersect(const Rect& rhs) const { 337 return operation(rhs, op_and); 338} 339const Region Region::subtract(const Rect& rhs) const { 340 return operation(rhs, op_nand); 341} 342const 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 350const Region Region::merge(const Region& rhs) const { 351 return operation(rhs, op_or); 352} 353const Region Region::mergeExclusive(const Region& rhs) const { 354 return operation(rhs, op_xor); 355} 356const Region Region::intersect(const Region& rhs) const { 357 return operation(rhs, op_and); 358} 359const Region Region::subtract(const Region& rhs) const { 360 return operation(rhs, op_nand); 361} 362const Region Region::operation(const Region& rhs, int op) const { 363 Region result; 364 boolean_operation(op, result, *this, rhs); 365 return result; 366} 367 368const Region Region::translate(int x, int y) const { 369 Region result; 370 translate(result, *this, x, y); 371 return result; 372} 373 374// ---------------------------------------------------------------------------- 375 376Region& Region::orSelf(const Region& rhs, int dx, int dy) { 377 return operationSelf(rhs, dx, dy, op_or); 378} 379Region& Region::xorSelf(const Region& rhs, int dx, int dy) { 380 return operationSelf(rhs, dx, dy, op_xor); 381} 382Region& Region::andSelf(const Region& rhs, int dx, int dy) { 383 return operationSelf(rhs, dx, dy, op_and); 384} 385Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { 386 return operationSelf(rhs, dx, dy, op_nand); 387} 388Region& 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 396const Region Region::merge(const Region& rhs, int dx, int dy) const { 397 return operation(rhs, dx, dy, op_or); 398} 399const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { 400 return operation(rhs, dx, dy, op_xor); 401} 402const Region Region::intersect(const Region& rhs, int dx, int dy) const { 403 return operation(rhs, dx, dy, op_and); 404} 405const Region Region::subtract(const Region& rhs, int dx, int dy) const { 406 return operation(rhs, dx, dy, op_nand); 407} 408const 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. 418class 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; 426public: 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 436private: 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 445Region::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 463void 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 479void 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 514bool Region::validate(const Region& reg, const char* name, bool silent) 515{ 516 bool result = true; 517 const_iterator cur = reg.begin(); 518 const_iterator const tail = reg.end(); 519 const_iterator prev = cur; 520 Rect b(*prev); 521 while (cur != tail) { 522 if (cur->isValid() == false) { 523 // We allow this particular flavor of invalid Rect, since it is used 524 // as a signal value in various parts of the system 525 if (*cur != Rect::INVALID_RECT) { 526 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); 527 result = false; 528 } 529 } 530 if (cur->right > region_operator<Rect>::max_value) { 531 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 532 result = false; 533 } 534 if (cur->bottom > region_operator<Rect>::max_value) { 535 ALOGE_IF(!silent, "%s: rect->right > max_value", name); 536 result = false; 537 } 538 if (prev != cur) { 539 b.left = b.left < cur->left ? b.left : cur->left; 540 b.top = b.top < cur->top ? b.top : cur->top; 541 b.right = b.right > cur->right ? b.right : cur->right; 542 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; 543 if ((*prev < *cur) == false) { 544 ALOGE_IF(!silent, "%s: region's Rects not sorted", name); 545 result = false; 546 } 547 if (cur->top == prev->top) { 548 if (cur->bottom != prev->bottom) { 549 ALOGE_IF(!silent, "%s: invalid span %p", name, cur); 550 result = false; 551 } else if (cur->left < prev->right) { 552 ALOGE_IF(!silent, 553 "%s: spans overlap horizontally prev=%p, cur=%p", 554 name, prev, cur); 555 result = false; 556 } 557 } else if (cur->top < prev->bottom) { 558 ALOGE_IF(!silent, 559 "%s: spans overlap vertically prev=%p, cur=%p", 560 name, prev, cur); 561 result = false; 562 } 563 prev = cur; 564 } 565 cur++; 566 } 567 if (b != reg.getBounds()) { 568 result = false; 569 ALOGE_IF(!silent, 570 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, 571 b.left, b.top, b.right, b.bottom, 572 reg.getBounds().left, reg.getBounds().top, 573 reg.getBounds().right, reg.getBounds().bottom); 574 } 575 if (reg.mStorage.size() == 2) { 576 result = false; 577 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name); 578 } 579 if (result == false && !silent) { 580 reg.dump(name); 581 CallStack stack(LOG_TAG); 582 } 583 return result; 584} 585 586void Region::boolean_operation(int op, Region& dst, 587 const Region& lhs, 588 const Region& rhs, int dx, int dy) 589{ 590#if VALIDATE_REGIONS 591 validate(lhs, "boolean_operation (before): lhs"); 592 validate(rhs, "boolean_operation (before): rhs"); 593 validate(dst, "boolean_operation (before): dst"); 594#endif 595 596 size_t lhs_count; 597 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 598 599 size_t rhs_count; 600 Rect const * const rhs_rects = rhs.getArray(&rhs_count); 601 602 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 603 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); 604 region_operator<Rect> operation(op, lhs_region, rhs_region); 605 { // scope for rasterizer (dtor has side effects) 606 rasterizer r(dst); 607 operation(r); 608 } 609 610#if VALIDATE_REGIONS 611 validate(lhs, "boolean_operation: lhs"); 612 validate(rhs, "boolean_operation: rhs"); 613 validate(dst, "boolean_operation: dst"); 614#endif 615 616#if VALIDATE_WITH_CORECG 617 SkRegion sk_lhs; 618 SkRegion sk_rhs; 619 SkRegion sk_dst; 620 621 for (size_t i=0 ; i<lhs_count ; i++) 622 sk_lhs.op( 623 lhs_rects[i].left + dx, 624 lhs_rects[i].top + dy, 625 lhs_rects[i].right + dx, 626 lhs_rects[i].bottom + dy, 627 SkRegion::kUnion_Op); 628 629 for (size_t i=0 ; i<rhs_count ; i++) 630 sk_rhs.op( 631 rhs_rects[i].left + dx, 632 rhs_rects[i].top + dy, 633 rhs_rects[i].right + dx, 634 rhs_rects[i].bottom + dy, 635 SkRegion::kUnion_Op); 636 637 const char* name = "---"; 638 SkRegion::Op sk_op; 639 switch (op) { 640 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; 641 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; 642 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; 643 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; 644 } 645 sk_dst.op(sk_lhs, sk_rhs, sk_op); 646 647 if (sk_dst.isEmpty() && dst.isEmpty()) 648 return; 649 650 bool same = true; 651 Region::const_iterator head = dst.begin(); 652 Region::const_iterator const tail = dst.end(); 653 SkRegion::Iterator it(sk_dst); 654 while (!it.done()) { 655 if (head != tail) { 656 if ( 657 head->left != it.rect().fLeft || 658 head->top != it.rect().fTop || 659 head->right != it.rect().fRight || 660 head->bottom != it.rect().fBottom 661 ) { 662 same = false; 663 break; 664 } 665 } else { 666 same = false; 667 break; 668 } 669 head++; 670 it.next(); 671 } 672 673 if (head != tail) { 674 same = false; 675 } 676 677 if(!same) { 678 ALOGD("---\nregion boolean %s failed", name); 679 lhs.dump("lhs"); 680 rhs.dump("rhs"); 681 dst.dump("dst"); 682 ALOGD("should be"); 683 SkRegion::Iterator it(sk_dst); 684 while (!it.done()) { 685 ALOGD(" [%3d, %3d, %3d, %3d]", 686 it.rect().fLeft, 687 it.rect().fTop, 688 it.rect().fRight, 689 it.rect().fBottom); 690 it.next(); 691 } 692 } 693#endif 694} 695 696void Region::boolean_operation(int op, Region& dst, 697 const Region& lhs, 698 const Rect& rhs, int dx, int dy) 699{ 700 // We allow this particular flavor of invalid Rect, since it is used as a 701 // signal value in various parts of the system 702 if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { 703 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", 704 op, rhs.left, rhs.top, rhs.right, rhs.bottom); 705 return; 706 } 707 708#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS 709 boolean_operation(op, dst, lhs, Region(rhs), dx, dy); 710#else 711 size_t lhs_count; 712 Rect const * const lhs_rects = lhs.getArray(&lhs_count); 713 714 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); 715 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); 716 region_operator<Rect> operation(op, lhs_region, rhs_region); 717 { // scope for rasterizer (dtor has side effects) 718 rasterizer r(dst); 719 operation(r); 720 } 721 722#endif 723} 724 725void Region::boolean_operation(int op, Region& dst, 726 const Region& lhs, const Region& rhs) 727{ 728 boolean_operation(op, dst, lhs, rhs, 0, 0); 729} 730 731void Region::boolean_operation(int op, Region& dst, 732 const Region& lhs, const Rect& rhs) 733{ 734 boolean_operation(op, dst, lhs, rhs, 0, 0); 735} 736 737void Region::translate(Region& reg, int dx, int dy) 738{ 739 if ((dx || dy) && !reg.isEmpty()) { 740#if VALIDATE_REGIONS 741 validate(reg, "translate (before)"); 742#endif 743 size_t count = reg.mStorage.size(); 744 Rect* rects = reg.mStorage.editArray(); 745 while (count) { 746 rects->offsetBy(dx, dy); 747 rects++; 748 count--; 749 } 750#if VALIDATE_REGIONS 751 validate(reg, "translate (after)"); 752#endif 753 } 754} 755 756void Region::translate(Region& dst, const Region& reg, int dx, int dy) 757{ 758 dst = reg; 759 translate(dst, dx, dy); 760} 761 762// ---------------------------------------------------------------------------- 763 764size_t Region::getFlattenedSize() const { 765 return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); 766} 767 768status_t Region::flatten(void* buffer, size_t size) const { 769#if VALIDATE_REGIONS 770 validate(*this, "Region::flatten"); 771#endif 772 if (size < getFlattenedSize()) { 773 return NO_MEMORY; 774 } 775 // Cast to uint32_t since the size of a size_t can vary between 32- and 776 // 64-bit processes 777 FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); 778 for (auto rect : mStorage) { 779 status_t result = rect.flatten(buffer, size); 780 if (result != NO_ERROR) { 781 return result; 782 } 783 FlattenableUtils::advance(buffer, size, sizeof(rect)); 784 } 785 return NO_ERROR; 786} 787 788status_t Region::unflatten(void const* buffer, size_t size) { 789 if (size < sizeof(uint32_t)) { 790 return NO_MEMORY; 791 } 792 793 uint32_t numRects = 0; 794 FlattenableUtils::read(buffer, size, numRects); 795 if (size < numRects * sizeof(Rect)) { 796 return NO_MEMORY; 797 } 798 799 Region result; 800 result.mStorage.clear(); 801 for (size_t r = 0; r < numRects; ++r) { 802 Rect rect; 803 status_t status = rect.unflatten(buffer, size); 804 if (status != NO_ERROR) { 805 return status; 806 } 807 FlattenableUtils::advance(buffer, size, sizeof(rect)); 808 result.mStorage.push_back(rect); 809 } 810 811#if VALIDATE_REGIONS 812 validate(result, "Region::unflatten"); 813#endif 814 815 if (!result.validate(result, "Region::unflatten", true)) { 816 ALOGE("Region::unflatten() failed, invalid region"); 817 return BAD_VALUE; 818 } 819 mStorage = result.mStorage; 820 return NO_ERROR; 821} 822 823// ---------------------------------------------------------------------------- 824 825Region::const_iterator Region::begin() const { 826 return mStorage.array(); 827} 828 829Region::const_iterator Region::end() const { 830 size_t numRects = isRect() ? 1 : mStorage.size() - 1; 831 return mStorage.array() + numRects; 832} 833 834Rect const* Region::getArray(size_t* count) const { 835 if (count) *count = static_cast<size_t>(end() - begin()); 836 return begin(); 837} 838 839// ---------------------------------------------------------------------------- 840 841void Region::dump(String8& out, const char* what, uint32_t /* flags */) const 842{ 843 const_iterator head = begin(); 844 const_iterator const tail = end(); 845 846 out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", 847 what, this, tail - head); 848 while (head != tail) { 849 out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, 850 head->right, head->bottom); 851 ++head; 852 } 853} 854 855void Region::dump(const char* what, uint32_t /* flags */) const 856{ 857 const_iterator head = begin(); 858 const_iterator const tail = end(); 859 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); 860 while (head != tail) { 861 ALOGD(" [%3d, %3d, %3d, %3d]\n", 862 head->left, head->top, head->right, head->bottom); 863 head++; 864 } 865} 866 867// ---------------------------------------------------------------------------- 868 869}; // namespace android 870