Index: skia/ext/skia_utils_mac.mm |
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm |
deleted file mode 100644 |
index 9e552eb77b0da67f5a6a5f99a11fd056c9d1ba65..0000000000000000000000000000000000000000 |
--- a/skia/ext/skia_utils_mac.mm |
+++ /dev/null |
@@ -1,462 +0,0 @@ |
-// Copyright (c) 2012 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/skia_utils_mac.h" |
- |
-#import <AppKit/AppKit.h> |
- |
-#include "base/logging.h" |
-#include "base/mac/scoped_cftyperef.h" |
-#include "base/mac/scoped_nsobject.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "skia/ext/bitmap_platform_device_mac.h" |
-#include "third_party/skia/include/core/SkRegion.h" |
-#include "third_party/skia/include/utils/mac/SkCGUtils.h" |
- |
-namespace { |
- |
-// Draws an NSImage or an NSImageRep with a given size into a SkBitmap. |
-SkBitmap NSImageOrNSImageRepToSkBitmapWithColorSpace( |
- NSImage* image, |
- NSImageRep* image_rep, |
- NSSize size, |
- bool is_opaque, |
- CGColorSpaceRef color_space) { |
- // Only image or image_rep should be provided, not both. |
- DCHECK((image != 0) ^ (image_rep != 0)); |
- |
- SkBitmap bitmap; |
- if (!bitmap.tryAllocN32Pixels(size.width, size.height, is_opaque)) |
- return bitmap; // Return |bitmap| which should respond true to isNull(). |
- |
- |
- void* data = bitmap.getPixels(); |
- |
- // Allocate a bitmap context with 4 components per pixel (BGRA). Apple |
- // recommends these flags for improved CG performance. |
-#define HAS_ARGB_SHIFTS(a, r, g, b) \ |
- (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \ |
- && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b)) |
-#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) |
- base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate( |
- data, |
- size.width, |
- size.height, |
- 8, |
- size.width * 4, |
- color_space, |
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); |
-#else |
-#error We require that Skia's and CoreGraphics's recommended \ |
- image memory layout match. |
-#endif |
-#undef HAS_ARGB_SHIFTS |
- |
- // Something went really wrong. Best guess is that the bitmap data is invalid. |
- DCHECK(context); |
- |
- [NSGraphicsContext saveGraphicsState]; |
- |
- NSGraphicsContext* context_cocoa = |
- [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; |
- [NSGraphicsContext setCurrentContext:context_cocoa]; |
- |
- NSRect drawRect = NSMakeRect(0, 0, size.width, size.height); |
- if (image) { |
- [image drawInRect:drawRect |
- fromRect:NSZeroRect |
- operation:NSCompositeCopy |
- fraction:1.0]; |
- } else { |
- [image_rep drawInRect:drawRect |
- fromRect:NSZeroRect |
- operation:NSCompositeCopy |
- fraction:1.0 |
- respectFlipped:NO |
- hints:nil]; |
- } |
- |
- [NSGraphicsContext restoreGraphicsState]; |
- |
- return bitmap; |
-} |
- |
-} // namespace |
- |
-namespace gfx { |
- |
-CGAffineTransform SkMatrixToCGAffineTransform(const SkMatrix& matrix) { |
- // CGAffineTransforms don't support perspective transforms, so make sure |
- // we don't get those. |
- DCHECK(matrix[SkMatrix::kMPersp0] == 0.0f); |
- DCHECK(matrix[SkMatrix::kMPersp1] == 0.0f); |
- DCHECK(matrix[SkMatrix::kMPersp2] == 1.0f); |
- |
- return CGAffineTransformMake(matrix[SkMatrix::kMScaleX], |
- matrix[SkMatrix::kMSkewY], |
- matrix[SkMatrix::kMSkewX], |
- matrix[SkMatrix::kMScaleY], |
- matrix[SkMatrix::kMTransX], |
- matrix[SkMatrix::kMTransY]); |
-} |
- |
-SkRect CGRectToSkRect(const CGRect& rect) { |
- SkRect sk_rect = { |
- rect.origin.x, rect.origin.y, CGRectGetMaxX(rect), CGRectGetMaxY(rect) |
- }; |
- return sk_rect; |
-} |
- |
-CGRect SkIRectToCGRect(const SkIRect& rect) { |
- CGRect cg_rect = { |
- { rect.fLeft, rect.fTop }, |
- { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } |
- }; |
- return cg_rect; |
-} |
- |
-CGRect SkRectToCGRect(const SkRect& rect) { |
- CGRect cg_rect = { |
- { rect.fLeft, rect.fTop }, |
- { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } |
- }; |
- return cg_rect; |
-} |
- |
-// Converts CGColorRef to the ARGB layout Skia expects. |
-SkColor CGColorRefToSkColor(CGColorRef color) { |
- DCHECK(CGColorGetNumberOfComponents(color) == 4); |
- const CGFloat* components = CGColorGetComponents(color); |
- return SkColorSetARGB(SkScalarRoundToInt(255.0 * components[3]), // alpha |
- SkScalarRoundToInt(255.0 * components[0]), // red |
- SkScalarRoundToInt(255.0 * components[1]), // green |
- SkScalarRoundToInt(255.0 * components[2])); // blue |
-} |
- |
-// Converts ARGB to CGColorRef. |
-CGColorRef CGColorCreateFromSkColor(SkColor color) { |
- return CGColorCreateGenericRGB(SkColorGetR(color) / 255.0, |
- SkColorGetG(color) / 255.0, |
- SkColorGetB(color) / 255.0, |
- SkColorGetA(color) / 255.0); |
-} |
- |
-// Converts NSColor to ARGB |
-SkColor NSDeviceColorToSkColor(NSColor* color) { |
- DCHECK([color colorSpace] == [NSColorSpace genericRGBColorSpace] || |
- [color colorSpace] == [NSColorSpace deviceRGBColorSpace]); |
- CGFloat red, green, blue, alpha; |
- color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]; |
- [color getRed:&red green:&green blue:&blue alpha:&alpha]; |
- return SkColorSetARGB(SkScalarRoundToInt(255.0 * alpha), |
- SkScalarRoundToInt(255.0 * red), |
- SkScalarRoundToInt(255.0 * green), |
- SkScalarRoundToInt(255.0 * blue)); |
-} |
- |
-// Converts ARGB to NSColor. |
-NSColor* SkColorToCalibratedNSColor(SkColor color) { |
- return [NSColor colorWithCalibratedRed:SkColorGetR(color) / 255.0 |
- green:SkColorGetG(color) / 255.0 |
- blue:SkColorGetB(color) / 255.0 |
- alpha:SkColorGetA(color) / 255.0]; |
-} |
- |
-NSColor* SkColorToDeviceNSColor(SkColor color) { |
- return [NSColor colorWithDeviceRed:SkColorGetR(color) / 255.0 |
- green:SkColorGetG(color) / 255.0 |
- blue:SkColorGetB(color) / 255.0 |
- alpha:SkColorGetA(color) / 255.0]; |
-} |
- |
-NSColor* SkColorToSRGBNSColor(SkColor color) { |
- const CGFloat components[] = { |
- SkColorGetR(color) / 255.0, |
- SkColorGetG(color) / 255.0, |
- SkColorGetB(color) / 255.0, |
- SkColorGetA(color) / 255.0 |
- }; |
- return [NSColor colorWithColorSpace:[NSColorSpace sRGBColorSpace] |
- components:components |
- count:4]; |
-} |
- |
-SkBitmap CGImageToSkBitmap(CGImageRef image) { |
- if (!image) |
- return SkBitmap(); |
- |
- int width = CGImageGetWidth(image); |
- int height = CGImageGetHeight(image); |
- |
- scoped_ptr<SkBaseDevice> device( |
- skia::BitmapPlatformDevice::Create(NULL, width, height, false)); |
- |
- CGContextRef context = skia::GetBitmapContext(device.get()); |
- |
- // We need to invert the y-axis of the canvas so that Core Graphics drawing |
- // happens right-side up. Skia has an upper-left origin and CG has a lower- |
- // left one. |
- CGContextScaleCTM(context, 1.0, -1.0); |
- CGContextTranslateCTM(context, 0, -height); |
- |
- // We want to copy transparent pixels from |image|, instead of blending it |
- // onto uninitialized pixels. |
- CGContextSetBlendMode(context, kCGBlendModeCopy); |
- |
- CGRect rect = CGRectMake(0, 0, width, height); |
- CGContextDrawImage(context, rect, image); |
- |
- // Because |device| will be cleaned up and will take its pixels with it, we |
- // copy it to the stack and return it. |
- SkBitmap bitmap = device->accessBitmap(false); |
- |
- return bitmap; |
-} |
- |
-SkBitmap NSImageToSkBitmapWithColorSpace( |
- NSImage* image, bool is_opaque, CGColorSpaceRef color_space) { |
- return NSImageOrNSImageRepToSkBitmapWithColorSpace( |
- image, nil, [image size], is_opaque, color_space); |
-} |
- |
-SkBitmap NSImageRepToSkBitmapWithColorSpace(NSImageRep* image_rep, |
- NSSize size, |
- bool is_opaque, |
- CGColorSpaceRef color_space) { |
- return NSImageOrNSImageRepToSkBitmapWithColorSpace( |
- nil, image_rep, size, is_opaque, color_space); |
-} |
- |
-NSBitmapImageRep* SkBitmapToNSBitmapImageRep(const SkBitmap& skiaBitmap) { |
- base::ScopedCFTypeRef<CGColorSpaceRef> color_space( |
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); |
- return SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, color_space); |
-} |
- |
-NSBitmapImageRep* SkBitmapToNSBitmapImageRepWithColorSpace( |
- const SkBitmap& skiaBitmap, |
- CGColorSpaceRef colorSpace) { |
- // First convert SkBitmap to CGImageRef. |
- base::ScopedCFTypeRef<CGImageRef> cgimage( |
- SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace)); |
- |
- // Now convert to NSBitmapImageRep. |
- base::scoped_nsobject<NSBitmapImageRep> bitmap( |
- [[NSBitmapImageRep alloc] initWithCGImage:cgimage]); |
- return [bitmap.release() autorelease]; |
-} |
- |
-NSImage* SkBitmapToNSImageWithColorSpace(const SkBitmap& skiaBitmap, |
- CGColorSpaceRef colorSpace) { |
- if (skiaBitmap.isNull()) |
- return nil; |
- |
- base::scoped_nsobject<NSImage> image([[NSImage alloc] init]); |
- [image addRepresentation: |
- SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, colorSpace)]; |
- [image setSize:NSMakeSize(skiaBitmap.width(), skiaBitmap.height())]; |
- return [image.release() autorelease]; |
-} |
- |
-NSImage* SkBitmapToNSImage(const SkBitmap& skiaBitmap) { |
- base::ScopedCFTypeRef<CGColorSpaceRef> colorSpace( |
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); |
- return SkBitmapToNSImageWithColorSpace(skiaBitmap, colorSpace.get()); |
-} |
- |
-SkiaBitLocker::SkiaBitLocker(SkCanvas* canvas) |
- : canvas_(canvas), |
- userClipRectSpecified_(false), |
- cgContext_(0), |
- bitmapScaleFactor_(1), |
- useDeviceBits_(false), |
- bitmapIsDummy_(false) { |
-} |
- |
-SkiaBitLocker::SkiaBitLocker(SkCanvas* canvas, |
- const SkIRect& userClipRect, |
- SkScalar bitmapScaleFactor) |
- : canvas_(canvas), |
- userClipRectSpecified_(true), |
- cgContext_(0), |
- bitmapScaleFactor_(bitmapScaleFactor), |
- useDeviceBits_(false), |
- bitmapIsDummy_(false) { |
- canvas_->save(); |
- canvas_->clipRect(SkRect::MakeFromIRect(userClipRect)); |
-} |
- |
-SkiaBitLocker::~SkiaBitLocker() { |
- releaseIfNeeded(); |
- if (userClipRectSpecified_) |
- canvas_->restore(); |
-} |
- |
-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()); |
- |
- // Find the bits that were drawn to. |
- SkAutoLockPixels lockedPixels(bitmap_); |
- const uint32_t* pixelBase |
- = reinterpret_cast<uint32_t*>(bitmap_.getPixels()); |
- int rowPixels = bitmap_.rowBytesAsPixels(); |
- int width = bitmap_.width(); |
- int height = bitmap_.height(); |
- SkIRect bounds; |
- bounds.fTop = 0; |
- int x; |
- int y = -1; |
- const uint32_t* pixels = pixelBase; |
- while (++y < height) { |
- for (x = 0; x < width; ++x) { |
- if (pixels[x]) { |
- bounds.fTop = y; |
- goto foundTop; |
- } |
- } |
- pixels += rowPixels; |
- } |
-foundTop: |
- bounds.fBottom = height; |
- y = height; |
- pixels = pixelBase + rowPixels * (y - 1); |
- while (--y > bounds.fTop) { |
- for (x = 0; x < width; ++x) { |
- if (pixels[x]) { |
- bounds.fBottom = y + 1; |
- goto foundBottom; |
- } |
- } |
- pixels -= rowPixels; |
- } |
-foundBottom: |
- bounds.fLeft = 0; |
- x = -1; |
- while (++x < width) { |
- pixels = pixelBase + rowPixels * bounds.fTop; |
- for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
- if (pixels[x]) { |
- bounds.fLeft = x; |
- goto foundLeft; |
- } |
- pixels += rowPixels; |
- } |
- } |
-foundLeft: |
- bounds.fRight = width; |
- x = width; |
- while (--x > bounds.fLeft) { |
- pixels = pixelBase + rowPixels * bounds.fTop; |
- for (y = bounds.fTop; y < bounds.fBottom; ++y) { |
- if (pixels[x]) { |
- bounds.fRight = x + 1; |
- goto foundRight; |
- } |
- pixels += rowPixels; |
- } |
- } |
-foundRight: |
- return bounds; |
-} |
- |
-// This must be called to balance calls to cgContext |
-void SkiaBitLocker::releaseIfNeeded() { |
- if (!cgContext_) |
- return; |
- if (useDeviceBits_) { |
- bitmap_.unlockPixels(); |
- } else if (!bitmapIsDummy_) { |
- // Find the bits that were drawn to. |
- SkIRect bounds = computeDirtyRect(); |
- SkBitmap subset; |
- if (!bitmap_.extractSubset(&subset, bounds)) { |
- return; |
- } |
- subset.setImmutable(); // Prevents a defensive copy inside Skia. |
- canvas_->save(); |
- canvas_->setMatrix(SkMatrix::I()); // Reset back to device space. |
- canvas_->translate(bounds.x() + bitmapOffset_.x(), |
- bounds.y() + bitmapOffset_.y()); |
- canvas_->scale(1.f / bitmapScaleFactor_, 1.f / bitmapScaleFactor_); |
- canvas_->drawBitmap(subset, 0, 0); |
- canvas_->restore(); |
- } |
- CGContextRelease(cgContext_); |
- cgContext_ = 0; |
- useDeviceBits_ = false; |
- bitmapIsDummy_ = false; |
-} |
- |
-CGContextRef SkiaBitLocker::cgContext() { |
- SkIRect clip_bounds; |
- if (!canvas_->getClipDeviceBounds(&clip_bounds)) { |
- // If the clip is empty, then there is nothing to draw. The caller may |
- // attempt to draw (to-be-clipped) results, so ensure there is a dummy |
- // non-NULL CGContext to use. |
- bitmapIsDummy_ = true; |
- clip_bounds = SkIRect::MakeXYWH(0, 0, 1, 1); |
- } |
- |
- SkBaseDevice* device = canvas_->getTopDevice(); |
- DCHECK(device); |
- if (!device) |
- return 0; |
- |
- releaseIfNeeded(); // This flushes any prior bitmap use |
- |
- // remember the top/left, in case we need to compose this later |
- bitmapOffset_.set(clip_bounds.x(), clip_bounds.y()); |
- |
- // Now make clip_bounds be relative to the current layer/device |
- clip_bounds.offset(-device->getOrigin()); |
- |
- const SkBitmap& deviceBits = device->accessBitmap(true); |
- |
- // 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() && |
- canvas_->isClipRect() && |
- !bitmapIsDummy_; |
- if (useDeviceBits_) { |
- bool result = deviceBits.extractSubset(&bitmap_, clip_bounds); |
- DCHECK(result); |
- if (!result) |
- return 0; |
- bitmap_.lockPixels(); |
- } else { |
- bool result = bitmap_.tryAllocN32Pixels( |
- SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.width()), |
- SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.height())); |
- DCHECK(result); |
- if (!result) |
- return 0; |
- bitmap_.eraseColor(0); |
- } |
- base::ScopedCFTypeRef<CGColorSpaceRef> 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())); |
- |
- CGContextConcatCTM(cgContext_, SkMatrixToCGAffineTransform(matrix)); |
- |
- return cgContext_; |
-} |
- |
-bool SkiaBitLocker::hasEmptyClipRegion() const { |
- return canvas_->isClipEmpty(); |
-} |
- |
-} // namespace gfx |