diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-02 22:44:07 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-02 22:44:07 +0000 |
commit | 9abceb78361ca70703fdf6051eb4e556f06f2b6a (patch) | |
tree | 2906b780dc22793414466f83e7d050af2e0d638e /skia | |
parent | fbc94488149d051eb37f09e9e5ba546f9d18880e (diff) | |
download | chromium_src-9abceb78361ca70703fdf6051eb4e556f06f2b6a.zip chromium_src-9abceb78361ca70703fdf6051eb4e556f06f2b6a.tar.gz chromium_src-9abceb78361ca70703fdf6051eb4e556f06f2b6a.tar.bz2 |
Remove BitmapPlatformDeviceData, and merge its functionality into the appropriate BitmapPlatformDevice. It was a little twisty maze of #ifdefs, ostensibly created to allow successful assignment and copy construction of the device. However, I could not find any such use, and the BitmapPlatformDevices are all marked DISALLOW_COPY_AND_ASSIGN!
Instead, we use a subclass of SkPixelRef to handle ownership of the platform-specific bitmaps. This allows correct Skia semantics: the SkBitmap used for device drawing can safely outlive the device, since it is refcounted. Such a subclass already existed for Windows; this simply implements it for Cairo as well, and uses it in all cases.
TBR=brettw
Review URL: https://codereview.chromium.org/95773002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238213 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r-- | skia/ext/bitmap_platform_device_cairo.cc | 97 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_cairo.h | 29 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_data.h | 102 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_mac.cc | 67 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_mac.h | 35 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_win.cc | 76 | ||||
-rw-r--r-- | skia/ext/bitmap_platform_device_win.h | 58 | ||||
-rw-r--r-- | skia/skia_chrome.gypi | 1 |
8 files changed, 212 insertions, 253 deletions
diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc index e931629..906f95c 100644 --- a/skia/ext/bitmap_platform_device_cairo.cc +++ b/skia/ext/bitmap_platform_device_cairo.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "skia/ext/bitmap_platform_device_cairo.h" -#include "skia/ext/bitmap_platform_device_data.h" #include "skia/ext/platform_canvas.h" #if defined(OS_OPENBSD) @@ -16,6 +15,42 @@ namespace skia { namespace { +// CairoSurfacePixelRef is an SkPixelRef that is backed by a cairo surface. +class SK_API CairoSurfacePixelRef : public SkPixelRef { + public: + // The constructor takes ownership of the passed-in surface. + explicit CairoSurfacePixelRef(cairo_surface_t* surface); + virtual ~CairoSurfacePixelRef(); + + SK_DECLARE_UNFLATTENABLE_OBJECT(); + + protected: + virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; + virtual void onUnlockPixels() SK_OVERRIDE; + + private: + cairo_surface_t* surface_; +}; + +CairoSurfacePixelRef::CairoSurfacePixelRef(cairo_surface_t* surface) + : surface_(surface) { +} + +CairoSurfacePixelRef::~CairoSurfacePixelRef() { + if (surface_) + cairo_surface_destroy(surface_); +} + +void* CairoSurfacePixelRef::onLockPixels(SkColorTable** color_table) { + *color_table = NULL; + return cairo_image_surface_get_data(surface_); +} + +void CairoSurfacePixelRef::onUnlockPixels() { + // Nothing to do. + return; +} + void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) { cairo_matrix_t cairo_matrix; cairo_matrix_init(&cairo_matrix, @@ -41,20 +76,7 @@ void LoadClipToContext(cairo_t* context, const SkRegion& clip) { } // namespace -BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData( - cairo_surface_t* surface) - : surface_(surface), - config_dirty_(true), - transform_(SkMatrix::I()) { // Want to load the config next time. - bitmap_context_ = cairo_create(surface); -} - -BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() { - cairo_destroy(bitmap_context_); - cairo_surface_destroy(surface_); -} - -void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( +void BitmapPlatformDevice::SetMatrixClip( const SkMatrix& transform, const SkRegion& region) { transform_ = transform; @@ -62,18 +84,18 @@ void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( config_dirty_ = true; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() { - if (!config_dirty_ || !bitmap_context_) +void BitmapPlatformDevice::LoadConfig() { + if (!config_dirty_ || !cairo_) return; // Nothing to do. config_dirty_ = false; // Load the identity matrix since this is what our clip is relative to. cairo_matrix_t cairo_matrix; cairo_matrix_init_identity(&cairo_matrix); - cairo_set_matrix(bitmap_context_, &cairo_matrix); + cairo_set_matrix(cairo_, &cairo_matrix); - LoadClipToContext(bitmap_context_, clip_region_); - LoadMatrixToContext(bitmap_context_, transform_); + LoadClipToContext(cairo_, clip_region_); + LoadMatrixToContext(cairo_, transform_); } // We use this static factory function instead of the regular constructor so @@ -91,11 +113,11 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, cairo_image_surface_get_stride(surface), is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); - bitmap.setPixels(cairo_image_surface_get_data(surface)); + RefPtr<SkPixelRef> pixel_ref = AdoptRef(new CairoSurfacePixelRef(surface)); + bitmap.setPixelRef(pixel_ref.get()); // The device object will take ownership of the graphics context. - return new BitmapPlatformDevice - (bitmap, new BitmapPlatformDeviceData(surface)); + return new BitmapPlatformDevice(bitmap, surface); } BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, @@ -136,13 +158,16 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. BitmapPlatformDevice::BitmapPlatformDevice( const SkBitmap& bitmap, - BitmapPlatformDeviceData* data) + cairo_surface_t* surface) : SkBitmapDevice(bitmap), - data_(data) { + cairo_(cairo_create(surface)), + config_dirty_(true), + transform_(SkMatrix::I()) { // Want to load the config next time. SetPlatformDevice(this, this); } BitmapPlatformDevice::~BitmapPlatformDevice() { + cairo_destroy(cairo_); } SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice( @@ -153,15 +178,14 @@ SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice( } cairo_t* BitmapPlatformDevice::BeginPlatformPaint() { - data_->LoadConfig(); - cairo_t* cairo = data_->bitmap_context(); - cairo_surface_t* surface = cairo_get_target(cairo); + LoadConfig(); + cairo_surface_t* surface = cairo_get_target(cairo_); // Tell cairo to flush anything it has pending. cairo_surface_flush(surface); // Tell Cairo that we (probably) modified (actually, will modify) its pixel // buffer directly. cairo_surface_mark_dirty(surface); - return cairo; + return cairo_; } void BitmapPlatformDevice::DrawToNativeContext( @@ -173,7 +197,7 @@ void BitmapPlatformDevice::DrawToNativeContext( void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, const SkRegion& region, const SkClipStack&) { - data_->SetMatrixClip(transform, region); + SetMatrixClip(transform, region); } // PlatformCanvas impl @@ -197,22 +221,17 @@ bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) { int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, stride, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); - if (!bitmap_.allocPixels()) // Using the default allocator. - return false; - cairo_surface_t* surf = cairo_image_surface_create_for_data( - reinterpret_cast<unsigned char*>(bitmap_.getPixels()), + cairo_surface_t* surf = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, - height, - stride); + height); if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(surf); return false; } - - surface_ = cairo_create(surf); - cairo_surface_destroy(surf); + RefPtr<SkPixelRef> pixel_ref = AdoptRef(new CairoSurfacePixelRef(surf)); + bitmap_.setPixelRef(pixel_ref.get()); return true; } diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h index 914be34..5b3c46c 100644 --- a/skia/ext/bitmap_platform_device_cairo.h +++ b/skia/ext/bitmap_platform_device_cairo.h @@ -57,9 +57,6 @@ namespace skia { // case we'll probably create the buffer from a precreated region of memory. // ----------------------------------------------------------------------------- class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { - // A reference counted cairo surface - class BitmapPlatformDeviceData; - public: // Create a BitmapPlatformDeviceLinux from an already constructed bitmap; // you should probably be using Create(). This may become private later if @@ -67,7 +64,7 @@ class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { // the Windows and Mac versions of this class do. // // This object takes ownership of @data. - BitmapPlatformDevice(const SkBitmap& other, BitmapPlatformDeviceData* data); + BitmapPlatformDevice(const SkBitmap& other, cairo_surface_t* surface); virtual ~BitmapPlatformDevice(); // Constructs a device with size |width| * |height| with contents initialized @@ -104,7 +101,29 @@ class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, cairo_surface_t* surface); - scoped_refptr<BitmapPlatformDeviceData> data_; + // Sets the transform and clip operations. This will not update the Cairo + // context, but will mark the config as dirty. The next call of LoadConfig + // will pick up these changes. + void SetMatrixClip(const SkMatrix& transform, const SkRegion& region); + + // Loads the current transform and clip into the context. + void LoadConfig(); + + // Graphics context used to draw into the surface. + cairo_t* cairo_; + + // True when there is a transform or clip that has not been set to the + // context. The context is retrieved for every text operation, and the + // transform and clip do not change as much. We can save time by not loading + // the clip and transform for every one. + bool config_dirty_; + + // Translation assigned to the context: we need to keep track of this + // separately so it can be updated even if the context isn't created yet. + SkMatrix transform_; + + // The current clipping + SkRegion clip_region_; DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); }; diff --git a/skia/ext/bitmap_platform_device_data.h b/skia/ext/bitmap_platform_device_data.h deleted file mode 100644 index 81e81ed7..0000000 --- a/skia/ext/bitmap_platform_device_data.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_DATA_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_DATA_H_ - -#include "skia/ext/bitmap_platform_device.h" - -namespace skia { - -class BitmapPlatformDevice::BitmapPlatformDeviceData : -#if defined(WIN32) || defined(__APPLE__) - public SkRefCnt { -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) - // These objects are reference counted and own a Cairo surface. The surface - // is the backing store for a Skia bitmap and we reference count it so that - // we can copy BitmapPlatformDevice objects without having to copy all the - // image data. - public base::RefCounted<BitmapPlatformDeviceData> { -#endif - - public: -#if defined(WIN32) - typedef HBITMAP PlatformContext; -#elif defined(__APPLE__) - typedef CGContextRef PlatformContext; -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) - typedef cairo_t* PlatformContext; -#endif - -#if defined(WIN32) || defined(__APPLE__) - explicit BitmapPlatformDeviceData(PlatformContext bitmap); -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) - explicit BitmapPlatformDeviceData(cairo_surface_t* surface); -#endif - -#if defined(WIN32) - // Create/destroy hdc_, which is the memory DC for our bitmap data. - HDC GetBitmapDC(); - void ReleaseBitmapDC(); - bool IsBitmapDCCreated() const; -#endif - -#if defined(__APPLE__) - void ReleaseBitmapContext(); -#endif // defined(__APPLE__) - - // Sets the transform and clip operations. This will not update the CGContext, - // but will mark the config as dirty. The next call of LoadConfig will - // pick up these changes. - void SetMatrixClip(const SkMatrix& transform, const SkRegion& region); - - // Loads the current transform and clip into the context. Can be called even - // when |bitmap_context_| is NULL (will be a NOP). - void LoadConfig(); - - const SkMatrix& transform() const { - return transform_; - } - - PlatformContext bitmap_context() { - return bitmap_context_; - } - - private: -#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) - friend class base::RefCounted<BitmapPlatformDeviceData>; -#endif - virtual ~BitmapPlatformDeviceData(); - - // Lazily-created graphics context used to draw into the bitmap. - PlatformContext bitmap_context_; - -#if defined(WIN32) - // Lazily-created DC used to draw into the bitmap, see GetBitmapDC(). - HDC hdc_; -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun) - cairo_surface_t *const surface_; -#endif - - // True when there is a transform or clip that has not been set to the - // context. The context is retrieved for every text operation, and the - // transform and clip do not change as much. We can save time by not loading - // the clip and transform for every one. - bool config_dirty_; - - // Translation assigned to the context: we need to keep track of this - // separately so it can be updated even if the context isn't created yet. - SkMatrix transform_; - - // The current clipping - SkRegion clip_region_; - - // Disallow copy & assign. - BitmapPlatformDeviceData(const BitmapPlatformDeviceData&); - BitmapPlatformDeviceData& operator=(const BitmapPlatformDeviceData&); -}; - -} // namespace skia - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_DATA_H_ diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc index 8525cd3..a62c3cf 100644 --- a/skia/ext/bitmap_platform_device_mac.cc +++ b/skia/ext/bitmap_platform_device_mac.cc @@ -9,7 +9,7 @@ #include "base/mac/mac_util.h" #include "base/memory/ref_counted.h" -#include "skia/ext/bitmap_platform_device_data.h" +#include "skia/ext/bitmap_platform_device.h" #include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_mac.h" #include "third_party/skia/include/core/SkMatrix.h" @@ -57,37 +57,13 @@ static CGContextRef CGContextForData(void* data, int width, int height) { } // namespace -BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData( - CGContextRef bitmap) - : bitmap_context_(bitmap), - config_dirty_(true), // Want to load the config next time. - transform_(SkMatrix::I()) { - SkASSERT(bitmap_context_); - // Initialize the clip region to the entire bitmap. - - SkIRect rect; - rect.set(0, 0, - CGBitmapContextGetWidth(bitmap_context_), - CGBitmapContextGetHeight(bitmap_context_)); - clip_region_ = SkRegion(rect); - CGContextRetain(bitmap_context_); - // We must save the state once so that we can use the restore/save trick - // in LoadConfig(). - CGContextSaveGState(bitmap_context_); -} - -BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() { - if (bitmap_context_) - CGContextRelease(bitmap_context_); -} - -void BitmapPlatformDevice::BitmapPlatformDeviceData::ReleaseBitmapContext() { +void BitmapPlatformDevice::ReleaseBitmapContext() { SkASSERT(bitmap_context_); CGContextRelease(bitmap_context_); bitmap_context_ = NULL; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( +void BitmapPlatformDevice::SetMatrixClip( const SkMatrix& transform, const SkRegion& region) { transform_ = transform; @@ -95,7 +71,7 @@ void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( config_dirty_ = true; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() { +void BitmapPlatformDevice::LoadConfig() { if (!config_dirty_ || !bitmap_context_) return; // Nothing to do. config_dirty_ = false; @@ -156,8 +132,7 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create(CGContextRef context, } else CGContextRetain(context); - BitmapPlatformDevice* rv = new BitmapPlatformDevice( - skia::AdoptRef(new BitmapPlatformDeviceData(context)), bitmap); + BitmapPlatformDevice* rv = new BitmapPlatformDevice(context, bitmap); // The device object took ownership of the graphics context with its own // CGContextRetain call. @@ -196,37 +171,53 @@ BitmapPlatformDevice* BitmapPlatformDevice::CreateWithData(uint8_t* data, // The device will own the bitmap, which corresponds to also owning the pixel // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. BitmapPlatformDevice::BitmapPlatformDevice( - const skia::RefPtr<BitmapPlatformDeviceData>& data, const SkBitmap& bitmap) + CGContextRef context, const SkBitmap& bitmap) : SkBitmapDevice(bitmap), - data_(data) { + bitmap_context_(context), + config_dirty_(true), // Want to load the config next time. + transform_(SkMatrix::I()) { SetPlatformDevice(this, this); + SkASSERT(bitmap_context_); + // Initialize the clip region to the entire bitmap. + + SkIRect rect; + rect.set(0, 0, + CGBitmapContextGetWidth(bitmap_context_), + CGBitmapContextGetHeight(bitmap_context_)); + clip_region_ = SkRegion(rect); + CGContextRetain(bitmap_context_); + // We must save the state once so that we can use the restore/save trick + // in LoadConfig(). + CGContextSaveGState(bitmap_context_); } BitmapPlatformDevice::~BitmapPlatformDevice() { + if (bitmap_context_) + CGContextRelease(bitmap_context_); } CGContextRef BitmapPlatformDevice::GetBitmapContext() { - data_->LoadConfig(); - return data_->bitmap_context(); + LoadConfig(); + return bitmap_context_; } void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, const SkRegion& region, const SkClipStack&) { - data_->SetMatrixClip(transform, region); + SetMatrixClip(transform, region); } void BitmapPlatformDevice::DrawToNativeContext(CGContextRef context, int x, int y, const CGRect* src_rect) { bool created_dc = false; - if (!data_->bitmap_context()) { + if (!bitmap_context_) { created_dc = true; GetBitmapContext(); } // this should not make a copy of the bits, since we're not doing // anything to trigger copy on write - CGImageRef image = CGBitmapContextCreateImage(data_->bitmap_context()); + CGImageRef image = CGBitmapContextCreateImage(bitmap_context_); CGRect bounds; bounds.origin.x = x; bounds.origin.y = y; @@ -244,7 +235,7 @@ void BitmapPlatformDevice::DrawToNativeContext(CGContextRef context, int x, CGImageRelease(image); if (created_dc) - data_->ReleaseBitmapContext(); + ReleaseBitmapContext(); } SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice( diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h index 07b0084..00b0309 100644 --- a/skia/ext/bitmap_platform_device_mac.h +++ b/skia/ext/bitmap_platform_device_mac.h @@ -60,21 +60,40 @@ class SK_API BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice const SkClipStack&) OVERRIDE; protected: - // Reference counted data that can be shared between multiple devices. This - // allows copy constructors and operator= for devices to work properly. The - // bitmaps used by the base device class are already refcounted and copyable. - class BitmapPlatformDeviceData; - - BitmapPlatformDevice(const skia::RefPtr<BitmapPlatformDeviceData>& data, + BitmapPlatformDevice(CGContextRef context, const SkBitmap& bitmap); virtual SkBaseDevice* onCreateCompatibleDevice(SkBitmap::Config, int width, int height, bool isOpaque, Usage usage) OVERRIDE; - // Data associated with this device, guaranteed non-null. - skia::RefPtr<BitmapPlatformDeviceData> data_; + private: + void ReleaseBitmapContext(); + + // Sets the transform and clip operations. This will not update the CGContext, + // but will mark the config as dirty. The next call of LoadConfig will + // pick up these changes. + void SetMatrixClip(const SkMatrix& transform, const SkRegion& region); + + // Loads the current transform and clip into the context. Can be called even + // when |bitmap_context_| is NULL (will be a NOP). + void LoadConfig(); + + // Lazily-created graphics context used to draw into the bitmap. + CGContextRef bitmap_context_; + + // True when there is a transform or clip that has not been set to the + // context. The context is retrieved for every text operation, and the + // transform and clip do not change as much. We can save time by not loading + // the clip and transform for every one. + bool config_dirty_; + + // Translation assigned to the context: we need to keep track of this + // separately so it can be updated even if the context isn't created yet. + SkMatrix transform_; + // The current clipping + SkRegion clip_region_; DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); }; diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc index 42f431b..0dfc324 100644 --- a/skia/ext/bitmap_platform_device_win.cc +++ b/skia/ext/bitmap_platform_device_win.cc @@ -8,7 +8,6 @@ #include "base/logging.h" #include "base/debug/alias.h" #include "skia/ext/bitmap_platform_device_win.h" -#include "skia/ext/bitmap_platform_device_data.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -144,34 +143,11 @@ void PlatformBitmapPixelRef::onUnlockPixels() { namespace skia { -BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData( - HBITMAP hbitmap) - : bitmap_context_(hbitmap), - hdc_(NULL), - config_dirty_(true), // Want to load the config next time. - transform_(SkMatrix::I()) { - // Initialize the clip region to the entire bitmap. - BITMAP bitmap_data; - if (GetObject(bitmap_context_, sizeof(BITMAP), &bitmap_data)) { - SkIRect rect; - rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight); - clip_region_ = SkRegion(rect); - } -} - -BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() { - if (hdc_) - ReleaseBitmapDC(); - - // this will free the bitmap data as well as the bitmap handle - DeleteObject(bitmap_context_); -} - -HDC BitmapPlatformDevice::BitmapPlatformDeviceData::GetBitmapDC() { +HDC BitmapPlatformDevice::GetBitmapDC() { if (!hdc_) { hdc_ = CreateCompatibleDC(NULL); InitializeDC(hdc_); - HGDIOBJ old_bitmap = SelectObject(hdc_, bitmap_context_); + HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_); // When the memory DC is created, its display surface is exactly one // monochrome pixel wide and one monochrome pixel high. Since we select our // own bitmap, we must delete the previous one. @@ -182,19 +158,19 @@ HDC BitmapPlatformDevice::BitmapPlatformDeviceData::GetBitmapDC() { return hdc_; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::ReleaseBitmapDC() { +void BitmapPlatformDevice::ReleaseBitmapDC() { SkASSERT(hdc_); DeleteDC(hdc_); hdc_ = NULL; } -bool BitmapPlatformDevice::BitmapPlatformDeviceData::IsBitmapDCCreated() +bool BitmapPlatformDevice::IsBitmapDCCreated() const { return hdc_ != NULL; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( +void BitmapPlatformDevice::SetMatrixClip( const SkMatrix& transform, const SkRegion& region) { transform_ = transform; @@ -202,7 +178,7 @@ void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip( config_dirty_ = true; } -void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() { +void BitmapPlatformDevice::LoadConfig() { if (!config_dirty_ || !hdc_) return; // Nothing to do. config_dirty_ = false; @@ -231,7 +207,9 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create( SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); - bitmap.setPixels(data); + RefPtr<SkPixelRef> pixel_ref = AdoptRef(new PlatformBitmapPixelRef(hbitmap, + data)); + bitmap.setPixelRef(pixel_ref.get()); #ifndef NDEBUG // If we were given data, then don't clobber it! @@ -243,8 +221,7 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create( // The device object will take ownership of the HBITMAP. The initial refcount // of the data object will be 1, which is what the constructor expects. - return new BitmapPlatformDevice( - skia::AdoptRef(new BitmapPlatformDeviceData(hbitmap)), bitmap); + return new BitmapPlatformDevice(hbitmap, bitmap); } // static @@ -267,22 +244,34 @@ BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width, // The device will own the HBITMAP, which corresponds to also owning the pixel // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. BitmapPlatformDevice::BitmapPlatformDevice( - const skia::RefPtr<BitmapPlatformDeviceData>& data, + HBITMAP hbitmap, const SkBitmap& bitmap) : SkBitmapDevice(bitmap), - data_(data) { + hbitmap_(hbitmap), + hdc_(NULL), + config_dirty_(true), // Want to load the config next time. + transform_(SkMatrix::I()) { // The data object is already ref'ed for us by create(). SkDEBUGCODE(begin_paint_count_ = 0); SetPlatformDevice(this, this); + // Initialize the clip region to the entire bitmap. + BITMAP bitmap_data; + if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) { + SkIRect rect; + rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight); + clip_region_ = SkRegion(rect); + } } BitmapPlatformDevice::~BitmapPlatformDevice() { SkASSERT(begin_paint_count_ == 0); + if (hdc_) + ReleaseBitmapDC(); } HDC BitmapPlatformDevice::BeginPlatformPaint() { SkDEBUGCODE(begin_paint_count_++); - return data_->GetBitmapDC(); + return GetBitmapDC(); } void BitmapPlatformDevice::EndPlatformPaint() { @@ -293,12 +282,12 @@ void BitmapPlatformDevice::EndPlatformPaint() { void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform, const SkRegion& region, const SkClipStack&) { - data_->SetMatrixClip(transform, region); + SetMatrixClip(transform, region); } void BitmapPlatformDevice::DrawToNativeContext(HDC dc, int x, int y, const RECT* src_rect) { - bool created_dc = !data_->IsBitmapDCCreated(); + bool created_dc = !IsBitmapDCCreated(); HDC source_dc = BeginPlatformPaint(); RECT temp_rect; @@ -344,17 +333,17 @@ void BitmapPlatformDevice::DrawToNativeContext(HDC dc, int x, int y, copy_height, blend_function); } - LoadTransformToDC(source_dc, data_->transform()); + LoadTransformToDC(source_dc, transform_); EndPlatformPaint(); if (created_dc) - data_->ReleaseBitmapDC(); + ReleaseBitmapDC(); } const SkBitmap& BitmapPlatformDevice::onAccessBitmap() { // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI // operation has occurred on our DC. - if (data_->IsBitmapDCCreated()) + if (IsBitmapDCCreated()) GdiFlush(); return SkBitmapDevice::onAccessBitmap(); } @@ -404,8 +393,9 @@ bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) { bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); // PlatformBitmapPixelRef takes ownership of |hbitmap|. - bitmap_.setPixelRef( - skia::AdoptRef(new PlatformBitmapPixelRef(hbitmap, data)).get()); + RefPtr<SkPixelRef> pixel_ref = AdoptRef(new PlatformBitmapPixelRef(hbitmap, + data)); + bitmap_.setPixelRef(pixel_ref.get()); bitmap_.lockPixels(); return true; diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h index 1261e51..d2c1603 100644 --- a/skia/ext/bitmap_platform_device_win.h +++ b/skia/ext/bitmap_platform_device_win.h @@ -19,13 +19,11 @@ namespace skia { // This pixel data is provided to the bitmap that the device contains so that it // can be shared. // -// The device owns the pixel data, when the device goes away, the pixel data -// also becomes invalid. THIS IS DIFFERENT THAN NORMAL SKIA which uses -// reference counting for the pixel data. In normal Skia, you could assign -// another bitmap to this device's bitmap and everything will work properly. -// For us, that other bitmap will become invalid as soon as the device becomes -// invalid, which may lead to subtle bugs. Therefore, DO NOT ASSIGN THE -// DEVICE'S PIXEL DATA TO ANOTHER BITMAP, make sure you copy instead. +// The GDI bitmap created for drawing is actually owned by a +// PlatformBitmapPixelRef, and stored in an SkBitmap via the normal skia +// SkPixelRef refcounting mechanism. In this way, the GDI bitmap can outlive +// the device created to draw into it. So it is safe to call accessBitmap() on +// the device, and retain the returned SkBitmap. class SK_API BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { public: // Factory function. is_opaque should be set if the caller knows the bitmap @@ -75,17 +73,43 @@ class SK_API BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice Usage usage) OVERRIDE; private: - // Reference counted data that can be shared between multiple devices. This - // allows copy constructors and operator= for devices to work properly. The - // bitmaps used by the base device class are already refcounted and copyable. - class BitmapPlatformDeviceData; - // Private constructor. - BitmapPlatformDevice(const skia::RefPtr<BitmapPlatformDeviceData>& data, - const SkBitmap& bitmap); - - // Data associated with this device, guaranteed non-null. - skia::RefPtr<BitmapPlatformDeviceData> data_; + BitmapPlatformDevice(HBITMAP hbitmap, const SkBitmap& bitmap); + + // Bitmap into which the drawing will be done. This bitmap not owned by this + // class, but by the BitmapPlatformPixelRef inside the device's SkBitmap. + // It's only stored here in order to lazy-create the DC (below). + HBITMAP hbitmap_; + + // Lazily-created DC used to draw into the bitmap; see GetBitmapDC(). + HDC hdc_; + + // True when there is a transform or clip that has not been set to the + // context. The context is retrieved for every text operation, and the + // transform and clip do not change as much. We can save time by not loading + // the clip and transform for every one. + bool config_dirty_; + + // Translation assigned to the context: we need to keep track of this + // separately so it can be updated even if the context isn't created yet. + SkMatrix transform_; + + // The current clipping region. + SkRegion clip_region_; + + // Create/destroy hdc_, which is the memory DC for our bitmap data. + HDC GetBitmapDC(); + void ReleaseBitmapDC(); + bool IsBitmapDCCreated() const; + + // Sets the transform and clip operations. This will not update the DC, + // but will mark the config as dirty. The next call of LoadConfig will + // pick up these changes. + void SetMatrixClip(const SkMatrix& transform, const SkRegion& region); + + // Loads the current transform and clip into the context. Can be called even + // when |hbitmap_| is NULL (will be a NOP). + void LoadConfig(); #ifdef SK_DEBUG int begin_paint_count_; diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi index 32179a6..6dcc665 100644 --- a/skia/skia_chrome.gypi +++ b/skia/skia_chrome.gypi @@ -28,7 +28,6 @@ 'ext/bitmap_platform_device.h', 'ext/bitmap_platform_device_cairo.cc', 'ext/bitmap_platform_device_cairo.h', - 'ext/bitmap_platform_device_data.h', 'ext/bitmap_platform_device_mac.cc', 'ext/bitmap_platform_device_mac.h', 'ext/bitmap_platform_device_skia.cc', |