123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // 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 <stdint.h>
- #include <memory>
- #include "base/check.h"
- #include "base/mac/mac_util.h"
- #include "base/mac/scoped_cftyperef.h"
- #include "base/mac/scoped_nsobject.h"
- #include "skia/ext/platform_canvas.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 != nullptr) ^ (image_rep != nullptr));
- 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,
- uint32_t{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:NSCompositingOperationCopy
- fraction:1.0];
- } else {
- [image_rep drawInRect:drawRect
- fromRect:NSZeroRect
- operation:NSCompositingOperationCopy
- fraction:1.0
- respectFlipped:NO
- hints:nil];
- }
- [NSGraphicsContext restoreGraphicsState];
- return bitmap;
- }
- } // namespace
- namespace skia {
- 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;
- }
- SkColor NSSystemColorToSkColor(NSColor* color) {
- // System colors use the an NSNamedColorSpace called "System", so first step
- // is to convert the color into something that can be worked with.
- NSColor* device_color =
- [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
- if (device_color)
- return NSDeviceColorToSkColor(device_color);
- // Sometimes the conversion is not possible, but we can get an approximation
- // by going through a CGColorRef. Note that simply using NSColor methods for
- // accessing components for system colors results in exceptions like
- // "-numberOfComponents not valid for the NSColor NSNamedColorSpace System
- // windowBackgroundColor; need to first convert colorspace." Hence the
- // conversion first to CGColor.
- CGColorRef cg_color = [color CGColor];
- const size_t component_count = CGColorGetNumberOfComponents(cg_color);
- if (component_count == 4)
- return CGColorRefToSkColor(cg_color);
- CHECK(component_count == 1 || component_count == 2);
- // 1-2 components means a grayscale channel and maybe an alpha channel, which
- // CGColorRefToSkColor will not like. But RGB is additive, so the conversion
- // is easy (RGB to grayscale is less easy).
- const CGFloat* components = CGColorGetComponents(cg_color);
- CGFloat alpha = component_count == 2 ? components[1] : 1.0f;
- return SkColor4f{components[0], components[0], components[0], alpha}
- .toSkColor();
- }
- SkColor CGColorRefToSkColor(CGColorRef color) {
- base::ScopedCFTypeRef<CGColorRef> cg_color(
- CGColorCreateCopyByMatchingToColorSpace(base::mac::GetSRGBColorSpace(),
- kCGRenderingIntentDefault, color,
- nullptr));
- DCHECK(CGColorGetNumberOfComponents(color) == 4);
- const CGFloat* components = CGColorGetComponents(cg_color);
- return SkColor4f{components[0], components[1], components[2], components[3]}
- .toSkColor();
- }
- base::ScopedCFTypeRef<CGColorRef> CGColorCreateFromSkColor(SkColor color) {
- CGFloat components[] = {
- SkColorGetR(color) / 255.0f, SkColorGetG(color) / 255.0f,
- SkColorGetB(color) / 255.0f, SkColorGetA(color) / 255.0f};
- return base::ScopedCFTypeRef<CGColorRef>(
- CGColorCreate(base::mac::GetSRGBColorSpace(), components));
- }
- // 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 SkColor4f{red, green, blue, alpha}.toSkColor();
- }
- // Converts ARGB to NSColor.
- NSColor* SkColorToCalibratedNSColor(SkColor color) {
- return [NSColor colorWithCalibratedRed:SkColorGetR(color) / 255.0f
- green:SkColorGetG(color) / 255.0f
- blue:SkColorGetB(color) / 255.0f
- alpha:SkColorGetA(color) / 255.0f];
- }
- NSColor* SkColorToDeviceNSColor(SkColor color) {
- return [NSColor colorWithDeviceRed:SkColorGetR(color) / 255.0f
- green:SkColorGetG(color) / 255.0f
- blue:SkColorGetB(color) / 255.0f
- alpha:SkColorGetA(color) / 255.0f];
- }
- NSColor* SkColorToSRGBNSColor(SkColor color) {
- const CGFloat components[] = {
- SkColorGetR(color) / 255.0f, SkColorGetG(color) / 255.0f,
- SkColorGetB(color) / 255.0f, SkColorGetA(color) / 255.0f};
- return [NSColor colorWithColorSpace:[NSColorSpace sRGBColorSpace]
- components:components
- count:4];
- }
- SkBitmap CGImageToSkBitmap(CGImageRef image) {
- SkBitmap bitmap;
- if (image && SkCreateBitmapFromCGImage(&bitmap, image))
- return bitmap;
- return SkBitmap();
- }
- 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* SkBitmapToNSBitmapImageRepWithColorSpace(
- const SkBitmap& skiaBitmap,
- CGColorSpaceRef colorSpace) {
- // First convert SkBitmap to CGImageRef.
- base::ScopedCFTypeRef<CGImageRef> cgimage(
- SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace));
- if (!cgimage)
- return nil;
- // 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]);
- NSBitmapImageRep* imageRep =
- SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, colorSpace);
- if (!imageRep)
- return nil;
- [image addRepresentation:imageRep];
- [image setSize:NSMakeSize(skiaBitmap.width(), skiaBitmap.height())];
- return [image.release() autorelease];
- }
- } // namespace skia
|