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