From 4a207e610fc0c36a82bf6406db294577c688c14c Mon Sep 17 00:00:00 2001 From: tomhudson Date: Thu, 5 Nov 2015 15:06:36 -0800 Subject: SkDevice shouldn't be accessed outside of Skia; it will soon be deprecated. This refactoring adds a function to Chromium's skia namespace that wraps the code required to get write access to the pixel data backing a *raster* SkCanvas. Instead of returning a SkBitmap with complicated lifetime semantics, we use the simpler SkPixmap where possible. The previous version of ImageDataPlatformBackend::Map() forcibly changed the bitmap descriptor from opaque to premultiplied; this isn't guaranteed to actually work. Instead we change the initialization of the bitmap so that it's premultiplied instead of opaque. R=reed@chromium.org,bbudge@chromium.org,piman@chromium.org,msw@chromium.org BUG=543755 TEST=gfx_unittests,ppapi_unittests Review URL: https://codereview.chromium.org/1420283003 Cr-Commit-Position: refs/heads/master@{#358166} --- skia/ext/platform_canvas.cc | 17 +++++++++++++++ skia/ext/platform_canvas.h | 10 +++++++++ skia/ext/skia_utils_mac.h | 8 ++++--- skia/ext/skia_utils_mac.mm | 51 ++++++++++++++++++++++++++------------------- 4 files changed, 61 insertions(+), 25 deletions(-) (limited to 'skia/ext') diff --git a/skia/ext/platform_canvas.cc b/skia/ext/platform_canvas.cc index 5e5aeb2..cf362b3 100644 --- a/skia/ext/platform_canvas.cc +++ b/skia/ext/platform_canvas.cc @@ -20,6 +20,23 @@ SkBitmap ReadPixels(SkCanvas* canvas) { return bitmap; } +bool GetWritablePixels(SkCanvas* canvas, SkPixmap* result) { + if (!canvas || !result) { + return false; + } + + SkImageInfo info; + size_t row_bytes; + void* pixels = canvas->accessTopLayerPixels(&info, &row_bytes); + if (!pixels) { + result->reset(); + return false; + } + + result->reset(info, pixels, row_bytes); + return true; +} + bool SupportsPlatformPaint(const SkCanvas* canvas) { PlatformDevice* platform_device = GetPlatformDevice(GetTopDevice(*canvas)); return platform_device && platform_device->SupportsPlatformPaint(); diff --git a/skia/ext/platform_canvas.h b/skia/ext/platform_canvas.h index 4499041..c46d6c4 100644 --- a/skia/ext/platform_canvas.h +++ b/skia/ext/platform_canvas.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPixelRef.h" +#include "third_party/skia/include/core/SkPixmap.h" namespace skia { @@ -123,6 +124,15 @@ SK_API SkBaseDevice* GetTopDevice(const SkCanvas& canvas); // of the pixels. SK_API SkBitmap ReadPixels(SkCanvas* canvas); +// Gives the pixmap passed in *writable* access to the pixels backing this +// canvas. All writes to the pixmap should be visible if the canvas is +// raster-backed. +// +// Returns false on failure: if either argument is nullptr, or if the +// pixels can not be retrieved from the canvas. In the latter case resets +// the pixmap to empty. +SK_API bool GetWritablePixels(SkCanvas* canvas, SkPixmap* pixmap); + // Returns true if native platform routines can be used to draw on the // given canvas. If this function returns false, BeginPlatformPaint will // return NULL PlatformSurface. diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h index b60f9e8..e99913f 100644 --- a/skia/ext/skia_utils_mac.h +++ b/skia/ext/skia_utils_mac.h @@ -10,6 +10,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPixmap.h" struct SkIRect; struct SkPoint; @@ -129,12 +130,13 @@ class SK_API SkiaBitLocker { bool userClipRectSpecified_; CGContextRef cgContext_; - SkBitmap bitmap_; + // offscreen_ is only valid if useDeviceBits_ is false + SkBitmap offscreen_; SkIPoint bitmapOffset_; SkScalar bitmapScaleFactor_; - // True if we are drawing to |canvas_|'s SkBaseDevice's bits directly through - // |bitmap_|. Otherwise, the bits in |bitmap_| are our allocation and need to + // True if we are drawing to |canvas_|'s backing store directly. + // Otherwise, the bits in |bitmap_| are our allocation and need to // be copied over to |canvas_|. bool useDeviceBits_; diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm index 9e552eb..fe05464c 100644 --- a/skia/ext/skia_utils_mac.mm +++ b/skia/ext/skia_utils_mac.mm @@ -11,6 +11,7 @@ #include "base/mac/scoped_nsobject.h" #include "base/memory/scoped_ptr.h" #include "skia/ext/bitmap_platform_device_mac.h" +#include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkRegion.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" @@ -297,15 +298,15 @@ 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()); + return SkIRect::MakeWH(offscreen_.width(), offscreen_.height()); // Find the bits that were drawn to. - SkAutoLockPixels lockedPixels(bitmap_); + SkAutoLockPixels lockedPixels(offscreen_); const uint32_t* pixelBase - = reinterpret_cast(bitmap_.getPixels()); - int rowPixels = bitmap_.rowBytesAsPixels(); - int width = bitmap_.width(); - int height = bitmap_.height(); + = reinterpret_cast(offscreen_.getPixels()); + int rowPixels = offscreen_.rowBytesAsPixels(); + int width = offscreen_.width(); + int height = offscreen_.height(); SkIRect bounds; bounds.fTop = 0; int x; @@ -367,13 +368,11 @@ foundRight: void SkiaBitLocker::releaseIfNeeded() { if (!cgContext_) return; - if (useDeviceBits_) { - bitmap_.unlockPixels(); - } else if (!bitmapIsDummy_) { + if (!useDeviceBits_ && !bitmapIsDummy_) { // Find the bits that were drawn to. SkIRect bounds = computeDirtyRect(); SkBitmap subset; - if (!bitmap_.extractSubset(&subset, bounds)) { + if (!offscreen_.extractSubset(&subset, bounds)) { return; } subset.setImmutable(); // Prevents a defensive copy inside Skia. @@ -414,41 +413,49 @@ CGContextRef SkiaBitLocker::cgContext() { // Now make clip_bounds be relative to the current layer/device clip_bounds.offset(-device->getOrigin()); - const SkBitmap& deviceBits = device->accessBitmap(true); + SkPixmap devicePixels; + skia::GetWritablePixels(canvas_, &devicePixels); // 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() && + useDeviceBits_ = devicePixels.addr() && canvas_->isClipRect() && !bitmapIsDummy_; + base::ScopedCFTypeRef colorSpace( + CGColorSpaceCreateDeviceRGB()); + + int displayHeight; if (useDeviceBits_) { - bool result = deviceBits.extractSubset(&bitmap_, clip_bounds); + SkPixmap subset; + bool result = devicePixels.extractSubset(&subset, clip_bounds); DCHECK(result); if (!result) return 0; - bitmap_.lockPixels(); + displayHeight = subset.height(); + cgContext_ = CGBitmapContextCreate(subset.writable_addr(), subset.width(), + subset.height(), 8, subset.rowBytes(), colorSpace, + kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); } else { - bool result = bitmap_.tryAllocN32Pixels( + bool result = offscreen_.tryAllocN32Pixels( SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.width()), SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.height())); DCHECK(result); if (!result) return 0; - bitmap_.eraseColor(0); + offscreen_.eraseColor(0); + displayHeight = offscreen_.height(); + cgContext_ = CGBitmapContextCreate(offscreen_.getPixels(), + offscreen_.width(), offscreen_.height(), 8, offscreen_.rowBytes(), + colorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); } - base::ScopedCFTypeRef colorSpace( - CGColorSpaceCreateDeviceRGB()); - 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()), -SkIntToScalar(bitmapOffset_.y())); matrix.postScale(bitmapScaleFactor_, -bitmapScaleFactor_); - matrix.postTranslate(0, SkIntToScalar(bitmap_.height())); + matrix.postTranslate(0, SkIntToScalar(displayHeight)); CGContextConcatCTM(cgContext_, SkMatrixToCGAffineTransform(matrix)); -- cgit v1.1