Remove BitmapPlatformDeviceData, and merge its functionality into the...

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
parent fbc94488
......@@ -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;
}
......
......@@ -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);
};
......
// 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_
......@@ -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(
......
......@@ -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);
};
......
......@@ -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;
......
......@@ -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_;
......
......@@ -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',
......
......@@ -65,7 +65,6 @@ skia_chrome_sources = [
"ext/bitmap_platform_device.h",
"ext/bitmap_platform_device_android.cc",
"ext/bitmap_platform_device_android.h",
"ext/bitmap_platform_device_data.h",
"ext/bitmap_platform_device_linux.cc",
"ext/bitmap_platform_device_linux.h",
"ext/bitmap_platform_device_mac.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment