| /* |
| * Copyright 2008, The Android Open Source Project |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #define LOG_NDEBUG 0 |
| #define LOG_TAG "pictureset" |
| |
| //#include <config.h> |
| #include "CachedPrefix.h" |
| #include "android_graphics.h" |
| #include "PictureSet.h" |
| #include "SkBounder.h" |
| #include "SkCanvas.h" |
| #include "SkPicture.h" |
| #include "SkRect.h" |
| #include "SkRegion.h" |
| #include "SkStream.h" |
| #include "TimeCounter.h" |
| |
| #define MAX_DRAW_TIME 100 |
| #define MIN_SPLITTABLE 400 |
| |
| #if PICTURE_SET_DEBUG |
| class MeasureStream : public SkWStream { |
| public: |
| MeasureStream() : mTotal(0) {} |
| virtual bool write(const void* , size_t size) { |
| mTotal += size; |
| return true; |
| } |
| size_t mTotal; |
| }; |
| #endif |
| |
| namespace android { |
| |
| PictureSet::PictureSet() |
| { |
| mWidth = mHeight = 0; |
| } |
| |
| PictureSet::~PictureSet() |
| { |
| clear(); |
| } |
| |
| void PictureSet::add(const Pictures* temp) |
| { |
| Pictures pictureAndBounds = *temp; |
| pictureAndBounds.mPicture->safeRef(); |
| pictureAndBounds.mWroteElapsed = false; |
| mPictures.append(pictureAndBounds); |
| } |
| |
| void PictureSet::add(const SkRegion& area, SkPicture* picture, |
| uint32_t elapsed, bool split, bool empty) |
| { |
| DBG_SET_LOGD("%p area={%d,%d,r=%d,b=%d} pict=%p elapsed=%d split=%d", this, |
| area.getBounds().fLeft, area.getBounds().fTop, |
| area.getBounds().fRight, area.getBounds().fBottom, picture, |
| elapsed, split); |
| picture->safeRef(); |
| /* if nothing is drawn beneath part of the new picture, mark it as a base */ |
| SkRegion diff = SkRegion(area); |
| Pictures* last = mPictures.end(); |
| for (Pictures* working = mPictures.begin(); working != last; working++) |
| diff.op(working->mArea, SkRegion::kDifference_Op); |
| Pictures pictureAndBounds = {area, picture, area.getBounds(), |
| elapsed, split, false, diff.isEmpty() == false, empty}; |
| mPictures.append(pictureAndBounds); |
| } |
| |
| /* |
| Pictures are discarded when they are fully drawn over. |
| When a picture is partially drawn over, it is discarded if it is not a base, and |
| its rectangular bounds is reduced if it is a base. |
| */ |
| bool PictureSet::build() |
| { |
| bool rebuild = false; |
| DBG_SET_LOGD("%p", this); |
| // walk pictures back to front, removing or trimming obscured ones |
| SkRegion drawn; |
| SkRegion inval; |
| Pictures* first = mPictures.begin(); |
| Pictures* last = mPictures.end(); |
| Pictures* working; |
| bool checkForNewBases = false; |
| for (working = last; working != first; ) { |
| --working; |
| SkRegion& area = working->mArea; |
| SkRegion visibleArea(area); |
| visibleArea.op(drawn, SkRegion::kDifference_Op); |
| #if PICTURE_SET_DEBUG |
| const SkIRect& a = area.getBounds(); |
| const SkIRect& d = drawn.getBounds(); |
| const SkIRect& i = inval.getBounds(); |
| const SkIRect& v = visibleArea.getBounds(); |
| DBG_SET_LOGD("%p [%d] area={%d,%d,r=%d,b=%d} drawn={%d,%d,r=%d,b=%d}" |
| " inval={%d,%d,r=%d,b=%d} vis={%d,%d,r=%d,b=%d}", |
| this, working - first, |
| a.fLeft, a.fTop, a.fRight, a.fBottom, |
| d.fLeft, d.fTop, d.fRight, d.fBottom, |
| i.fLeft, i.fTop, i.fRight, i.fBottom, |
| v.fLeft, v.fTop, v.fRight, v.fBottom); |
| #endif |
| bool tossPicture = false; |
| if (working->mBase == false) { |
| if (area != visibleArea) { |
| if (visibleArea.isEmpty() == false) { |
| DBG_SET_LOGD("[%d] partially overdrawn", working - first); |
| inval.op(visibleArea, SkRegion::kUnion_Op); |
| } else |
| DBG_SET_LOGD("[%d] fully hidden", working - first); |
| area.setEmpty(); |
| tossPicture = true; |
| } |
| } else { |
| const SkIRect& visibleBounds = visibleArea.getBounds(); |
| const SkIRect& areaBounds = area.getBounds(); |
| if (visibleBounds != areaBounds) { |
| DBG_SET_LOGD("[%d] base to be reduced", working - first); |
| area.setRect(visibleBounds); |
| checkForNewBases = tossPicture = true; |
| } |
| if (area.intersects(inval)) { |
| DBG_SET_LOGD("[%d] base to be redrawn", working - first); |
| tossPicture = true; |
| } |
| } |
| if (tossPicture) { |
| working->mPicture->safeUnref(); |
| working->mPicture = NULL; // mark to redraw |
| } |
| if (working->mPicture == NULL) // may have been set to null elsewhere |
| rebuild = true; |
| drawn.op(area, SkRegion::kUnion_Op); |
| } |
| // collapse out empty regions |
| Pictures* writer = first; |
| for (working = first; working != last; working++) { |
| if (working->mArea.isEmpty()) |
| continue; |
| *writer++ = *working; |
| } |
| #if PICTURE_SET_DEBUG |
| if ((unsigned) (writer - first) != mPictures.size()) |
| DBG_SET_LOGD("shrink=%d (was %d)", writer - first, mPictures.size()); |
| #endif |
| mPictures.shrink(writer - first); |
| /* When a base is discarded because it was entirely drawn over, all |
| remaining pictures are checked to see if one has become a base. */ |
| if (checkForNewBases) { |
| drawn.setEmpty(); |
| Pictures* last = mPictures.end(); |
| for (working = mPictures.begin(); working != last; working++) { |
| SkRegion& area = working->mArea; |
| if (drawn.contains(working->mArea) == false) { |
| working->mBase = true; |
| DBG_SET_LOGD("[%d] new base", working - mPictures.begin()); |
| } |
| drawn.op(working->mArea, SkRegion::kUnion_Op); |
| } |
| } |
| validate(__FUNCTION__); |
| return rebuild; |
| } |
| |
| void PictureSet::checkDimensions(int width, int height, SkRegion* inval) |
| { |
| if (mWidth == width && mHeight == height) |
| return; |
| DBG_SET_LOGD("%p old:(w=%d,h=%d) new:(w=%d,h=%d)", this, |
| mWidth, mHeight, width, height); |
| if (mWidth == width && height > mHeight) { // only grew vertically |
| SkIRect rect; |
| rect.set(0, mHeight, width, height - mHeight); |
| inval->op(rect, SkRegion::kUnion_Op); |
| } else { |
| clear(); // if both width/height changed, clear the old cache |
| inval->setRect(0, 0, width, height); |
| } |
| mWidth = width; |
| mHeight = height; |
| } |
| |
| void PictureSet::clear() |
| { |
| DBG_SET_LOG(""); |
| Pictures* last = mPictures.end(); |
| for (Pictures* working = mPictures.begin(); working != last; working++) { |
| working->mArea.setEmpty(); |
| working->mPicture->safeUnref(); |
| } |
| mPictures.clear(); |
| mWidth = mHeight = 0; |
| } |
| |
| bool PictureSet::draw(SkCanvas* canvas) |
| { |
| validate(__FUNCTION__); |
| Pictures* first = mPictures.begin(); |
| Pictures* last = mPictures.end(); |
| Pictures* working; |
| SkRect bounds; |
| if (canvas->getClipBounds(&bounds) == false) |
| return false; |
| SkIRect irect; |
| bounds.roundOut(&irect); |
| for (working = last; working != first; ) { |
| --working; |
| if (working->mArea.contains(irect)) { |
| #if PICTURE_SET_DEBUG |
| const SkIRect& b = working->mArea.getBounds(); |
| DBG_SET_LOGD("contains working->mArea={%d,%d,%d,%d}" |
| " irect={%d,%d,%d,%d}", b.fLeft, b.fTop, b.fRight, b.fBottom, |
| irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); |
| #endif |
| first = working; |
| break; |
| } |
| } |
| DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(), |
| last - mPictures.begin()); |
| uint32_t maxElapsed = 0; |
| for (working = first; working != last; working++) { |
| const SkRegion& area = working->mArea; |
| if (area.quickReject(irect)) { |
| #if PICTURE_SET_DEBUG |
| const SkIRect& b = area.getBounds(); |
| DBG_SET_LOGD("[%d] %p quickReject working->mArea={%d,%d,%d,%d}" |
| " irect={%d,%d,%d,%d}", working - first, working, |
| b.fLeft, b.fTop, b.fRight, b.fBottom, |
| irect.fLeft, irect.fTop, irect.fRight, irect.fBottom); |
| #endif |
| working->mElapsed = 0; |
| continue; |
| } |
| int saved = canvas->save(); |
| SkRect pathBounds; |
| if (area.isComplex()) { |
| SkPath pathClip; |
| area.getBoundaryPath(&pathClip); |
| canvas->clipPath(pathClip); |
| pathBounds = pathClip.getBounds(); |
| } else { |
| pathBounds.set(area.getBounds()); |
| canvas->clipRect(pathBounds); |
| } |
| canvas->translate(pathBounds.fLeft, pathBounds.fTop); |
| canvas->save(); |
| uint32_t startTime = getThreadMsec(); |
| canvas->drawPicture(*working->mPicture); |
| size_t elapsed = working->mElapsed = getThreadMsec() - startTime; |
| working->mWroteElapsed = true; |
| if (maxElapsed < elapsed && (pathBounds.width() >= MIN_SPLITTABLE || |
| pathBounds.height() >= MIN_SPLITTABLE)) |
| maxElapsed = elapsed; |
| canvas->restoreToCount(saved); |
| #define DRAW_TEST_IMAGE 01 |
| #if DRAW_TEST_IMAGE && PICTURE_SET_DEBUG |
| SkColor color = 0x3f000000 | (0xffffff & (unsigned) working); |
| canvas->drawColor(color); |
| SkPaint paint; |
| color ^= 0x00ffffff; |
| paint.setColor(color); |
| char location[256]; |
| for (int x = area.getBounds().fLeft & ~0x3f; |
| x < area.getBounds().fRight; x += 0x40) { |
| for (int y = area.getBounds().fTop & ~0x3f; |
| y < area.getBounds().fBottom; y += 0x40) { |
| int len = snprintf(location, sizeof(location) - 1, "(%d,%d)", x, y); |
| canvas->drawText(location, len, x, y, paint); |
| } |
| } |
| #endif |
| DBG_SET_LOGD("[%d] %p working->mArea={%d,%d,%d,%d} elapsed=%d base=%s", |
| working - first, working, |
| area.getBounds().fLeft, area.getBounds().fTop, |
| area.getBounds().fRight, area.getBounds().fBottom, |
| working->mElapsed, working->mBase ? "true" : "false"); |
| } |
| // dump(__FUNCTION__); |
| return maxElapsed >= MAX_DRAW_TIME; |
| } |
| |
| void PictureSet::dump(const char* label) const |
| { |
| #if PICTURE_SET_DUMP |
| DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(), |
| mWidth, mHeight); |
| const Pictures* last = mPictures.end(); |
| for (const Pictures* working = mPictures.begin(); working != last; working++) { |
| const SkIRect& bounds = working->mArea.getBounds(); |
| const SkIRect& unsplit = working->mUnsplit; |
| MeasureStream measure; |
| if (working->mPicture != NULL) |
| working->mPicture->serialize(&measure); |
| LOGD(" [%d]" |
| " mArea.bounds={%d,%d,r=%d,b=%d}" |
| " mPicture=%p" |
| " mUnsplit={%d,%d,r=%d,b=%d}" |
| " mElapsed=%d" |
| " mSplit=%s" |
| " mWroteElapsed=%s" |
| " mBase=%s" |
| " pict-size=%d", |
| working - mPictures.begin(), |
| bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, |
| working->mPicture, |
| unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom, |
| working->mElapsed, working->mSplit ? "true" : "false", |
| working->mWroteElapsed ? "true" : "false", |
| working->mBase ? "true" : "false", |
| measure.mTotal); |
| } |
| #endif |
| } |
| |
| class IsEmptyBounder : public SkBounder { |
| virtual bool onIRect(const SkIRect& rect) { |
| return false; |
| } |
| }; |
| |
| class IsEmptyCanvas : public SkCanvas { |
| public: |
| IsEmptyCanvas(SkBounder* bounder, SkPicture* picture) : |
| mPicture(picture), mEmpty(true) { |
| setBounder(bounder); |
| } |
| |
| void notEmpty() { |
| mEmpty = false; |
| mPicture->abortPlayback(); |
| } |
| |
| virtual void commonDrawBitmap(const SkBitmap& bitmap, |
| const SkMatrix& , const SkPaint& ) { |
| if (bitmap.width() <= 1 || bitmap.height() <= 1) |
| return; |
| DBG_SET_LOGD("abort {%d,%d}", bitmap.width(), bitmap.height()); |
| notEmpty(); |
| } |
| |
| virtual void drawPaint(const SkPaint& paint) { |
| } |
| |
| virtual void drawPath(const SkPath& , const SkPaint& paint) { |
| DBG_SET_LOG("abort"); |
| notEmpty(); |
| } |
| |
| virtual void drawPoints(PointMode , size_t , const SkPoint [], |
| const SkPaint& paint) { |
| } |
| |
| virtual void drawRect(const SkRect& , const SkPaint& paint) { |
| // wait for visual content |
| } |
| |
| virtual void drawSprite(const SkBitmap& , int , int , |
| const SkPaint* paint = NULL) { |
| DBG_SET_LOG("abort"); |
| notEmpty(); |
| } |
| |
| virtual void drawText(const void* , size_t byteLength, SkScalar , |
| SkScalar , const SkPaint& paint) { |
| DBG_SET_LOGD("abort %d", byteLength); |
| notEmpty(); |
| } |
| |
| virtual void drawPosText(const void* , size_t byteLength, |
| const SkPoint [], const SkPaint& paint) { |
| DBG_SET_LOGD("abort %d", byteLength); |
| notEmpty(); |
| } |
| |
| virtual void drawPosTextH(const void* , size_t byteLength, |
| const SkScalar [], SkScalar , |
| const SkPaint& paint) { |
| DBG_SET_LOGD("abort %d", byteLength); |
| notEmpty(); |
| } |
| |
| virtual void drawTextOnPath(const void* , size_t byteLength, |
| const SkPath& , const SkMatrix* , |
| const SkPaint& paint) { |
| DBG_SET_LOGD("abort %d", byteLength); |
| notEmpty(); |
| } |
| |
| virtual void drawPicture(SkPicture& picture) { |
| SkCanvas::drawPicture(picture); |
| } |
| |
| SkPicture* mPicture; |
| bool mEmpty; |
| }; |
| |
| bool PictureSet::emptyPicture(SkPicture* picture) const |
| { |
| IsEmptyBounder isEmptyBounder; |
| IsEmptyCanvas checker(&isEmptyBounder, picture); |
| SkBitmap bitmap; |
| bitmap.setConfig(SkBitmap::kARGB_8888_Config, mWidth, mHeight); |
| checker.setBitmapDevice(bitmap); |
| checker.drawPicture(*picture); |
| return checker.mEmpty; |
| } |
| |
| bool PictureSet::isEmpty() const |
| { |
| const Pictures* last = mPictures.end(); |
| for (const Pictures* working = mPictures.begin(); working != last; working++) { |
| if (!working->mEmpty) |
| return false; |
| } |
| return true; |
| } |
| |
| bool PictureSet::reuseSubdivided(const SkRegion& inval) |
| { |
| validate(__FUNCTION__); |
| if (inval.isComplex()) |
| return false; |
| Pictures* working, * last = mPictures.end(); |
| const SkIRect& invalBounds = inval.getBounds(); |
| bool steal = false; |
| for (working = mPictures.begin(); working != last; working++) { |
| if (working->mSplit && invalBounds == working->mUnsplit) { |
| steal = true; |
| continue; |
| } |
| if (steal == false) |
| continue; |
| SkRegion temp = SkRegion(inval); |
| temp.op(working->mArea, SkRegion::kIntersect_Op); |
| if (temp.isEmpty() || temp == working->mArea) |
| continue; |
| return false; |
| } |
| if (steal == false) |
| return false; |
| for (working = mPictures.begin(); working != last; working++) { |
| if ((working->mSplit == false || invalBounds != working->mUnsplit) && |
| inval.contains(working->mArea) == false) |
| continue; |
| working->mPicture->safeUnref(); |
| working->mPicture = NULL; |
| } |
| return true; |
| } |
| |
| void PictureSet::set(const PictureSet& src) |
| { |
| DBG_SET_LOGD("start %p src=%p", this, &src); |
| clear(); |
| mWidth = src.mWidth; |
| mHeight = src.mHeight; |
| const Pictures* last = src.mPictures.end(); |
| for (const Pictures* working = src.mPictures.begin(); working != last; working++) |
| add(working); |
| // dump(__FUNCTION__); |
| validate(__FUNCTION__); |
| DBG_SET_LOG("end"); |
| } |
| |
| void PictureSet::setDrawTimes(const PictureSet& src) |
| { |
| validate(__FUNCTION__); |
| if (mWidth != src.mWidth || mHeight != src.mHeight) |
| return; |
| Pictures* last = mPictures.end(); |
| Pictures* working = mPictures.begin(); |
| if (working == last) |
| return; |
| const Pictures* srcLast = src.mPictures.end(); |
| const Pictures* srcWorking = src.mPictures.begin(); |
| for (; srcWorking != srcLast; srcWorking++) { |
| if (srcWorking->mWroteElapsed == false) |
| continue; |
| while ((srcWorking->mArea != working->mArea || |
| srcWorking->mPicture != working->mPicture)) { |
| if (++working == last) |
| return; |
| } |
| DBG_SET_LOGD("%p [%d] [%d] {%d,%d,r=%d,b=%d} working->mElapsed=%d <- %d", |
| this, working - mPictures.begin(), srcWorking - src.mPictures.begin(), |
| working->mArea.getBounds().fLeft, working->mArea.getBounds().fTop, |
| working->mArea.getBounds().fRight, working->mArea.getBounds().fBottom, |
| working->mElapsed, srcWorking->mElapsed); |
| working->mElapsed = srcWorking->mElapsed; |
| } |
| } |
| |
| void PictureSet::setPicture(size_t i, SkPicture* p) |
| { |
| mPictures[i].mPicture->safeUnref(); |
| mPictures[i].mPicture = p; |
| mPictures[i].mEmpty = emptyPicture(p); |
| } |
| |
| void PictureSet::split(PictureSet* out) const |
| { |
| dump(__FUNCTION__); |
| DBG_SET_LOGD("%p", this); |
| SkIRect totalBounds; |
| out->mWidth = mWidth; |
| out->mHeight = mHeight; |
| totalBounds.set(0, 0, mWidth, mHeight); |
| SkRegion* total = new SkRegion(totalBounds); |
| const Pictures* last = mPictures.end(); |
| const Pictures* working; |
| uint32_t balance = 0; |
| int multiUnsplitFastPictures = 0; // > 1 has more than 1 |
| for (working = mPictures.begin(); working != last; working++) { |
| if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit) |
| continue; |
| if (++multiUnsplitFastPictures > 1) |
| break; |
| } |
| for (working = mPictures.begin(); working != last; working++) { |
| uint32_t elapsed = working->mElapsed; |
| if (elapsed < MAX_DRAW_TIME) { |
| bool split = working->mSplit; |
| DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()=" |
| "{%d,%d,r=%d,b=%d} split=%s", elapsed, working, |
| total->getBounds().fLeft, total->getBounds().fTop, |
| total->getBounds().fRight, total->getBounds().fBottom, |
| split ? "true" : "false"); |
| if (multiUnsplitFastPictures <= 1 || split) { |
| total->op(working->mArea, SkRegion::kDifference_Op); |
| out->add(working->mArea, working->mPicture, elapsed, split, |
| working->mEmpty); |
| } else if (balance < elapsed) |
| balance = elapsed; |
| continue; |
| } |
| total->op(working->mArea, SkRegion::kDifference_Op); |
| const SkIRect& bounds = working->mArea.getBounds(); |
| int width = bounds.width(); |
| int height = bounds.height(); |
| int across = 1; |
| int down = 1; |
| while (height >= MIN_SPLITTABLE || width >= MIN_SPLITTABLE) { |
| if (height >= width) { |
| height >>= 1; |
| down <<= 1; |
| } else { |
| width >>= 1; |
| across <<= 1 ; |
| } |
| if ((elapsed >>= 1) < MAX_DRAW_TIME) |
| break; |
| } |
| width = bounds.width(); |
| height = bounds.height(); |
| int top = bounds.fTop; |
| for (int indexY = 0; indexY < down; ) { |
| int bottom = bounds.fTop + height * ++indexY / down; |
| int left = bounds.fLeft; |
| for (int indexX = 0; indexX < across; ) { |
| int right = bounds.fLeft + width * ++indexX / across; |
| SkIRect cBounds; |
| cBounds.set(left, top, right, bottom); |
| out->add(SkRegion(cBounds), (across | down) != 1 ? NULL : |
| working->mPicture, elapsed, true, |
| (across | down) != 1 ? false : working->mEmpty); |
| left = right; |
| } |
| top = bottom; |
| } |
| } |
| DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d", |
| this, mWidth, mHeight, total->isEmpty() ? "true" : "false", |
| multiUnsplitFastPictures); |
| if (!total->isEmpty() && multiUnsplitFastPictures > 1) |
| out->add(*total, NULL, balance, false, false); |
| delete total; |
| validate(__FUNCTION__); |
| out->dump("split-out"); |
| } |
| |
| bool PictureSet::validate(const char* funct) const |
| { |
| bool valid = true; |
| #if PICTURE_SET_VALIDATE |
| SkRegion all; |
| const Pictures* first = mPictures.begin(); |
| for (const Pictures* working = mPictures.end(); working != first; ) { |
| --working; |
| const SkPicture* pict = working->mPicture; |
| const SkRegion& area = working->mArea; |
| const SkIRect& bounds = area.getBounds(); |
| bool localValid = false; |
| if (working->mUnsplit.isEmpty()) |
| LOGD("%s working->mUnsplit.isEmpty()", funct); |
| else if (working->mUnsplit.contains(bounds) == false) |
| LOGD("%s working->mUnsplit.contains(bounds) == false", funct); |
| else if (working->mElapsed >= 1000) |
| LOGD("%s working->mElapsed >= 1000", funct); |
| else if ((working->mSplit & 0xfe) != 0) |
| LOGD("%s (working->mSplit & 0xfe) != 0", funct); |
| else if ((working->mWroteElapsed & 0xfe) != 0) |
| LOGD("%s (working->mWroteElapsed & 0xfe) != 0", funct); |
| else if (pict != NULL) { |
| int pictWidth = pict->width(); |
| int pictHeight = pict->height(); |
| if (pictWidth < bounds.width()) |
| LOGD("%s pictWidth=%d < bounds.width()=%d", funct, pictWidth, bounds.width()); |
| else if (pictHeight < bounds.height()) |
| LOGD("%s pictHeight=%d < bounds.height()=%d", funct, pictHeight, bounds.height()); |
| else if (working->mArea.isEmpty()) |
| LOGD("%s working->mArea.isEmpty()", funct); |
| else |
| localValid = true; |
| } else |
| localValid = true; |
| working->mArea.validate(); |
| if (localValid == false) { |
| if (all.contains(area) == true) |
| LOGD("%s all.contains(area) == true", funct); |
| else |
| localValid = true; |
| } |
| valid &= localValid; |
| all.op(area, SkRegion::kUnion_Op); |
| } |
| const SkIRect& allBounds = all.getBounds(); |
| if (valid) { |
| valid = false; |
| if (allBounds.width() != mWidth) |
| LOGD("%s allBounds.width()=%d != mWidth=%d", funct, allBounds.width(), mWidth); |
| else if (allBounds.height() != mHeight) |
| LOGD("%s allBounds.height()=%d != mHeight=%d", funct, allBounds.height(), mHeight); |
| else |
| valid = true; |
| } |
| while (valid == false) |
| ; |
| #endif |
| return valid; |
| } |
| |
| } /* namespace android */ |