summaryrefslogtreecommitdiffstats
path: root/skia/ext/bitmap_platform_device_mac.cc
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-21 20:32:45 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-21 20:32:45 +0000
commit98abd85558e19788d971df47690bcb4eb4dd8d98 (patch)
tree3639cbd4ce1324ce34be603ed36fec0022a438d7 /skia/ext/bitmap_platform_device_mac.cc
parent21ba9918905c5f3f66e3a075944587618da2d52d (diff)
downloadchromium_src-98abd85558e19788d971df47690bcb4eb4dd8d98.zip
chromium_src-98abd85558e19788d971df47690bcb4eb4dd8d98.tar.gz
chromium_src-98abd85558e19788d971df47690bcb4eb4dd8d98.tar.bz2
Move the platform files form port to skia for Mac only. Hopefully this won't affect other platforms.
Review URL: http://codereview.chromium.org/11357 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5845 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext/bitmap_platform_device_mac.cc')
-rwxr-xr-xskia/ext/bitmap_platform_device_mac.cc290
1 files changed, 290 insertions, 0 deletions
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
new file mode 100755
index 0000000..d4458d7
--- /dev/null
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2006-2008 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.
+
+#include "skia/ext/bitmap_platform_device_mac.h"
+
+#include <time.h>
+
+#include "SkMatrix.h"
+#include "SkRegion.h"
+#include "SkUtils.h"
+
+#include "base/gfx/skia_utils_mac.h"
+#include "base/logging.h"
+
+namespace gfx {
+
+namespace {
+
+// Constrains position and size to fit within available_size. If |size| is -1,
+// all the |available_size| is used. Returns false if the position is out of
+// |available_size|.
+bool Constrain(int available_size, int* position, int *size) {
+ if (*size < -2)
+ return false;
+
+ if (*position < 0) {
+ if (*size != -1)
+ *size += *position;
+ *position = 0;
+ }
+ if (*size == 0 || *position >= available_size)
+ return false;
+
+ if (*size > 0) {
+ int overflow = (*position + *size) - available_size;
+ if (overflow > 0) {
+ *size -= overflow;
+ }
+ } else {
+ // Fill up available size.
+ *size = available_size - *position;
+ }
+ return true;
+}
+
+} // namespace
+
+class BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData
+ : public base::RefCounted<BitmapPlatformDeviceMacData> {
+ public:
+ explicit BitmapPlatformDeviceMacData(CGContextRef bitmap);
+
+ // Create/destroy CoreGraphics context for our bitmap data.
+ CGContextRef GetBitmapContext() {
+ LoadConfig();
+ return bitmap_context_;
+ }
+
+ void ReleaseBitmapContext() {
+ DCHECK(bitmap_context_);
+ CGContextRelease(bitmap_context_);
+ bitmap_context_ = NULL;
+ }
+
+ // 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 DC. 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
+ // CGContext. The CGContext 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 CGContext: we need to keep track of this
+ // separately so it can be updated even if the CGContext isn't created yet.
+ SkMatrix transform_;
+
+ // The current clipping
+ SkRegion clip_region_;
+
+ private:
+ friend class base::RefCounted<BitmapPlatformDeviceMacData>;
+ ~BitmapPlatformDeviceMacData() {
+ if (bitmap_context_)
+ CGContextRelease(bitmap_context_);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDeviceMacData);
+};
+
+BitmapPlatformDeviceMac::\
+ BitmapPlatformDeviceMacData::BitmapPlatformDeviceMacData(
+ CGContextRef bitmap)
+ : bitmap_context_(bitmap),
+ config_dirty_(true) { // Want to load the config next time.
+ DCHECK(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);
+ transform_.reset();
+ CGContextRetain(bitmap_context_);
+}
+
+void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::SetMatrixClip(
+ const SkMatrix& transform,
+ const SkRegion& region) {
+ transform_ = transform;
+ clip_region_ = region;
+ config_dirty_ = true;
+}
+
+void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::LoadConfig() {
+ if (!config_dirty_ || !bitmap_context_)
+ return; // Nothing to do.
+ config_dirty_ = false;
+
+ // Transform.
+ SkMatrix t(transform_);
+ LoadTransformToCGContext(bitmap_context_, t);
+ t.setTranslateX(-t.getTranslateX());
+ t.setTranslateY(-t.getTranslateY());
+ LoadClippingRegionToCGContext(bitmap_context_, clip_region_, t);
+}
+
+
+// We use this static factory function instead of the regular constructor so
+// that we can create the pixel data before calling the constructor. This is
+// required so that we can call the base class' constructor with the pixel
+// data.
+BitmapPlatformDeviceMac* BitmapPlatformDeviceMac::Create(CGContextRef context,
+ int width,
+ int height,
+ bool is_opaque) {
+ void* data = malloc(height * width * 4);
+ if (!data) return NULL;
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.setPixels(data);
+
+ // Note: The Windows implementation clears the Bitmap later on.
+ // This bears mentioning since removal of this line makes the
+ // unit tests only fail periodically (or when MallocPreScribble is set).
+ bitmap.eraseARGB(0, 0, 0, 0);
+
+ bitmap.setIsOpaque(is_opaque);
+
+ if (is_opaque) {
+#ifndef NDEBUG
+ // To aid in finding bugs, we set the background color to something
+ // obviously wrong so it will be noticable when it is not cleared
+ bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green
+#endif
+ }
+
+ CGColorSpaceRef color_space =
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ // allocate a bitmap context with 4 components per pixel (RGBA):
+ CGContextRef bitmap_context =
+ CGBitmapContextCreate(data, width, height, 8, width*4,
+ color_space, kCGImageAlphaPremultipliedLast);
+
+ // Change the coordinate system to match WebCore's
+ CGContextTranslateCTM(bitmap_context, 0, height);
+ CGContextScaleCTM(bitmap_context, 1.0, -1.0);
+ CGColorSpaceRelease(color_space);
+
+ // The device object will take ownership of the graphics context.
+ return new BitmapPlatformDeviceMac(
+ new BitmapPlatformDeviceMacData(bitmap_context), bitmap);
+}
+
+// The device will own the bitmap, which corresponds to also owning the pixel
+// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
+BitmapPlatformDeviceMac::BitmapPlatformDeviceMac(
+ BitmapPlatformDeviceMacData* data, const SkBitmap& bitmap)
+ : PlatformDeviceMac(bitmap),
+ data_(data) {
+}
+
+// The copy constructor just adds another reference to the underlying data.
+// We use a const cast since the default Skia definitions don't define the
+// proper constedness that we expect (accessBitmap should really be const).
+BitmapPlatformDeviceMac::BitmapPlatformDeviceMac(
+ const BitmapPlatformDeviceMac& other)
+ : PlatformDeviceMac(
+ const_cast<BitmapPlatformDeviceMac&>(other).accessBitmap(true)),
+ data_(other.data_) {
+}
+
+BitmapPlatformDeviceMac::~BitmapPlatformDeviceMac() {
+}
+
+BitmapPlatformDeviceMac& BitmapPlatformDeviceMac::operator=(
+ const BitmapPlatformDeviceMac& other) {
+ data_ = other.data_;
+ return *this;
+}
+
+CGContextRef BitmapPlatformDeviceMac::GetBitmapContext() {
+ return data_->GetBitmapContext();
+}
+
+void BitmapPlatformDeviceMac::setMatrixClip(const SkMatrix& transform,
+ const SkRegion& region) {
+ data_->SetMatrixClip(transform, region);
+}
+
+void BitmapPlatformDeviceMac::DrawToContext(CGContextRef context, int x, int y,
+ const CGRect* src_rect) {
+ bool created_dc = false;
+ if (!data_->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_);
+ CGRect bounds;
+ if (src_rect) {
+ bounds = *src_rect;
+ bounds.origin.x = x;
+ bounds.origin.y = y;
+ CGImageRef sub_image = CGImageCreateWithImageInRect(image, *src_rect);
+ CGContextDrawImage(context, bounds, sub_image);
+ CGImageRelease(sub_image);
+ } else {
+ bounds.origin.x = 0;
+ bounds.origin.y = 0;
+ bounds.size.width = width();
+ bounds.size.height = height();
+ CGContextDrawImage(context, bounds, image);
+ }
+ CGImageRelease(image);
+
+ if (created_dc)
+ data_->ReleaseBitmapContext();
+}
+
+// Returns the color value at the specified location.
+SkColor BitmapPlatformDeviceMac::getColorAt(int x, int y) {
+ const SkBitmap& bitmap = accessBitmap(true);
+ SkAutoLockPixels lock(bitmap);
+ uint32_t* data = bitmap.getAddr32(0, 0);
+ return static_cast<SkColor>(data[x + y * width()]);
+}
+
+void BitmapPlatformDeviceMac::onAccessBitmap(SkBitmap*) {
+ // Not needed in CoreGraphics
+}
+
+void BitmapPlatformDeviceMac::processPixels(int x, int y,
+ int width, int height,
+ adjustAlpha adjustor) {
+ const SkBitmap& bitmap = accessBitmap(true);
+ SkMatrix& matrix = data_->transform_;
+ int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
+ int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;
+
+ SkAutoLockPixels lock(bitmap);
+ if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
+ Constrain(bitmap.height(), &bitmap_start_y, &height)) {
+ uint32_t* data = bitmap.getAddr32(0, 0);
+ size_t row_words = bitmap.rowBytes() / 4;
+ for (int i = 0; i < height; i++) {
+ size_t offset = (i + bitmap_start_y) * row_words + bitmap_start_x;
+ for (int j = 0; j < width; j++) {
+ adjustor(data + offset + j);
+ }
+ }
+ }
+}
+
+} // namespace gfx
+