diff options
author | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-14 12:55:23 +0000 |
---|---|---|
committer | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-14 12:55:23 +0000 |
commit | d5f5c2a08c3130d4836551f713dab341f4c06db3 (patch) | |
tree | 6210951e7f43d3bf8aaf2377e2855d5b2b2b2b03 | |
parent | 9a9f8bd9220215ae97cab7cb43bba8eb0b0d52bf (diff) | |
download | chromium_src-d5f5c2a08c3130d4836551f713dab341f4c06db3.zip chromium_src-d5f5c2a08c3130d4836551f713dab341f4c06db3.tar.gz chromium_src-d5f5c2a08c3130d4836551f713dab341f4c06db3.tar.bz2 |
Adds an iOS implementation of gfx::Image.
BUG=None
TEST=None
Review URL: https://chromiumcodereview.appspot.com/10928093
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156787 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | skia/ext/skia_utils_ios.h | 30 | ||||
-rw-r--r-- | skia/ext/skia_utils_ios.mm | 77 | ||||
-rw-r--r-- | skia/skia.gyp | 8 | ||||
-rw-r--r-- | ui/base/layout.cc | 7 | ||||
-rw-r--r-- | ui/gfx/image/image.cc | 118 | ||||
-rw-r--r-- | ui/gfx/image/image.h | 12 | ||||
-rw-r--r-- | ui/gfx/image/image_ios.mm | 71 | ||||
-rw-r--r-- | ui/gfx/image/image_skia_util_ios.h | 27 | ||||
-rw-r--r-- | ui/gfx/image/image_skia_util_ios.mm | 59 | ||||
-rw-r--r-- | ui/gfx/image/image_unittest.cc | 21 | ||||
-rw-r--r-- | ui/gfx/image/image_unittest_util.cc | 24 | ||||
-rw-r--r-- | ui/gfx/image/image_unittest_util.h | 4 | ||||
-rw-r--r-- | ui/gfx/image/image_util.cc | 15 | ||||
-rw-r--r-- | ui/gfx/image/image_util.h | 10 | ||||
-rw-r--r-- | ui/gfx/image/image_util_ios.mm | 27 | ||||
-rw-r--r-- | ui/ui.gyp | 36 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 19 |
17 files changed, 511 insertions, 54 deletions
diff --git a/skia/ext/skia_utils_ios.h b/skia/ext/skia_utils_ios.h new file mode 100644 index 0000000..0b086ad --- /dev/null +++ b/skia/ext/skia_utils_ios.h @@ -0,0 +1,30 @@ +// Copyright 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. + +#ifndef SKIA_EXT_SKIA_UTILS_IOS_H_ +#define SKIA_EXT_SKIA_UTILS_IOS_H_ + +#include <CoreGraphics/CoreGraphics.h> +#include <vector> + +#include "third_party/skia/include/core/SkBitmap.h" + +#ifdef __OBJC__ +@class UIImage; +#else +class UIImage; +#endif + +namespace gfx { + +// Draws a UIImage with a given size into a SkBitmap. +SK_API SkBitmap UIImageToSkBitmap(UIImage* image, CGSize size, bool is_opaque); + +// Given an SkBitmap and a color space, return an autoreleased UIImage. +SK_API UIImage* SkBitmapToUIImageWithColorSpace(const SkBitmap& skia_bitmap, + CGColorSpaceRef color_space); + +} // namespace gfx + +#endif // SKIA_EXT_SKIA_UTILS_IOS_H_ diff --git a/skia/ext/skia_utils_ios.mm b/skia/ext/skia_utils_ios.mm new file mode 100644 index 0000000..9d4c14a --- /dev/null +++ b/skia/ext/skia_utils_ios.mm @@ -0,0 +1,77 @@ +// Copyright 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_ios.h" + +#import <UIKit/UIKit.h> + +#include "base/logging.h" +#include "base/mac/scoped_cftyperef.h" +#include "third_party/skia/include/utils/mac/SkCGUtils.h" + +namespace gfx { + +SkBitmap UIImageToSkBitmap(UIImage* image, CGSize size, bool is_opaque) { + SkBitmap bitmap; + if (!image) + return bitmap; + + bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width, size.height); + if (!bitmap.allocPixels()) + return bitmap; + + bitmap.setIsOpaque(is_opaque); + 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::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space( + CGColorSpaceCreateDeviceRGB()); + base::mac::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 + + DCHECK(context); + if (!context) + return bitmap; + + // UIGraphicsPushContext be called from the main thread. + // TODO(rohitrao): We can use CG to make this thread safe, but the mac code + // calls setCurrentContext, so it's similarly limited to the main thread. + DCHECK([NSThread isMainThread]); + UIGraphicsPushContext(context); + [image drawInRect:CGRectMake(0, 0, size.width, size.height) + blendMode:kCGBlendModeCopy + alpha:1.0]; + UIGraphicsPopContext(); + + return bitmap; +} + +UIImage* SkBitmapToUIImageWithColorSpace(const SkBitmap& skia_bitmap, + CGColorSpaceRef color_space) { + if (skia_bitmap.isNull()) + return nil; + + // First convert SkBitmap to CGImageRef. + base::mac::ScopedCFTypeRef<CGImageRef> cg_image( + SkCreateCGImageRefWithColorspace(skia_bitmap, color_space)); + + // Now convert to UIImage. + // TODO(rohitrao): Gotta incorporate the scale factor somewhere! + return [UIImage imageWithCGImage:cg_image.get()]; +} + +} // namespace gfx diff --git a/skia/skia.gyp b/skia/skia.gyp index 618ac91..894e360 100644 --- a/skia/skia.gyp +++ b/skia/skia.gyp @@ -183,6 +183,8 @@ 'ext/skia_sandbox_support_win.h', 'ext/skia_sandbox_support_win.cc', 'ext/skia_trace_shim.h', + 'ext/skia_utils_ios.mm', + 'ext/skia_utils_ios.h', 'ext/skia_utils_mac.mm', 'ext/skia_utils_mac.h', 'ext/skia_utils_win.cc', @@ -308,6 +310,11 @@ 'SK_DEFAULT_FONT_CACHE_LIMIT=(20*1024*1024)', ], }], + [ 'OS != "ios"', { + 'sources/': [ + ['exclude', '_ios\\.(cc|cpp|mm?)$'], + ], + }], [ 'OS != "mac"', { 'sources/': [ ['exclude', '_mac\\.(cc|cpp|mm?)$'], @@ -593,6 +600,7 @@ 'sources/': [ ['include', 'SkFontHost_mac\\.cpp$',], ['include', 'SkStream_mac\\.cpp$',], + ['include', 'SkCreateCGImageRef\\.cpp$',], ], }], ], diff --git a/ui/base/layout.cc b/ui/base/layout.cc index ffc7082..48bdab6 100644 --- a/ui/base/layout.cc +++ b/ui/base/layout.cc @@ -19,7 +19,7 @@ #include "ui/compositor/compositor.h" #endif // defined(USE_AURA) && !defined(OS_WIN) -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) #include "base/mac/mac_util.h" #endif @@ -70,7 +70,10 @@ std::vector<ui::ScaleFactor>& GetSupportedScaleFactorsInternal() { new std::vector<ui::ScaleFactor>(); if (supported_scale_factors->empty()) { supported_scale_factors->push_back(ui::SCALE_FACTOR_100P); -#if defined(OS_MACOSX) && defined(ENABLE_HIDPI) +// TODO(rohitrao): Set the appropriate scale factors for iOS. Ideally set +// either 100P or 200P but not both, since a given device will only ever use one +// scale factor. +#if defined(OS_MACOSX) && !defined(OS_IOS) && defined(ENABLE_HIDPI) if (base::mac::IsOSLionOrLater()) supported_scale_factors->push_back(ui::SCALE_FACTOR_200P); #elif defined(OS_WIN) && defined(ENABLE_HIDPI) diff --git a/ui/gfx/image/image.cc b/ui/gfx/image/image.cc index c5c0c76..7a87cc3 100644 --- a/ui/gfx/image/image.cc +++ b/ui/gfx/image/image.cc @@ -9,10 +9,13 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/size.h" +#if !defined(OS_IOS) +#include "ui/gfx/codec/png_codec.h" +#endif + #if defined(TOOLKIT_GTK) #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk/gdk.h> @@ -21,6 +24,9 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/gtk_util.h" #include "ui/gfx/image/cairo_cached_surface.h" +#elif defined(OS_IOS) +#include "base/mac/foundation_util.h" +#include "ui/gfx/image/image_skia_util_ios.h" #elif defined(OS_MACOSX) #include "base/mac/mac_util.h" #include "ui/gfx/image/image_skia_util_mac.h" @@ -84,11 +90,18 @@ void PNGFromGdkPixbuf(GdkPixbuf* pixbuf, std::vector<unsigned char>* png) { #endif // defined(TOOLKIT_GTK) -#if defined(OS_MACOSX) +#if defined(OS_IOS) +void PNGFromUIImage(UIImage* nsimage, std::vector<unsigned char>* png); +UIImage* CreateUIImageFromPNG(const std::vector<unsigned char>& png); +#elif defined(OS_MACOSX) void PNGFromNSImage(NSImage* nsimage, std::vector<unsigned char>* png); NSImage* NSImageFromPNG(const std::vector<unsigned char>& png); #endif // defined(OS_MACOSX) +#if defined(OS_IOS) +ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png); +void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png); +#else ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png) { SkBitmap bitmap; if (!gfx::PNGCodec::Decode(&png.front(), png.size(), &bitmap)) { @@ -104,12 +117,14 @@ ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png) { void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png) { CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(*skia->bitmap(), false, png)); } +#endif class ImageRepPNG; class ImageRepSkia; class ImageRepGdk; class ImageRepCairo; class ImageRepCocoa; +class ImageRepCocoaTouch; // An ImageRep is the object that holds the backing memory for an Image. Each // RepresentationType has an ImageRep subclass that is responsible for freeing @@ -146,7 +161,12 @@ class ImageRep { } #endif -#if defined(OS_MACOSX) +#if defined(OS_IOS) + ImageRepCocoaTouch* AsImageRepCocoaTouch() { + CHECK_EQ(type_, Image::kImageRepCocoaTouch); + return reinterpret_cast<ImageRepCocoaTouch*>(this); + } +#elif defined(OS_MACOSX) ImageRepCocoa* AsImageRepCocoa() { CHECK_EQ(type_, Image::kImageRepCocoa); return reinterpret_cast<ImageRepCocoa*>(this); @@ -245,7 +265,28 @@ class ImageRepCairo : public ImageRep { }; #endif // defined(TOOLKIT_GTK) -#if defined(OS_MACOSX) +#if defined(OS_IOS) +class ImageRepCocoaTouch : public ImageRep { + public: + explicit ImageRepCocoaTouch(UIImage* image) + : ImageRep(Image::kImageRepCocoaTouch), + image_(image) { + CHECK(image); + } + + virtual ~ImageRepCocoaTouch() { + base::mac::NSObjectRelease(image_); + image_ = nil; + } + + UIImage* image() const { return image_; } + + private: + UIImage* image_; + + DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch); +}; +#elif defined(OS_MACOSX) class ImageRepCocoa : public ImageRep { public: explicit ImageRepCocoa(NSImage* image) @@ -343,7 +384,15 @@ Image::Image(GdkPixbuf* pixbuf) { } #endif -#if defined(OS_MACOSX) +#if defined(OS_IOS) +Image::Image(UIImage* image) + : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) { + if (image) { + internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image); + AddRepresentation(rep); + } +} +#elif defined(OS_MACOSX) Image::Image(NSImage* image) { if (image) { storage_ = new internal::ImageStorage(Image::kImageRepCocoa); @@ -376,6 +425,14 @@ const std::vector<unsigned char>* Image::ToImagePNG() const { internal::PNGFromGdkPixbuf(gdk_rep->pixbuf(), png_rep->image()); break; } +#elif defined(OS_IOS) + case kImageRepCocoaTouch: { + internal::ImageRepCocoaTouch* cocoa_touch_rep = + GetRepresentation(kImageRepCocoaTouch, true) + ->AsImageRepCocoaTouch(); + internal::PNGFromUIImage(cocoa_touch_rep->image(), png_rep->image()); + break; + } #elif defined(OS_MACOSX) case kImageRepCocoa: { internal::ImageRepCocoa* cocoa_rep = @@ -424,6 +481,15 @@ const ImageSkia* Image::ToImageSkia() const { internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf()))); break; } +#elif defined(OS_IOS) + case kImageRepCocoaTouch: { + internal::ImageRepCocoaTouch* native_rep = + GetRepresentation(kImageRepCocoaTouch, true) + ->AsImageRepCocoaTouch(); + rep = new internal::ImageRepSkia(new ImageSkia( + ImageSkiaFromUIImage(native_rep->image()))); + break; + } #elif defined(OS_MACOSX) case kImageRepCocoa: { internal::ImageRepCocoa* native_rep = @@ -483,7 +549,35 @@ CairoCachedSurface* const Image::ToCairo() const { } #endif -#if defined(OS_MACOSX) +#if defined(OS_IOS) +UIImage* Image::ToUIImage() const { + internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false); + if (!rep) { + switch (DefaultRepresentationType()) { + case kImageRepPNG: { + internal::ImageRepPNG* png_rep = + GetRepresentation(kImageRepPNG, true)->AsImageRepPNG(); + rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG( + *png_rep->image())); + break; + } + case kImageRepSkia: { + internal::ImageRepSkia* skia_rep = + GetRepresentation(kImageRepSkia, true)->AsImageRepSkia(); + UIImage* image = UIImageFromImageSkia(*skia_rep->image()); + base::mac::NSObjectRetain(image); + rep = new internal::ImageRepCocoaTouch(image); + break; + } + default: + NOTREACHED(); + } + CHECK(rep); + AddRepresentation(rep); + } + return rep->AsImageRepCocoaTouch()->image(); +} +#elif defined(OS_MACOSX) NSImage* Image::ToNSImage() const { internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false); if (!rep) { @@ -525,7 +619,7 @@ ImageSkia Image::AsImageSkia() const { return IsEmpty() ? ImageSkia() : *ToImageSkia(); } -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) NSImage* Image::AsNSImage() const { return IsEmpty() ? nil : ToNSImage(); } @@ -547,7 +641,13 @@ GdkPixbuf* Image::CopyGdkPixbuf() const { } #endif -#if defined(OS_MACOSX) +#if defined(OS_IOS) +UIImage* Image::CopyUIImage() const { + UIImage* image = ToUIImage(); + base::mac::NSObjectRetain(image); + return image; +} +#elif defined(OS_MACOSX) NSImage* Image::CopyNSImage() const { NSImage* image = ToNSImage(); base::mac::NSObjectRetain(image); @@ -555,7 +655,7 @@ NSImage* Image::CopyNSImage() const { } #endif -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) Image::operator NSImage*() const { return ToNSImage(); } diff --git a/ui/gfx/image/image.h b/ui/gfx/image/image.h index 999e397..05a50a4 100644 --- a/ui/gfx/image/image.h +++ b/ui/gfx/image/image.h @@ -52,6 +52,7 @@ class UI_EXPORT Image { enum RepresentationType { kImageRepGdk, kImageRepCocoa, + kImageRepCocoaTouch, kImageRepCairo, kImageRepSkia, kImageRepPNG, @@ -80,6 +81,9 @@ class UI_EXPORT Image { #if defined(TOOLKIT_GTK) // Does not increase |pixbuf|'s reference count; expects to take ownership. explicit Image(GdkPixbuf* pixbuf); +#elif defined(OS_IOS) + // Does not retain |image|; expects to take ownership. + explicit Image(UIImage* image); #elif defined(OS_MACOSX) // Does not retain |image|; expects to take ownership. // A single NSImage object can contain multiple bitmaps so there's no reason @@ -106,6 +110,8 @@ class UI_EXPORT Image { #if defined(TOOLKIT_GTK) GdkPixbuf* ToGdkPixbuf() const; CairoCachedSurface* const ToCairo() const; +#elif defined(OS_IOS) + UIImage* ToUIImage() const; #elif defined(OS_MACOSX) NSImage* ToNSImage() const; #endif @@ -117,7 +123,7 @@ class UI_EXPORT Image { // image is empty. ImageSkia AsImageSkia() const; -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) // Same as ToSkBitmap(), but returns nil if this image is empty. NSImage* AsNSImage() const; #endif @@ -133,13 +139,15 @@ class UI_EXPORT Image { SkBitmap* CopySkBitmap() const; #if defined(TOOLKIT_GTK) GdkPixbuf* CopyGdkPixbuf() const; +#elif defined(OS_IOS) + UIImage* CopyUIImage() const; #elif defined(OS_MACOSX) NSImage* CopyNSImage() const; #endif // DEPRECATED ---------------------------------------------------------------- // Conversion handlers. These wrap the ToType() variants. -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) operator NSImage*() const; #endif // --------------------------------------------------------------------------- diff --git a/ui/gfx/image/image_ios.mm b/ui/gfx/image/image_ios.mm new file mode 100644 index 0000000..c8db540 --- /dev/null +++ b/ui/gfx/image/image_ios.mm @@ -0,0 +1,71 @@ +// Copyright 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 "ui/gfx/image/image.h" + +#import <UIKit/UIKit.h> + +#include "base/logging.h" +#include "base/memory/scoped_nsobject.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_util_ios.h" + +namespace gfx { +namespace internal { + +void PNGFromUIImage(UIImage* uiimage, std::vector<unsigned char>* png) { + NSData* data = UIImagePNGRepresentation(uiimage); + + if ([data length] == 0) + return; + + png->resize([data length]); + [data getBytes:&png->at(0) length:[data length]]; +} + +UIImage* CreateUIImageFromPNG(const std::vector<unsigned char>& png) { + NSData* data = [NSData dataWithBytes:&png.front() length:png.size()]; + scoped_nsobject<UIImage> image ([[UIImage alloc] initWithData:data]); + if (!image) { + LOG(WARNING) << "Unable to decode PNG into UIImage."; + // Return a 16x16 red image to visually show error. + UIGraphicsBeginImageContext(CGSizeMake(16, 16)); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); + CGContextFillRect(context, CGRectMake(0.0, 0.0, 16, 16)); + image.reset([UIGraphicsGetImageFromCurrentImageContext() retain]); + UIGraphicsEndImageContext(); + } + return image.release(); +} + +void PNGFromImageSkia(const ImageSkia* skia, std::vector<unsigned char>* png) { + // iOS does not expose libpng, so conversion from ImageSkia to PNG must go + // through UIImage. + // TODO(rohitrao): Rewrite the callers of this function to save the UIImage + // representation in the gfx::Image. If we're generating it, we might as well + // hold on to it. + UIImage* image = UIImageFromImageSkia(*skia); + PNGFromUIImage(image, png); +} + +ImageSkia* ImageSkiaFromPNG(const std::vector<unsigned char>& png) { + // iOS does not expose libpng, so conversion from PNG to ImageSkia must go + // through UIImage. + scoped_nsobject<UIImage> uiimage(CreateUIImageFromPNG(png)); + if (!uiimage) { + LOG(WARNING) << "Unable to decode PNG into ImageSkia."; + // Return a 16x16 red image to visually show error. + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); + bitmap.allocPixels(); + bitmap.eraseRGB(0xff, 0, 0); + return new ImageSkia(bitmap); + } + + return new ImageSkia(ImageSkiaFromUIImage(uiimage)); +} + +} // namespace internal +} // namespace gfx diff --git a/ui/gfx/image/image_skia_util_ios.h b/ui/gfx/image/image_skia_util_ios.h new file mode 100644 index 0000000..3862d1d --- /dev/null +++ b/ui/gfx/image/image_skia_util_ios.h @@ -0,0 +1,27 @@ +// Copyright 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. + +#ifndef UI_GFX_IMAGE_IMAGE_SKIA_UTIL_IOS_H_ +#define UI_GFX_IMAGE_IMAGE_SKIA_UTIL_IOS_H_ + +#include "ui/base/ui_export.h" + +#ifdef __OBJC__ +@class UIImage; +#else +class UIImage; +#endif + +namespace gfx { +class ImageSkia; + +// Converts to ImageSkia from UIImage. +UI_EXPORT gfx::ImageSkia ImageSkiaFromUIImage(UIImage* image); + +// Converts to UIImage from ImageSkia. Returns an autoreleased UIImage. +UI_EXPORT UIImage* UIImageFromImageSkia(const gfx::ImageSkia& image_skia); + +} // namespace gfx + +#endif // UI_GFX_IMAGE_IMAGE_SKIA_UTIL_IOS_H_ diff --git a/ui/gfx/image/image_skia_util_ios.mm b/ui/gfx/image/image_skia_util_ios.mm new file mode 100644 index 0000000..47f076f --- /dev/null +++ b/ui/gfx/image/image_skia_util_ios.mm @@ -0,0 +1,59 @@ +// Copyright 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 "ui/gfx/image/image_skia_util_ios.h" + +#include <UIKit/UIKit.h> + +#include "base/logging.h" +#include "base/mac/scoped_cftyperef.h" +#include "skia/ext/skia_utils_ios.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/image/image_skia.h" + +namespace gfx { + +gfx::ImageSkia ImageSkiaFromUIImage(UIImage* image) { + gfx::ImageSkia image_skia; + if (!image) + return image_skia; + + // iOS only supports one scale factor. + std::vector<ui::ScaleFactor> supported_scale_factors = + ui::GetSupportedScaleFactors(); + DCHECK_EQ(1U, supported_scale_factors.size()); + if (supported_scale_factors.size() < 1) + return image_skia; + + ui::ScaleFactor scale_factor = supported_scale_factors[0]; + float scale = ui::GetScaleFactorScale(scale_factor); + CGSize size = image.size; + CGSize desired_size_for_scale = + CGSizeMake(size.width * scale, size.height * scale); + SkBitmap bitmap(gfx::UIImageToSkBitmap(image, desired_size_for_scale, false)); + if (!bitmap.isNull()) + image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor)); + return image_skia; +} + +UIImage* UIImageFromImageSkia(const gfx::ImageSkia& image_skia) { + if (image_skia.isNull()) + return nil; + + // iOS only supports one scale factor. + std::vector<ui::ScaleFactor> supported_scale_factors = + ui::GetSupportedScaleFactors(); + DCHECK_EQ(1U, supported_scale_factors.size()); + if (supported_scale_factors.size() < 1) + return nil; + + image_skia.EnsureRepsForSupportedScaleFactors(); + const ImageSkiaRep& rep = + image_skia.GetRepresentation(supported_scale_factors[0]); + base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space( + CGColorSpaceCreateDeviceRGB()); + return gfx::SkBitmapToUIImageWithColorSpace(rep.sk_bitmap(), color_space); +} + +} // namespace gfx diff --git a/ui/gfx/image/image_unittest.cc b/ui/gfx/image/image_unittest.cc index 967bb3a..5c5dd23 100644 --- a/ui/gfx/image/image_unittest.cc +++ b/ui/gfx/image/image_unittest.cc @@ -10,6 +10,9 @@ #if defined(TOOLKIT_GTK) #include <gtk/gtk.h> #include "ui/gfx/gtk_util.h" +#elif defined(OS_IOS) +#include "base/mac/foundation_util.h" +#include "skia/ext/skia_utils_ios.h" #elif defined(OS_MACOSX) #include "base/mac/mac_util.h" #include "skia/ext/skia_utils_mac.h" @@ -171,11 +174,15 @@ TEST_F(ImageTest, PNGDecodeToSkiaFailure) { gt::CheckColor(bitmap->getColor(10, 10), true); } +// TODO(rohitrao): This test needs an iOS implementation of +// GetPlatformImageColor(). +#if !defined(OS_IOS) TEST_F(ImageTest, PNGDecodeToPlatformFailure) { std::vector<unsigned char> png(100, 0); gfx::Image image(&png.front(), png.size()); gt::CheckColor(gt::GetPlatformImageColor(gt::ToPlatformType(image)), true); } +#endif TEST_F(ImageTest, SkiaToPlatform) { gfx::Image image(gt::CreateBitmap(25, 25)); @@ -264,7 +271,19 @@ TEST_F(ImageTest, SkiaToCairoCreatesGdk) { } #endif -#if defined(OS_MACOSX) +#if defined(OS_IOS) +TEST_F(ImageTest, SkiaToCocoaTouchCopy) { + UIImage* ui_image; + + { + gfx::Image image(gt::CreateBitmap(25, 25)); + ui_image = image.CopyUIImage(); + } + + EXPECT_TRUE(ui_image); + base::mac::NSObjectRelease(ui_image); +} +#elif defined(OS_MACOSX) TEST_F(ImageTest, SkiaToCocoaCopy) { NSImage* ns_image; diff --git a/ui/gfx/image/image_unittest_util.cc b/ui/gfx/image/image_unittest_util.cc index f7486ea..6291b23 100644 --- a/ui/gfx/image/image_unittest_util.cc +++ b/ui/gfx/image/image_unittest_util.cc @@ -14,6 +14,10 @@ #if defined(TOOLKIT_GTK) #include <gtk/gtk.h> #include "ui/gfx/gtk_util.h" +#elif defined(OS_IOS) +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" +#include "skia/ext/skia_utils_ios.h" #elif defined(OS_MACOSX) #include "base/mac/mac_util.h" #include "skia/ext/skia_utils_mac.h" @@ -79,7 +83,13 @@ bool IsEmpty(const gfx::Image& image) { PlatformImage CreatePlatformImage() { const SkBitmap bitmap(CreateBitmap(25, 25)); -#if defined(OS_MACOSX) +#if defined(OS_IOS) + base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space( + CGColorSpaceCreateDeviceRGB()); + UIImage* image = gfx::SkBitmapToUIImageWithColorSpace(bitmap, color_space); + base::mac::NSObjectRetain(image); + return image; +#elif defined(OS_MACOSX) NSImage* image = gfx::SkBitmapToNSImage(bitmap); base::mac::NSObjectRetain(image); return image; @@ -91,7 +101,9 @@ PlatformImage CreatePlatformImage() { } gfx::Image::RepresentationType GetPlatformRepresentationType() { -#if defined(OS_MACOSX) +#if defined(OS_IOS) + return gfx::Image::kImageRepCocoaTouch; +#elif defined(OS_MACOSX) return gfx::Image::kImageRepCocoa; #elif defined(TOOLKIT_GTK) return gfx::Image::kImageRepGdk; @@ -101,7 +113,9 @@ gfx::Image::RepresentationType GetPlatformRepresentationType() { } PlatformImage ToPlatformType(const gfx::Image& image) { -#if defined(OS_MACOSX) +#if defined(OS_IOS) + return image.ToUIImage(); +#elif defined(OS_MACOSX) return image.ToNSImage(); #elif defined(TOOLKIT_GTK) return image.ToGdkPixbuf(); @@ -111,7 +125,9 @@ PlatformImage ToPlatformType(const gfx::Image& image) { } PlatformImage CopyPlatformType(const gfx::Image& image) { -#if defined(OS_MACOSX) +#if defined(OS_IOS) + return image.CopyUIImage(); +#elif defined(OS_MACOSX) return image.CopyNSImage(); #elif defined(TOOLKIT_GTK) return image.CopyGdkPixbuf(); diff --git a/ui/gfx/image/image_unittest_util.h b/ui/gfx/image/image_unittest_util.h index de97133..4560ce6 100644 --- a/ui/gfx/image/image_unittest_util.h +++ b/ui/gfx/image/image_unittest_util.h @@ -14,7 +14,9 @@ namespace gfx { namespace test { -#if defined(OS_MACOSX) +#if defined(OS_IOS) +typedef UIImage* PlatformImage; +#elif defined(OS_MACOSX) typedef NSImage* PlatformImage; #elif defined(TOOLKIT_GTK) typedef GdkPixbuf* PlatformImage; diff --git a/ui/gfx/image/image_util.cc b/ui/gfx/image/image_util.cc index 6403419..04bc5a2 100644 --- a/ui/gfx/image/image_util.cc +++ b/ui/gfx/image/image_util.cc @@ -17,6 +17,14 @@ Image* ImageFromPNGEncodedData(const unsigned char* input, size_t input_size) { return image; } +bool PNGEncodedDataFromImage(const Image& image, + std::vector<unsigned char>* dst) { + *dst = *image.ToImagePNG(); + return !dst->empty(); +} + +// The iOS implementations of the JPEG functions are in image_util_ios.mm. +#if !defined(OS_IOS) Image ImageFromJPEGEncodedData(const unsigned char* input, size_t input_size) { scoped_ptr<SkBitmap> bitmap(gfx::JPEGCodec::Decode(input, input_size)); if (bitmap.get()) @@ -25,12 +33,6 @@ Image ImageFromJPEGEncodedData(const unsigned char* input, size_t input_size) { return Image(); } -bool PNGEncodedDataFromImage(const Image& image, - std::vector<unsigned char>* dst) { - *dst = *image.ToImagePNG(); - return !dst->empty(); -} - bool JPEGEncodedDataFromImage(const Image& image, int quality, std::vector<unsigned char>* dst) { const SkBitmap& bitmap = *image.ToSkBitmap(); @@ -46,5 +48,6 @@ bool JPEGEncodedDataFromImage(const Image& image, int quality, static_cast<int>(bitmap.rowBytes()), quality, dst); } +#endif // !defined(OS_IOS) } diff --git a/ui/gfx/image/image_util.h b/ui/gfx/image/image_util.h index 06643172..6767062 100644 --- a/ui/gfx/image/image_util.h +++ b/ui/gfx/image/image_util.h @@ -21,17 +21,17 @@ namespace gfx { UI_EXPORT Image* ImageFromPNGEncodedData(const unsigned char* input, size_t input_size); +// Fills the |dst| vector with PNG-encoded bytes based on the given Image. +// Returns true if the Image was encoded successfully. +UI_EXPORT bool PNGEncodedDataFromImage(const Image& image, + std::vector<unsigned char>* dst); + // Creates an image from the given JPEG-encoded input. The caller owns the // returned Image. If there was an error creating the image, returns an // IsEmpty() Image. UI_EXPORT Image ImageFromJPEGEncodedData(const unsigned char* input, size_t input_size); -// Fills the |dst| vector with PNG-encoded bytes based on the given Image. -// Returns true if the Image was encoded successfully. -UI_EXPORT bool PNGEncodedDataFromImage(const Image& image, - std::vector<unsigned char>* dst); - // Fills the |dst| vector with JPEG-encoded bytes based on the given Image. // |quality| determines the compression level, 0 == lowest, 100 == highest. // Returns true if the Image was encoded successfully. diff --git a/ui/gfx/image/image_util_ios.mm b/ui/gfx/image/image_util_ios.mm new file mode 100644 index 0000000..d3a1cf7 --- /dev/null +++ b/ui/gfx/image/image_util_ios.mm @@ -0,0 +1,27 @@ +// 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 <UIKit/UIKit.h> + +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_util.h" + +#include "base/logging.h" + +namespace gfx { + +bool JPEGEncodedDataFromImage(const Image& image, + int quality, + std::vector<unsigned char>* dst) { + NSData* data = UIImageJPEGRepresentation(image.ToUIImage(), quality / 100.0); + + if ([data length] == 0) + return false; + + dst->resize([data length]); + [data getBytes:&dst->at(0) length:[data length]]; + return true; +} + +} // end namespace gfx @@ -41,6 +41,8 @@ # iOS uses a small subset of ui. common_sources are the only files that # are built on iOS. 'common_sources' : [ + 'base/layout.cc', + 'base/layout.h', 'base/models/tree_node_iterator.h', 'base/models/tree_node_model.h', 'base/ui_base_paths.cc', @@ -48,6 +50,24 @@ 'base/ui_base_switches.cc', 'base/ui_base_switches.h', 'base/ui_export.h', + 'gfx/image/image.cc', + 'gfx/image/image.h', + 'gfx/image/image_ios.mm', + 'gfx/image/image_mac.mm', + 'gfx/image/image_skia.cc', + 'gfx/image/image_skia.h', + 'gfx/image/image_skia_operations.cc', + 'gfx/image/image_skia_operations.h', + 'gfx/image/image_skia_rep.cc', + 'gfx/image/image_skia_rep.h', + 'gfx/image/image_skia_source.h', + 'gfx/image/image_skia_util_ios.h', + 'gfx/image/image_skia_util_ios.mm', + 'gfx/image/image_skia_util_mac.h', + 'gfx/image/image_skia_util_mac.mm', + 'gfx/image/image_util.cc', + 'gfx/image/image_util.h', + 'gfx/image/image_util_ios.mm', 'gfx/insets.cc', 'gfx/insets.h', 'gfx/point.cc', @@ -264,8 +284,6 @@ 'base/l10n/l10n_util_posix.cc', 'base/l10n/l10n_util_win.cc', 'base/l10n/l10n_util_win.h', - 'base/layout.cc', - 'base/layout.h', 'base/layout_mac.mm', 'base/models/button_menu_item_model.cc', 'base/models/button_menu_item_model.h', @@ -421,20 +439,6 @@ 'gfx/gfx_paths.h', 'gfx/image/canvas_image_source.cc', 'gfx/image/canvas_image_source.h', - 'gfx/image/image.cc', - 'gfx/image/image.h', - 'gfx/image/image_mac.mm', - 'gfx/image/image_skia.cc', - 'gfx/image/image_skia.h', - 'gfx/image/image_skia_operations.cc', - 'gfx/image/image_skia_operations.h', - 'gfx/image/image_skia_rep.cc', - 'gfx/image/image_skia_rep.h', - 'gfx/image/image_skia_source.h', - 'gfx/image/image_skia_util_mac.h', - 'gfx/image/image_skia_util_mac.mm', - 'gfx/image/image_util.cc', - 'gfx/image/image_util.h', 'gfx/interpolated_transform.h', 'gfx/interpolated_transform.cc', 'gfx/mac/nsimage_cache.h', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 17088c2..7297af5 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -58,6 +58,11 @@ # are built on iOS. 'common_sources' : [ 'base/models/tree_node_iterator_unittest.cc', + 'gfx/image/image_skia_unittest.cc', + 'gfx/image/image_unittest.cc', + 'gfx/image/image_unittest_util.cc', + 'gfx/image/image_unittest_util.h', + 'gfx/image/image_unittest_util_mac.mm', 'gfx/insets_unittest.cc', ], 'all_sources': [ @@ -105,11 +110,6 @@ 'gfx/font_list_unittest.cc', 'gfx/font_unittest.cc', 'gfx/image/image_mac_unittest.mm', - 'gfx/image/image_skia_unittest.cc', - 'gfx/image/image_unittest.cc', - 'gfx/image/image_unittest_util.cc', - 'gfx/image/image_unittest_util.h', - 'gfx/image/image_unittest_util_mac.mm', 'gfx/image/image_util_unittest.cc', 'gfx/rect_unittest.cc', 'gfx/render_text_unittest.cc', @@ -133,9 +133,12 @@ 'base/ime/ime_unittests.gypi', ], }, { # OS=="ios" - 'sources' : ['<@(_common_sources)'], - 'dependencies' : [ - '../testing/gtest.gyp:gtest_main', + 'sources' : [ + '<@(_common_sources)', + # TODO(rohitrao): Get ui/test/test_suite.cc and + # ui/test/run_all_unittests.cc compiling on iOS and remove this + # line. + '../base/test/run_all_unittests.cc', ], }], ['OS == "win"', { |