Index: skia/ext/skia_utils_mac.mm |
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm |
index 4f7ddd98f2d152af67c793b75435c2b89455ba3e..d6b604169f0238c727af4784e80fadfe543df447 100644 |
--- a/skia/ext/skia_utils_mac.mm |
+++ b/skia/ext/skia_utils_mac.mm |
@@ -267,81 +267,107 @@ NSImage* SkBitmapToNSImage(const SkBitmap& skiaBitmap) { |
SkiaBitLocker::SkiaBitLocker(SkCanvas* canvas) |
: canvas_(canvas), |
- cgContext_(0) { |
+ userClipRectSpecified_(false), |
+ cgContext_(0), |
+ useDeviceBits_(false), |
+ bitmapIsDummy_(false) { |
+} |
+ |
+SkiaBitLocker::SkiaBitLocker(SkCanvas* canvas, const SkIRect& userClipRect) |
+ : canvas_(canvas), |
+ userClipRectSpecified_(true), |
+ cgContext_(0), |
+ useDeviceBits_(false), |
+ bitmapIsDummy_(false) { |
+ canvas_->save(); |
+ canvas_->clipRect(SkRect::MakeFromIRect(userClipRect)); |
} |
SkiaBitLocker::~SkiaBitLocker() { |
releaseIfNeeded(); |
+ if (userClipRectSpecified_) |
+ canvas_->restore(); |
} |
-// This must be called to balance calls to cgContext |
-void SkiaBitLocker::releaseIfNeeded() { |
- if (!cgContext_) |
- return; |
- if (useDeviceBits_) { |
- bitmap_.unlockPixels(); |
- } else { |
- // Find the bits that were drawn to. |
- SkAutoLockPixels lockedPixels(bitmap_); |
- const uint32_t* pixelBase |
- = reinterpret_cast<uint32_t*>(bitmap_.getPixels()); |
- int rowPixels = bitmap_.rowBytesAsPixels(); |
- int width = bitmap_.width(); |
- int height = bitmap_.height(); |
- SkIRect bounds; |
- bounds.fTop = 0; |
- int x; |
- int y = -1; |
- const uint32_t* pixels = pixelBase; |
- while (++y < height) { |
- for (x = 0; x < width; ++x) { |
- if (pixels[x]) { |
- bounds.fTop = y; |
- goto foundTop; |
- } |
+SkIRect SkiaBitLocker::computeDirtyRect() { |
+ // If the user specified a clip region, assume that it was tight and that the |
+ // dirty rect is approximately the whole bitmap. |
+ if (userClipRectSpecified_) |
+ return SkIRect::MakeWH(bitmap_.width(), bitmap_.height()); |
+ |
+ // Find the bits that were drawn to. |
+ SkAutoLockPixels lockedPixels(bitmap_); |
+ const uint32_t* pixelBase |
+ = reinterpret_cast<uint32_t*>(bitmap_.getPixels()); |
+ int rowPixels = bitmap_.rowBytesAsPixels(); |
+ int width = bitmap_.width(); |
+ int height = bitmap_.height(); |
+ SkIRect bounds; |
+ bounds.fTop = 0; |
+ int x; |
+ int y = -1; |
+ const uint32_t* pixels = pixelBase; |
+ while (++y < height) { |
+ for (x = 0; x < width; ++x) { |
+ if (pixels[x]) { |
+ bounds.fTop = y; |
+ goto foundTop; |
} |
- pixels += rowPixels; |
} |
+ pixels += rowPixels; |
+ } |
foundTop: |
- bounds.fBottom = height; |
- y = height; |
- pixels = pixelBase + rowPixels * (y - 1); |
- while (--y > bounds.fTop) { |
- for (x = 0; x < width; ++x) { |
- if (pixels[x]) { |
- bounds.fBottom = y + 1; |
- goto foundBottom; |
- } |
+ bounds.fBottom = height; |
+ y = height; |
+ pixels = pixelBase + rowPixels * (y - 1); |
+ while (--y > bounds.fTop) { |
+ for (x = 0; x < width; ++x) { |
+ if (pixels[x]) { |
+ bounds.fBottom = y + 1; |
+ goto foundBottom; |
} |
- pixels -= rowPixels; |
} |
+ pixels -= rowPixels; |
+ } |
foundBottom: |
- bounds.fLeft = 0; |
- x = -1; |
- while (++x < width) { |
- pixels = pixelBase + rowPixels * bounds.fTop; |
- for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
- if (pixels[x]) { |
- bounds.fLeft = x; |
- goto foundLeft; |
- } |
- pixels += rowPixels; |
+ bounds.fLeft = 0; |
+ x = -1; |
+ while (++x < width) { |
+ pixels = pixelBase + rowPixels * bounds.fTop; |
+ for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
+ if (pixels[x]) { |
+ bounds.fLeft = x; |
+ goto foundLeft; |
} |
+ pixels += rowPixels; |
} |
+ } |
foundLeft: |
- bounds.fRight = width; |
- x = width; |
- while (--x > bounds.fLeft) { |
- pixels = pixelBase + rowPixels * bounds.fTop; |
- for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
- if (pixels[x]) { |
- bounds.fRight = x + 1; |
- goto foundRight; |
- } |
- pixels += rowPixels; |
+ bounds.fRight = width; |
+ x = width; |
+ while (--x > bounds.fLeft) { |
+ pixels = pixelBase + rowPixels * bounds.fTop; |
+ for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
+ if (pixels[x]) { |
+ bounds.fRight = x + 1; |
+ goto foundRight; |
} |
+ pixels += rowPixels; |
} |
+ } |
foundRight: |
+ return bounds; |
+} |
+ |
+// This must be called to balance calls to cgContext |
+void SkiaBitLocker::releaseIfNeeded() { |
+ if (!cgContext_) |
+ return; |
+ if (useDeviceBits_) { |
+ bitmap_.unlockPixels(); |
+ } else if (!bitmapIsDummy_) { |
+ // Find the bits that were drawn to. |
+ SkIRect bounds = computeDirtyRect(); |
SkBitmap subset; |
if (!bitmap_.extractSubset(&subset, bounds)) { |
return; |
@@ -362,12 +388,19 @@ foundRight: |
} |
CGContextRelease(cgContext_); |
cgContext_ = 0; |
+ useDeviceBits_ = false; |
+ bitmapIsDummy_ = false; |
} |
CGContextRef SkiaBitLocker::cgContext() { |
SkIRect clip_bounds; |
- if (!canvas_->getClipDeviceBounds(&clip_bounds)) |
- return 0; // the clip is empty, nothing to draw |
+ if (!canvas_->getClipDeviceBounds(&clip_bounds)) { |
+ // If the clip is empty, then there is nothing to draw. The caller may |
+ // attempt to draw (to-be-clipped) results, so ensure there is a dummy |
+ // non-NULL CGContext to use. |
+ bitmapIsDummy_ = true; |
+ clip_bounds = SkIRect::MakeXYWH(0, 0, 1, 1); |
+ } |
SkBaseDevice* device = canvas_->getTopDevice(); |
DCHECK(device); |
@@ -387,13 +420,20 @@ CGContextRef SkiaBitLocker::cgContext() { |
// Only draw directly if we have pixels, and we're only rect-clipped. |
// If not, we allocate an offscreen and draw into that, relying on the |
// compositing step to apply skia's clip. |
- useDeviceBits_ = deviceBits.getPixels() && canvas_->isClipRect(); |
+ useDeviceBits_ = deviceBits.getPixels() && |
+ canvas_->isClipRect() && |
+ !bitmapIsDummy_; |
if (useDeviceBits_) { |
- if (!deviceBits.extractSubset(&bitmap_, clip_bounds)) |
+ bool result = deviceBits.extractSubset(&bitmap_, clip_bounds); |
+ DCHECK(result); |
+ if (!result) |
return 0; |
bitmap_.lockPixels(); |
} else { |
- if (!bitmap_.allocN32Pixels(clip_bounds.width(), clip_bounds.height())) |
+ bool result = bitmap_.allocN32Pixels( |
+ clip_bounds.width(), clip_bounds.height()); |
+ DCHECK(result); |
+ if (!result) |
return 0; |
bitmap_.eraseColor(0); |
} |
@@ -402,6 +442,7 @@ CGContextRef SkiaBitLocker::cgContext() { |
cgContext_ = CGBitmapContextCreate(bitmap_.getPixels(), bitmap_.width(), |
bitmap_.height(), 8, bitmap_.rowBytes(), colorSpace, |
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); |
+ DCHECK(cgContext_); |
SkMatrix matrix = canvas_->getTotalMatrix(); |
matrix.postTranslate(-SkIntToScalar(bitmapOffset_.x()), |
@@ -414,4 +455,8 @@ CGContextRef SkiaBitLocker::cgContext() { |
return cgContext_; |
} |
+bool SkiaBitLocker::hasEmptyClipRegion() const { |
+ return canvas_->isClipEmpty(); |
+} |
+ |
} // namespace gfx |