diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 20:32:45 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-21 20:32:45 +0000 |
commit | 98abd85558e19788d971df47690bcb4eb4dd8d98 (patch) | |
tree | 3639cbd4ce1324ce34be603ed36fec0022a438d7 /skia/ext/bitmap_platform_device_mac.cc | |
parent | 21ba9918905c5f3f66e3a075944587618da2d52d (diff) | |
download | chromium_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-x | skia/ext/bitmap_platform_device_mac.cc | 290 |
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 + |