1/* 2 * Copyright 2008, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#define LOG_NDEBUG 0 27#define LOG_TAG "pictureset" 28 29//#include <config.h> 30#include "CachedPrefix.h" 31#include "android_graphics.h" 32#include "PictureSet.h" 33#include "SkBounder.h" 34#include "SkCanvas.h" 35#include "SkPicture.h" 36#include "SkRect.h" 37#include "SkRegion.h" 38#include "SkStream.h" 39#include "TimeCounter.h" 40 41#define MAX_DRAW_TIME 100 42#define MIN_SPLITTABLE 400 43 44#if PICTURE_SET_DEBUG 45class MeasureStream : public SkWStream { 46public: 47 MeasureStream() : mTotal(0) {} 48 virtual bool write(const void* , size_t size) { 49 mTotal += size; 50 return true; 51 } 52 size_t mTotal; 53}; 54#endif 55 56namespace android { 57 58PictureSet::PictureSet() 59{ 60 mWidth = mHeight = 0; 61} 62 63PictureSet::~PictureSet() 64{ 65 clear(); 66} 67 68void PictureSet::add(const Pictures* temp) 69{ 70 Pictures pictureAndBounds = *temp; 71 pictureAndBounds.mPicture->safeRef(); 72 pictureAndBounds.mWroteElapsed = false; 73 mPictures.append(pictureAndBounds); 74} 75 76void PictureSet::add(const SkRegion& area, SkPicture* picture, 77 uint32_t elapsed, bool split, bool empty) 78{ 79 DBG_SET_LOGD("%p area={%d,%d,r=%d,b=%d} pict=%p elapsed=%d split=%d", this, 80 area.getBounds().fLeft, area.getBounds().fTop, 81 area.getBounds().fRight, area.getBounds().fBottom, picture, 82 elapsed, split); 83 picture->safeRef(); 84 /* if nothing is drawn beneath part of the new picture, mark it as a base */ 85 SkRegion diff = SkRegion(area); 86 Pictures* last = mPictures.end(); 87 for (Pictures* working = mPictures.begin(); working != last; working++) 88 diff.op(working->mArea, SkRegion::kDifference_Op); 89 Pictures pictureAndBounds = {area, picture, area.getBounds(), 90 elapsed, split, false, diff.isEmpty() == false, empty}; 91 mPictures.append(pictureAndBounds); 92} 93 94/* 95Pictures are discarded when they are fully drawn over. 96When a picture is partially drawn over, it is discarded if it is not a base, and 97its rectangular bounds is reduced if it is a base. 98*/ 99bool PictureSet::build() 100{ 101 bool rebuild = false; 102 DBG_SET_LOGD("%p", this); 103 // walk pictures back to front, removing or trimming obscured ones 104 SkRegion drawn; 105 SkRegion inval; 106 Pictures* first = mPictures.begin(); 107 Pictures* last = mPictures.end(); 108 Pictures* working; 109 bool checkForNewBases = false; 110 for (working = last; working != first; ) { 111 --working; 112 SkRegion& area = working->mArea; 113 SkRegion visibleArea(area); 114 visibleArea.op(drawn, SkRegion::kDifference_Op); 115#if PICTURE_SET_DEBUG 116 const SkIRect& a = area.getBounds(); 117 const SkIRect& d = drawn.getBounds(); 118 const SkIRect& i = inval.getBounds(); 119 const SkIRect& v = visibleArea.getBounds(); 120 DBG_SET_LOGD("%p [%d] area={%d,%d,r=%d,b=%d} drawn={%d,%d,r=%d,b=%d}" 121 " inval={%d,%d,r=%d,b=%d} vis={%d,%d,r=%d,b=%d}", 122 this, working - first, 123 a.fLeft, a.fTop, a.fRight, a.fBottom, 124 d.fLeft, d.fTop, d.fRight, d.fBottom, 125 i.fLeft, i.fTop, i.fRight, i.fBottom, 126 v.fLeft, v.fTop, v.fRight, v.fBottom); 127#endif 128 bool tossPicture = false; 129 if (working->mBase == false) { 130 if (area != visibleArea) { 131 if (visibleArea.isEmpty() == false) { 132 DBG_SET_LOGD("[%d] partially overdrawn", working - first); 133 inval.op(visibleArea, SkRegion::kUnion_Op); 134 } else 135 DBG_SET_LOGD("[%d] fully hidden", working - first); 136 area.setEmpty(); 137 tossPicture = true; 138 } 139 } else { 140 const SkIRect& visibleBounds = visibleArea.getBounds(); 141 const SkIRect& areaBounds = area.getBounds(); 142 if (visibleBounds != areaBounds) { 143 DBG_SET_LOGD("[%d] base to be reduced", working - first); 144 area.setRect(visibleBounds); 145 checkForNewBases = tossPicture = true; 146 } 147 if (area.intersects(inval)) { 148 DBG_SET_LOGD("[%d] base to be redrawn", working - first); 149 tossPicture = true; 150 } 151 } 152 if (tossPicture) { 153 working->mPicture->safeUnref(); 154 working->mPicture = NULL; // mark to redraw 155 } 156 if (working->mPicture == NULL) // may have been set to null elsewhere 157 rebuild = true; 158 drawn.op(area, SkRegion::kUnion_Op); 159 } 160 // collapse out empty regions 161 Pictures* writer = first; 162 for (working = first; working != last; working++) { 163 if (working->mArea.isEmpty()) 164 continue; 165 *writer++ = *working; 166 } 167#if PICTURE_SET_DEBUG 168 if ((unsigned) (writer - first) != mPictures.size()) 169 DBG_SET_LOGD("shrink=%d (was %d)", writer - first, mPictures.size()); 170#endif 171 mPictures.shrink(writer - first); 172 /* When a base is discarded because it was entirely drawn over, all 173 remaining pictures are checked to see if one has become a base. */ 174 if (checkForNewBases) { 175 drawn.setEmpty(); 176 Pictures* last = mPictures.end(); 177 for (working = mPictures.begin(); working != last; working++) { 178 SkRegion& area = working->mArea; 179 if (drawn.contains(working->mArea) == false) { 180 working->mBase = true; 181 DBG_SET_LOGD("[%d] new base", working - mPictures.begin()); 182 } 183 drawn.op(working->mArea, SkRegion::kUnion_Op); 184 } 185 } 186 validate(__FUNCTION__); 187 return rebuild; 188} 189 190void PictureSet::checkDimensions(int width, int height, SkRegion* inval) 191{ 192 if (mWidth == width && mHeight == height) 193 return; 194 DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this, 195 mWidth, mHeight, width, height); 196 if (mWidth == width && height > mHeight) { // only grew vertically 197 SkIRect rect; 198 rect.set(0, mHeight, width, height - mHeight); 199 inval->op(rect, SkRegion::kUnion_Op); 200 } else { 201 clear(); // if both width/height changed, clear the old cache 202 inval->setRect(0, 0, width, height); 203 } 204 mWidth = width; 205 mHeight = height; 206} 207 208void PictureSet::clear() 209{ 210 DBG_SET_LOG(""); 211 Pictures* last = mPictures.end(); 212 for (Pictures* working = mPictures.begin(); working != last; working++) { 213 working->mArea.setEmpty(); 214 working->mPicture->safeUnref(); 215 } 216 mPictures.clear(); 217 mWidth = mHeight = 0; 218} 219 220bool PictureSet::draw(SkCanvas* canvas) 221{ 222 validate(__FUNCTION__); 223 Pictures* first = mPictures.begin(); 224 Pictures* last = mPictures.end(); 225 Pictures* working; 226 SkRect bounds; 227 if (canvas->getClipBounds(&bounds) == false) 228 return false; 229 SkIRect irect; 230 bounds.roundOut(&irect); 231 for (working = last; working != first; ) { 232 --working; 233 if (working->mArea.contains(irect)) { 234#if PICTURE_SET_DEBUG 235 const SkIRect& b = working->mArea.getBounds(); 236 DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}" 237 " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom, 238 irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); 239#endif 240 first = working; 241 break; 242 } 243 } 244 DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(), 245 last - mPictures.begin()); 246 uint32_t maxElapsed = 0; 247 for (working = first; working != last; working++) { 248 const SkRegion& area = working->mArea; 249 if (area.quickReject(irect)) { 250#if PICTURE_SET_DEBUG 251 const SkIRect& b = area.getBounds(); 252 DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}" 253 " irect={%d,%d,%d,%d}", working - first, working, 254 b.fLeft, b.fTop, b.fRight, b.fBottom, 255 irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); 256#endif 257 working->mElapsed = 0; 258 continue; 259 } 260 int saved = canvas->save(); 261 SkRect pathBounds; 262 if (area.isComplex()) { 263 SkPath pathClip; 264 area.getBoundaryPath(&pathClip); 265 canvas->clipPath(pathClip); 266 pathBounds = pathClip.getBounds(); 267 } else { 268 pathBounds.set(area.getBounds()); 269 canvas->clipRect(pathBounds); 270 } 271 canvas->translate(pathBounds.fLeft, pathBounds.fTop); 272 canvas->save(); 273 uint32_t startTime = getThreadMsec(); 274 canvas->drawPicture(*working->mPicture); 275 size_t elapsed = working->mElapsed = getThreadMsec() - startTime; 276 working->mWroteElapsed = true; 277 if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE || 278 pathBounds.height() >= MIN_SPLITTABLE)) 279 maxElapsed = elapsed; 280 canvas->restoreToCount(saved); 281#define DRAW_TEST_IMAGE 01 282#if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG 283 SkColor color = 0x3f000000 | (0xffffff & (unsigned) working); 284 canvas->drawColor(color); 285 SkPaint paint; 286 color ^= 0x00ffffff; 287 paint.setColor(color); 288 char location[256]; 289 for (int x = area.getBounds().fLeft & ~0x3f; 290 x < area.getBounds().fRight; x += 0x40) { 291 for (int y = area.getBounds().fTop & ~0x3f; 292 y < area.getBounds().fBottom; y += 0x40) { 293 int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y); 294 canvas->drawText(location, len, x, y, paint); 295 } 296 } 297#endif 298 DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s", 299 working - first, working, 300 area.getBounds().fLeft, area.getBounds().fTop, 301 area.getBounds().fRight, area.getBounds().fBottom, 302 working->mElapsed, working->mBase ? "true" : "false"); 303 } 304 // dump(__FUNCTION__); 305 return maxElapsed >= MAX_DRAW_TIME; 306} 307 308void PictureSet::dump(const char* label) const 309{ 310#if PICTURE_SET_DUMP 311 DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(), 312 mWidth, mHeight); 313 const Pictures* last = mPictures.end(); 314 for (const Pictures* working = mPictures.begin(); working != last; working++) { 315 const SkIRect& bounds = working->mArea.getBounds(); 316 const SkIRect& unsplit = working->mUnsplit; 317 MeasureStream measure; 318 if (working->mPicture != NULL) 319 working->mPicture->serialize(&measure); 320 LOGD(" [%d]" 321 " mArea.bounds={%d,%d,r=%d,b=%d}" 322 " mPicture=%p" 323 " mUnsplit={%d,%d,r=%d,b=%d}" 324 " mElapsed=%d" 325 " mSplit=%s" 326 " mWroteElapsed=%s" 327 " mBase=%s" 328 " pict-size=%d", 329 working - mPictures.begin(), 330 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 331 working->mPicture, 332 unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom, 333 working->mElapsed, working->mSplit ? "true" : "false", 334 working->mWroteElapsed ? "true" : "false", 335 working->mBase ? "true" : "false", 336 measure.mTotal); 337 } 338#endif 339} 340 341class IsEmptyBounder : public SkBounder { 342 virtual bool onIRect(const SkIRect& rect) { 343 return false; 344 } 345}; 346 347class IsEmptyCanvas : public SkCanvas { 348public: 349 IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) : 350 mPicture(picture), mEmpty(true) { 351 setBounder(bounder); 352 } 353 354 void notEmpty() { 355 mEmpty = false; 356 mPicture->abortPlayback(); 357 } 358 359 virtual bool clipPath(const SkPath&, SkRegion::Op) { 360 // this can be expensive to actually do, and doesn't affect the 361 // question of emptiness, so we make it a no-op 362 return true; 363 } 364 365 virtual void commonDrawBitmap(const SkBitmap& bitmap, 366 const SkMatrix& , const SkPaint& ) { 367 if (bitmap.width() <= 1 || bitmap.height() <= 1) 368 return; 369 DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height()); 370 notEmpty(); 371 } 372 373 virtual void drawPaint(const SkPaint& paint) { 374 } 375 376 virtual void drawPath(const SkPath& , const SkPaint& paint) { 377 DBG_SET_LOG("abort"); 378 notEmpty(); 379 } 380 381 virtual void drawPoints(PointMode , size_t , const SkPoint [], 382 const SkPaint& paint) { 383 } 384 385 virtual void drawRect(const SkRect& , const SkPaint& paint) { 386 // wait for visual content 387 } 388 389 virtual void drawSprite(const SkBitmap& , int , int , 390 const SkPaint* paint = NULL) { 391 DBG_SET_LOG("abort"); 392 notEmpty(); 393 } 394 395 virtual void drawText(const void* , size_t byteLength, SkScalar , 396 SkScalar , const SkPaint& paint) { 397 DBG_SET_LOGD("abort %d", byteLength); 398 notEmpty(); 399 } 400 401 virtual void drawPosText(const void* , size_t byteLength, 402 const SkPoint [], const SkPaint& paint) { 403 DBG_SET_LOGD("abort %d", byteLength); 404 notEmpty(); 405 } 406 407 virtual void drawPosTextH(const void* , size_t byteLength, 408 const SkScalar [], SkScalar , 409 const SkPaint& paint) { 410 DBG_SET_LOGD("abort %d", byteLength); 411 notEmpty(); 412 } 413 414 virtual void drawTextOnPath(const void* , size_t byteLength, 415 const SkPath& , const SkMatrix* , 416 const SkPaint& paint) { 417 DBG_SET_LOGD("abort %d", byteLength); 418 notEmpty(); 419 } 420 421 virtual void drawPicture(SkPicture& picture) { 422 SkCanvas::drawPicture(picture); 423 } 424 425 SkPicture* mPicture; 426 bool mEmpty; 427}; 428 429bool PictureSet::emptyPicture(SkPicture* picture) const 430{ 431 IsEmptyBounder isEmptyBounder; 432 IsEmptyCanvas checker(&isEmptyBounder, picture); 433 SkBitmap bitmap; 434 bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight); 435 checker.setBitmapDevice(bitmap); 436 checker.drawPicture(*picture); 437 return checker.mEmpty; 438} 439 440bool PictureSet::isEmpty() const 441{ 442 const Pictures* last = mPictures.end(); 443 for (const Pictures* working = mPictures.begin(); working != last; working++) { 444 if (!working->mEmpty) 445 return false; 446 } 447 return true; 448} 449 450bool PictureSet::reuseSubdivided(const SkRegion& inval) 451{ 452 validate(__FUNCTION__); 453 if (inval.isComplex()) 454 return false; 455 Pictures* working, * last = mPictures.end(); 456 const SkIRect& invalBounds = inval.getBounds(); 457 bool steal = false; 458 for (working = mPictures.begin(); working != last; working++) { 459 if (working->mSplit && invalBounds == working->mUnsplit) { 460 steal = true; 461 continue; 462 } 463 if (steal == false) 464 continue; 465 SkRegion temp = SkRegion(inval); 466 temp.op(working->mArea, SkRegion::kIntersect_Op); 467 if (temp.isEmpty() || temp == working->mArea) 468 continue; 469 return false; 470 } 471 if (steal == false) 472 return false; 473 for (working = mPictures.begin(); working != last; working++) { 474 if ((working->mSplit == false || invalBounds != working->mUnsplit) && 475 inval.contains(working->mArea) == false) 476 continue; 477 working->mPicture->safeUnref(); 478 working->mPicture = NULL; 479 } 480 return true; 481} 482 483void PictureSet::set(const PictureSet& src) 484{ 485 DBG_SET_LOGD("start %p src=%p", this, &src); 486 clear(); 487 mWidth = src.mWidth; 488 mHeight = src.mHeight; 489 const Pictures* last = src.mPictures.end(); 490 for (const Pictures* working = src.mPictures.begin(); working != last; working++) 491 add(working); 492 // dump(__FUNCTION__); 493 validate(__FUNCTION__); 494 DBG_SET_LOG("end"); 495} 496 497void PictureSet::setDrawTimes(const PictureSet& src) 498{ 499 validate(__FUNCTION__); 500 if (mWidth != src.mWidth || mHeight != src.mHeight) 501 return; 502 Pictures* last = mPictures.end(); 503 Pictures* working = mPictures.begin(); 504 if (working == last) 505 return; 506 const Pictures* srcLast = src.mPictures.end(); 507 const Pictures* srcWorking = src.mPictures.begin(); 508 for (; srcWorking != srcLast; srcWorking++) { 509 if (srcWorking->mWroteElapsed == false) 510 continue; 511 while ((srcWorking->mArea != working->mArea || 512 srcWorking->mPicture != working->mPicture)) { 513 if (++working == last) 514 return; 515 } 516 DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d", 517 this, working - mPictures.begin(), srcWorking - src.mPictures.begin(), 518 working->mArea.getBounds().fLeft, working->mArea.getBounds().fTop, 519 working->mArea.getBounds().fRight, working->mArea.getBounds().fBottom, 520 working->mElapsed, srcWorking->mElapsed); 521 working->mElapsed = srcWorking->mElapsed; 522 } 523} 524 525void PictureSet::setPicture(size_t i, SkPicture* p) 526{ 527 mPictures[i].mPicture->safeUnref(); 528 mPictures[i].mPicture = p; 529 mPictures[i].mEmpty = emptyPicture(p); 530} 531 532void PictureSet::split(PictureSet* out) const 533{ 534 dump(__FUNCTION__); 535 DBG_SET_LOGD("%p", this); 536 SkIRect totalBounds; 537 out->mWidth = mWidth; 538 out->mHeight = mHeight; 539 totalBounds.set(0, 0, mWidth, mHeight); 540 SkRegion* total = new SkRegion(totalBounds); 541 const Pictures* last = mPictures.end(); 542 const Pictures* working; 543 uint32_t balance = 0; 544 int multiUnsplitFastPictures = 0; // > 1 has more than 1 545 for (working = mPictures.begin(); working != last; working++) { 546 if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit) 547 continue; 548 if (++multiUnsplitFastPictures > 1) 549 break; 550 } 551 for (working = mPictures.begin(); working != last; working++) { 552 uint32_t elapsed = working->mElapsed; 553 if (elapsed < MAX_DRAW_TIME) { 554 bool split = working->mSplit; 555 DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()=" 556 "{%d,%d,r=%d,b=%d} split=%s", elapsed, working, 557 total->getBounds().fLeft, total->getBounds().fTop, 558 total->getBounds().fRight, total->getBounds().fBottom, 559 split ? "true" : "false"); 560 if (multiUnsplitFastPictures <= 1 || split) { 561 total->op(working->mArea, SkRegion::kDifference_Op); 562 out->add(working->mArea, working->mPicture, elapsed, split, 563 working->mEmpty); 564 } else if (balance < elapsed) 565 balance = elapsed; 566 continue; 567 } 568 total->op(working->mArea, SkRegion::kDifference_Op); 569 const SkIRect& bounds = working->mArea.getBounds(); 570 int width = bounds.width(); 571 int height = bounds.height(); 572 int across = 1; 573 int down = 1; 574 while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) { 575 if (height >= width) { 576 height >>= 1; 577 down <<= 1; 578 } else { 579 width >>= 1; 580 across <<= 1 ; 581 } 582 if ((elapsed >>= 1) < MAX_DRAW_TIME) 583 break; 584 } 585 width = bounds.width(); 586 height = bounds.height(); 587 int top = bounds.fTop; 588 for (int indexY = 0; indexY < down; ) { 589 int bottom = bounds.fTop + height * ++indexY / down; 590 int left = bounds.fLeft; 591 for (int indexX = 0; indexX < across; ) { 592 int right = bounds.fLeft + width * ++indexX / across; 593 SkIRect cBounds; 594 cBounds.set(left, top, right, bottom); 595 out->add(SkRegion(cBounds), (across | down) != 1 ? NULL : 596 working->mPicture, elapsed, true, 597 (across | down) != 1 ? false : working->mEmpty); 598 left = right; 599 } 600 top = bottom; 601 } 602 } 603 DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d", 604 this, mWidth, mHeight, total->isEmpty() ? "true" : "false", 605 multiUnsplitFastPictures); 606 if (!total->isEmpty() && multiUnsplitFastPictures > 1) 607 out->add(*total, NULL, balance, false, false); 608 delete total; 609 validate(__FUNCTION__); 610 out->dump("split-out"); 611} 612 613bool PictureSet::validate(const char* funct) const 614{ 615 bool valid = true; 616#if PICTURE_SET_VALIDATE 617 SkRegion all; 618 const Pictures* first = mPictures.begin(); 619 for (const Pictures* working = mPictures.end(); working != first; ) { 620 --working; 621 const SkPicture* pict = working->mPicture; 622 const SkRegion& area = working->mArea; 623 const SkIRect& bounds = area.getBounds(); 624 bool localValid = false; 625 if (working->mUnsplit.isEmpty()) 626 LOGD("%s working->mUnsplit.isEmpty()", funct); 627 else if (working->mUnsplit.contains(bounds) == false) 628 LOGD("%s working->mUnsplit.contains(bounds) == false", funct); 629 else if (working->mElapsed >= 1000) 630 LOGD("%s working->mElapsed >= 1000", funct); 631 else if ((working->mSplit & 0xfe) != 0) 632 LOGD("%s (working->mSplit & 0xfe) != 0", funct); 633 else if ((working->mWroteElapsed & 0xfe) != 0) 634 LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); 635 else if (pict != NULL) { 636 int pictWidth = pict->width(); 637 int pictHeight = pict->height(); 638 if (pictWidth < bounds.width()) 639 LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); 640 else if (pictHeight < bounds.height()) 641 LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); 642 else if (working->mArea.isEmpty()) 643 LOGD("%s working->mArea.isEmpty()", funct); 644 else 645 localValid = true; 646 } else 647 localValid = true; 648 working->mArea.validate(); 649 if (localValid == false) { 650 if (all.contains(area) == true) 651 LOGD("%s all.contains(area) == true", funct); 652 else 653 localValid = true; 654 } 655 valid &= localValid; 656 all.op(area, SkRegion::kUnion_Op); 657 } 658 const SkIRect& allBounds = all.getBounds(); 659 if (valid) { 660 valid = false; 661 if (allBounds.width() != mWidth) 662 LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); 663 else if (allBounds.height() != mHeight) 664 LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); 665 else 666 valid = true; 667 } 668 while (valid == false) 669 ; 670#endif 671 return valid; 672} 673 674} /* namespace android */ 675