diff options
31 files changed, 756 insertions, 446 deletions
diff --git a/ash/wm/workspace/frame_maximize_button.cc b/ash/wm/workspace/frame_maximize_button.cc index 360f49c..863203f 100644 --- a/ash/wm/workspace/frame_maximize_button.cc +++ b/ash/wm/workspace/frame_maximize_button.cc @@ -179,7 +179,8 @@ ui::GestureStatus FrameMaximizeButton::OnGestureEvent( return ImageButton::OnGestureEvent(event); } -gfx::ImageSkia FrameMaximizeButton::GetImageToPaint(float scale) { +gfx::ImageSkia FrameMaximizeButton::GetImageToPaint( + ui::ScaleFactor scale_factor) { if (is_snap_enabled_) { int id = 0; if (frame_->GetWidget()->IsMaximized()) { @@ -224,7 +225,7 @@ gfx::ImageSkia FrameMaximizeButton::GetImageToPaint(float scale) { return *ResourceBundle::GetSharedInstance().GetImageNamed(id).ToImageSkia(); } // Hot and pressed states handled by regular ImageButton. - return ImageButton::GetImageToPaint(scale); + return ImageButton::GetImageToPaint(scale_factor); } void FrameMaximizeButton::ProcessStartEvent(const views::LocatedEvent& event) { diff --git a/ash/wm/workspace/frame_maximize_button.h b/ash/wm/workspace/frame_maximize_button.h index aa26249..9bca380 100644 --- a/ash/wm/workspace/frame_maximize_button.h +++ b/ash/wm/workspace/frame_maximize_button.h @@ -40,7 +40,8 @@ class ASH_EXPORT FrameMaximizeButton : public views::ImageButton { protected: // ImageButton overrides: - virtual gfx::ImageSkia GetImageToPaint(float scale) OVERRIDE; + virtual gfx::ImageSkia GetImageToPaint( + ui::ScaleFactor scale_factor) OVERRIDE; private: class EscapeEventFilter; diff --git a/chrome/browser/chromeos/status/network_menu_icon.cc b/chrome/browser/chromeos/status/network_menu_icon.cc index 2ac54d6..8624286 100644 --- a/chrome/browser/chromeos/status/network_menu_icon.cc +++ b/chrome/browser/chromeos/status/network_menu_icon.cc @@ -154,24 +154,27 @@ const gfx::ImageSkia GenerateFadedImage(gfx::ImageSkia source, gfx::ImageSkia empty_image, double alpha) { gfx::ImageSkia faded_image; - const std::vector<SkBitmap>& bitmaps = source.bitmaps(); - for (size_t i = 0; i < bitmaps.size(); ++i) { - SkBitmap bitmap = bitmaps[i]; - float bitmap_scale = source.GetScaleAtIndex(i); - float empty_bitmap_scale; - SkBitmap empty_bitmap = empty_image.GetBitmapForScale(bitmap_scale, - &empty_bitmap_scale); - if (empty_bitmap.isNull() || empty_bitmap_scale != bitmap_scale) { + std::vector<gfx::ImageSkiaRep> image_reps = source.image_reps(); + for (size_t i = 0; i < image_reps.size(); ++i) { + gfx::ImageSkiaRep image_rep = image_reps[i]; + ui::ScaleFactor scale_factor = image_rep.scale_factor(); + gfx::ImageSkiaRep empty_image_rep = + empty_image.GetRepresentation(scale_factor); + if (empty_image_rep.is_null() || + empty_image_rep.scale_factor() != scale_factor) { + SkBitmap empty_bitmap; empty_bitmap.setConfig(SkBitmap::kARGB_8888_Config, - bitmap.width(), - bitmap.height()); + image_rep.pixel_width(), + image_rep.pixel_height()); empty_bitmap.allocPixels(); empty_bitmap.eraseARGB(0, 0, 0, 0); - empty_image.AddBitmapForScale(empty_bitmap, bitmap_scale); + empty_image.AddRepresentation(gfx::ImageSkiaRep(empty_bitmap, + scale_factor)); } SkBitmap faded_bitmap = SkBitmapOperations::CreateBlendedBitmap( - empty_bitmap, bitmap, alpha); - faded_image.AddBitmapForScale(faded_bitmap, bitmap_scale); + empty_image_rep.sk_bitmap(), image_rep.sk_bitmap(), alpha); + faded_image.AddRepresentation(gfx::ImageSkiaRep(faded_bitmap, + scale_factor)); } return faded_image; } @@ -756,12 +759,11 @@ const gfx::ImageSkia NetworkMenuIcon::GenerateImageFromComponents( gfx::ImageSkia badged; int dip_width = icon.width(); int dip_height = icon.height(); - std::vector<SkBitmap> bitmaps = icon.bitmaps(); - for (std::vector<SkBitmap> ::const_iterator it = bitmaps.begin(); - it != bitmaps.end(); ++it) { - gfx::Canvas canvas(*it, false); - int px_width = it->width(); - float dip_scale = (float) px_width / (float) dip_width; + std::vector<gfx::ImageSkiaRep> image_reps = icon.image_reps(); + for (std::vector<gfx::ImageSkiaRep>::iterator it = image_reps.begin(); + it != image_reps.end(); ++it) { + float dip_scale = it->GetScale(); + gfx::Canvas canvas(it->sk_bitmap(), false); // TODO(kevers): This looks ugly, but gfx::Canvas::Scale is restricted to // integer scale factors. Consider adding a method to gfx::Canvas for // float scale factors. @@ -781,7 +783,8 @@ const gfx::ImageSkia NetworkMenuIcon::GenerateImageFromComponents( canvas.DrawImageInt(*bottom_right_badge, dip_width - bottom_right_badge->width(), dip_height - bottom_right_badge->height()); - badged.AddBitmapForScale(canvas.ExtractBitmap(), dip_scale); + badged.AddRepresentation(gfx::ImageSkiaRep(canvas.ExtractBitmap(), + it->scale_factor())); } return badged; } diff --git a/chrome/browser/chromeos/status/network_menu_icon_unittest.cc b/chrome/browser/chromeos/status/network_menu_icon_unittest.cc index 61d6182..88a76d2 100644 --- a/chrome/browser/chromeos/status/network_menu_icon_unittest.cc +++ b/chrome/browser/chromeos/status/network_menu_icon_unittest.cc @@ -18,11 +18,18 @@ namespace { bool CompareTwoImages(const gfx::ImageSkia& image_a, const gfx::ImageSkia& image_b, int log_level) { - float actual_scale_factor; - SkBitmap a = image_a.GetBitmapForScale(1.0f, 1.0f, &actual_scale_factor); - DCHECK_EQ(1.0f, actual_scale_factor); - SkBitmap b = image_b.GetBitmapForScale(1.0f, 1.0f, &actual_scale_factor); - DCHECK_EQ(1.0f, actual_scale_factor); + CHECK(!image_a.isNull()); + CHECK(!image_b.isNull()); + + gfx::ImageSkiaRep image_rep_a = + image_a.GetRepresentation(ui::SCALE_FACTOR_100P); + CHECK_EQ(ui::SCALE_FACTOR_100P, image_rep_a.scale_factor()); + gfx::ImageSkiaRep image_rep_b = + image_b.GetRepresentation(ui::SCALE_FACTOR_100P); + CHECK_EQ(ui::SCALE_FACTOR_100P, image_rep_b.scale_factor()); + + SkBitmap a = image_rep_a.sk_bitmap(); + SkBitmap b = image_rep_b.sk_bitmap(); CHECK(!a.empty()); CHECK(!b.empty()); diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc index 65d47ad..94379b7 100644 --- a/chrome/browser/extensions/image_loading_tracker.cc +++ b/chrome/browser/extensions/image_loading_tracker.cc @@ -19,6 +19,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_rep.h" #include "webkit/glue/image_decoder.h" using content::BrowserThread; @@ -308,8 +309,9 @@ void ImageLoadingTracker::OnImageLoaded( gfx::ImageSkia image_skia; for (std::vector<SkBitmap>::const_iterator it = info->bitmaps.begin(); it != info->bitmaps.end(); ++it) { - // TODO(pkotwicz): Do something better but ONLY when ENABLE_DIP. - image_skia.AddBitmapForScale(*it, 1.0f); + // TODO(pkotwicz): Do something better but ONLY when DIP is enabled. + image_skia.AddRepresentation( + gfx::ImageSkiaRep(*it, ui::SCALE_FACTOR_100P)); } image = gfx::Image(image_skia); } diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc index 82bcd15..54d1958 100644 --- a/chrome/browser/extensions/image_loading_tracker_unittest.cc +++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc @@ -219,15 +219,18 @@ TEST_F(ImageLoadingTrackerTest, MultipleImages) { EXPECT_EQ(1, image_loaded_count()); // Check that all images were loaded. - const std::vector<SkBitmap> bitmaps = image_.ToImageSkia()->bitmaps(); - ASSERT_EQ(2u, bitmaps.size()); - const SkBitmap* bmp1 = &bitmaps[0]; - const SkBitmap* bmp2 = &bitmaps[1]; - if (bmp1->width() > bmp2->width()) { - std::swap(bmp1, bmp2); + std::vector<gfx::ImageSkiaRep> image_reps = + image_.ToImageSkia()->image_reps(); + ASSERT_EQ(2u, image_reps.size()); + const gfx::ImageSkiaRep* img_rep1 = &image_reps[0]; + const gfx::ImageSkiaRep* img_rep2 = &image_reps[1]; + if (img_rep1->pixel_width() > img_rep2->pixel_width()) { + std::swap(img_rep1, img_rep2); } - EXPECT_EQ(ExtensionIconSet::EXTENSION_ICON_BITTY, bmp1->width()); - EXPECT_EQ(ExtensionIconSet::EXTENSION_ICON_SMALLISH, bmp2->width()); + EXPECT_EQ(ExtensionIconSet::EXTENSION_ICON_BITTY, + img_rep1->pixel_width()); + EXPECT_EQ(ExtensionIconSet::EXTENSION_ICON_SMALLISH, + img_rep2->pixel_width()); } // Tests IsComponentExtensionResource function. diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc index de09a41..2d62595 100644 --- a/chrome/browser/themes/browser_theme_pack.cc +++ b/chrome/browser/themes/browser_theme_pack.cc @@ -24,6 +24,7 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "ui/base/resource/data_pack.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" @@ -314,15 +315,14 @@ base::RefCountedMemory* ReadFileData(const FilePath& path) { gfx::Image* CreateHSLShiftedImage(const gfx::Image& image, const color_utils::HSL& hsl_shift) { const gfx::ImageSkia* src_image = image.ToImageSkia(); - const std::vector<SkBitmap> src_bitmaps = src_image->bitmaps(); + std::vector<gfx::ImageSkiaRep> src_image_reps = src_image->image_reps(); gfx::ImageSkia dst_image; - for (size_t i = 0; i < src_bitmaps.size(); ++i) { - const SkBitmap& bitmap = src_bitmaps[i]; - float scale_factor = - static_cast<float>(bitmap.width()) / src_image->width(); - dst_image.AddBitmapForScale( - SkBitmapOperations::CreateHSLShiftedBitmap(bitmap, hsl_shift), - scale_factor); + for (size_t i = 0; i < src_image_reps.size(); ++i) { + const gfx::ImageSkiaRep& image_rep = src_image_reps[i]; + SkBitmap dst_bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( + image_rep.sk_bitmap(), hsl_shift); + dst_image.AddRepresentation(gfx::ImageSkiaRep(dst_bitmap, + image_rep.scale_factor())); } return new gfx::Image(dst_image); } @@ -998,28 +998,37 @@ void BrowserThemePack::GenerateTabBackgroundImages(ImageCache* bitmaps) const { ImageCache::const_iterator it = bitmaps->find(prs_base_id); if (it != bitmaps->end()) { const gfx::ImageSkia* image_to_tint = (it->second)->ToImageSkia(); - const std::vector<SkBitmap> bitmaps_to_tint = image_to_tint->bitmaps(); + const std::vector<gfx::ImageSkiaRep> image_reps_to_tint = + image_to_tint->image_reps(); gfx::ImageSkia tinted_image; - for (size_t j = 0; j < bitmaps_to_tint.size(); ++j) { + for (size_t j = 0; j < image_reps_to_tint.size(); ++j) { + gfx::ImageSkiaRep image_rep_to_tint = image_reps_to_tint[j]; SkBitmap bg_tint = SkBitmapOperations::CreateHSLShiftedBitmap( - bitmaps_to_tint[j], GetTintInternal( + image_rep_to_tint.sk_bitmap(), GetTintInternal( ThemeService::TINT_BACKGROUND_TAB)); + gfx::Size bg_tint_dip_size(image_rep_to_tint.GetWidth(), + image_rep_to_tint.GetHeight()); int vertical_offset = bitmaps->count(prs_id) ? kRestoredTabVerticalOffset : 0; - SkBitmap bg_tab = SkBitmapOperations::CreateTiledBitmap( - bg_tint, 0, vertical_offset, bg_tint.width(), bg_tint.height()); + gfx::Canvas canvas(gfx::Size(bg_tint.width(), bg_tint.height()), + false); + SkScalar image_rep_to_tint_scale = + SkFloatToScalar(image_rep_to_tint.GetScale()); + canvas.sk_canvas()->scale(image_rep_to_tint_scale, + image_rep_to_tint_scale); + canvas.TileImageInt(bg_tint, 0, vertical_offset, + bg_tint_dip_size.width(), bg_tint_dip_size.height()); // If they've provided a custom image, overlay it. ImageCache::const_iterator overlay_it = bitmaps->find(prs_id); if (overlay_it != bitmaps->end()) { - const SkBitmap* overlay = overlay_it->second->ToSkBitmap(); - SkCanvas canvas(bg_tab); - for (int x = 0; x < bg_tab.width(); x += overlay->width()) - canvas.drawBitmap(*overlay, static_cast<SkScalar>(x), 0, NULL); + const gfx::ImageSkia* overlay = overlay_it->second->ToImageSkia(); + canvas.TileImageInt(*overlay, 0, 0, bg_tint_dip_size.width(), + overlay->height()); } - float scale_factor = - static_cast<float>(bg_tab.width()) / image_to_tint->width(); - tinted_image.AddBitmapForScale(bg_tab, scale_factor); + SkBitmap bg_tab = canvas.ExtractBitmap(); + tinted_image.AddRepresentation(gfx::ImageSkiaRep(bg_tab, + image_rep_to_tint.scale_factor())); } temp_output[prs_id] = new gfx::Image(tinted_image); diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc index 6a4d5eb..58cc41b 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc @@ -14,6 +14,7 @@ #include "content/public/browser/web_ui.h" #include "ui/base/models/menu_model.h" #include "ui/gfx/font.h" +#include "ui/gfx/image/image_skia.h" namespace chromeos { @@ -76,9 +77,8 @@ base::ListValue* NetworkMenuWebUI::ConvertMenuModel(ui::MenuModel* model) { item->SetString("label", model->GetLabelAt(i)); gfx::ImageSkia icon; if (model->GetIconAt(i, &icon)) { - float icon_scale; - SkBitmap icon_bitmap = icon.GetBitmapForScale( - web_ui_->GetDeviceScale(), &icon_scale); + gfx::ImageSkiaRep icon_bitmap = icon.GetRepresentation( + ui::GetScaleFactorFromScale(web_ui_->GetDeviceScale())).sk_bitmap(); item->SetString("icon", web_ui_util::GetImageDataUrl(icon_bitmap)); } if (id >= 0) { @@ -149,9 +149,8 @@ void NetworkDropdown::NetworkMenuIconChanged() { void NetworkDropdown::SetNetworkIconAndText() { string16 text; const gfx::ImageSkia icon_image = network_icon_->GetIconAndText(&text); - float icon_scale; - SkBitmap icon_bitmap = icon_image.GetBitmapForScale( - web_ui_->GetDeviceScale(), &icon_scale); + gfx::ImageSkiaRep icon_bitmap = icon_image.GetRepresentation( + ui::GetScaleFactorFromScale(web_ui_->GetDeviceScale())).sk_bitmap(); std::string icon_str = icon_image.empty() ? std::string() : web_ui_util::GetImageDataUrl(icon_bitmap); diff --git a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc index 449e147..1951174 100644 --- a/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc +++ b/chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc @@ -54,6 +54,7 @@ #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "grit/theme_resources.h" +#include "ui/base/layout.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/display.h" @@ -85,31 +86,29 @@ const char kNetworkInfoKeyPolicyManaged[] = "policyManaged"; class NetworkInfoDictionary { public: // Initializes the dictionary with default values. - explicit NetworkInfoDictionary(float bitmapScale); + explicit NetworkInfoDictionary(float icon_scale); // Copies in service path, connect{ing|ed|able} flags and connection type from // the provided network object. Also chooses an appropriate icon based on the // network type. NetworkInfoDictionary(const chromeos::Network* network, - float bitmapScape); + float icon_scale); // Initializes a remembered network entry, pulling information from the passed // network object and the corresponding remembered network object. |network| // may be NULL. NetworkInfoDictionary(const chromeos::Network* network, const chromeos::Network* remembered, - float bitmapScale); + float icon_scale); // Setters for filling in information. void set_service_path(const std::string& service_path) { service_path_ = service_path; } void set_icon(const gfx::ImageSkia& icon) { - float actualScale; - SkBitmap bitmap = icon.GetBitmapForScale(bitmap_scale_factor_, - bitmap_scale_factor_, - &actualScale); - icon_url_ = icon.isNull() ? "" : web_ui_util::GetImageDataUrl(bitmap); + gfx::ImageSkiaRep image_rep = icon.GetRepresentation(icon_scale_factor_); + icon_url_ = icon.isNull() ? "" : web_ui_util::GetImageDataUrl( + image_rep.sk_bitmap()); } void set_name(const std::string& name) { name_ = name; @@ -160,13 +159,14 @@ class NetworkInfoDictionary { chromeos::ActivationState activation_state_; bool needs_new_plan_; bool policy_managed_; - float bitmap_scale_factor_; + ui::ScaleFactor icon_scale_factor_; DISALLOW_COPY_AND_ASSIGN(NetworkInfoDictionary); }; -NetworkInfoDictionary::NetworkInfoDictionary(float bitmapScale) - : bitmap_scale_factor_(bitmapScale) { +NetworkInfoDictionary::NetworkInfoDictionary( + float icon_scale) + : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) { set_connecting(false); set_connected(false); set_connectable(false); @@ -178,8 +178,8 @@ NetworkInfoDictionary::NetworkInfoDictionary(float bitmapScale) } NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network, - float bitmapScale) - : bitmap_scale_factor_(bitmapScale) { + float icon_scale) + : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) { set_service_path(network->service_path()); set_icon(chromeos::NetworkMenuIcon::GetImage(network, chromeos::NetworkMenuIcon::COLOR_DARK)); @@ -197,8 +197,8 @@ NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network, NetworkInfoDictionary::NetworkInfoDictionary( const chromeos::Network* network, const chromeos::Network* remembered, - float bitmapScale) - : bitmap_scale_factor_(bitmapScale) { + float icon_scale) + : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) { set_service_path(remembered->service_path()); set_icon(chromeos::NetworkMenuIcon::GetImage( network ? network : remembered, chromeos::NetworkMenuIcon::COLOR_DARK)); diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm index 46ce5f5..de64f35 100644 --- a/chrome/browser/web_applications/web_app_mac.mm +++ b/chrome/browser/web_applications/web_app_mac.mm @@ -198,9 +198,11 @@ bool WebAppShortcutCreator::UpdateIcon(const FilePath& app_path) const { scoped_nsobject<IconFamily> icon_family([[IconFamily alloc] init]); bool image_added = false; - const std::vector<SkBitmap> bitmaps = info_.favicon.ToImageSkia()->bitmaps(); - for (size_t i = 0; i < bitmaps.size(); ++i) { - NSBitmapImageRep* image_rep = SkBitmapToImageRep(bitmaps[i]); + std::vector<gfx::ImageSkiaRep> image_reps = + info_.favicon.ToImageSkia()->image_reps(); + for (size_t i = 0; i < image_reps.size(); ++i) { + NSBitmapImageRep* image_rep = SkBitmapToImageRep( + image_reps[i].sk_bitmap()); if (!image_rep) continue; diff --git a/content/browser/renderer_host/backing_store_aura.cc b/content/browser/renderer_host/backing_store_aura.cc index 780c017..c995ea1 100644 --- a/content/browser/renderer_host/backing_store_aura.cc +++ b/content/browser/renderer_host/backing_store_aura.cc @@ -36,8 +36,9 @@ BackingStoreAura::~BackingStoreAura() { void BackingStoreAura::SkiaShowRect(const gfx::Point& point, gfx::Canvas* canvas) { - canvas->DrawImageInt(gfx::ImageSkia(bitmap_, device_scale_factor_), - point.x(), point.y()); + gfx::ImageSkia image = gfx::ImageSkia(gfx::ImageSkiaRep(bitmap_, + ui::GetScaleFactorFromScale(device_scale_factor_))); + canvas->DrawImageInt(image, point.x(), point.y()); } void BackingStoreAura::ScaleFactorChanged(float device_scale_factor) { diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc index 1f0babe..47e4e18 100644 --- a/ui/aura/root_window_host_linux.cc +++ b/ui/aura/root_window_host_linux.cc @@ -17,7 +17,6 @@ #include "base/stl_util.h" #include "base/stringprintf.h" #include "grit/ui_resources_standard.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/aura/client/capture_client.h" #include "ui/aura/client/user_action_client.h" #include "ui/aura/dispatcher_linux.h" @@ -400,18 +399,12 @@ class RootWindowHostLinux::ImageCursors { void LoadImageCursor(int id, int resource_id, int hot_x, int hot_y) { const gfx::ImageSkia* image = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); - float actual_scale = 0; - const SkBitmap& bitmap = image->GetBitmapForScale(scale_factor_, - scale_factor_, - &actual_scale); - // We never use scaled cursor, but the following DCHECK fails - // because the method above computes the actual scale from the image - // size instead of obtaining from the resource data, and the some - // of cursors are indeed not 2x size of the 2x images. - // TODO(oshima): Fix this and enable the following DCHECK. - // DCHECK_EQ(actual_scale, scale_factor_); - XcursorImage* x_image = ui::SkBitmapToXcursorImage( - &bitmap, gfx::Point(hot_x * actual_scale, hot_y * actual_scale)); + const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( + ui::GetScaleFactorFromScale(scale_factor_)); + DCHECK_EQ(scale_factor_, image_rep.GetScale()); + gfx::Point hot(hot_x * scale_factor_, hot_y * scale_factor_); + XcursorImage* x_image = + ui::SkBitmapToXcursorImage(&image_rep.sk_bitmap(), hot); cursors_[id] = ui::CreateReffedCustomXCursor(x_image); // |bitmap| is owned by the resource bundle. So we do not need to free it. } @@ -422,10 +415,10 @@ class RootWindowHostLinux::ImageCursors { void LoadAnimatedCursor(int id, int resource_id, int hot_x, int hot_y) { const gfx::ImageSkia* image = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); - float actual_scale = 0; - const SkBitmap& bitmap = image->GetBitmapForScale(scale_factor_, - scale_factor_, - &actual_scale); + const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( + ui::GetScaleFactorFromScale(scale_factor_)); + DCHECK_EQ(scale_factor_, image_rep.GetScale()); + const SkBitmap bitmap = image_rep.sk_bitmap(); DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config); int frame_width = bitmap.height(); int frame_height = frame_width; @@ -446,8 +439,8 @@ class RootWindowHostLinux::ImageCursors { pixels + i * frame_width + j * total_width, frame_width * 4); } - x_image->xhot = hot_x * actual_scale; - x_image->yhot = hot_y * actual_scale; + x_image->xhot = hot_x * scale_factor_; + x_image->yhot = hot_y * scale_factor_; x_image->delay = kAnimatedCursorFrameDelayMs; x_images->images[i] = x_image; } diff --git a/ui/base/layout.cc b/ui/base/layout.cc index 451e9ac..ac4ee55 100644 --- a/ui/base/layout.cc +++ b/ui/base/layout.cc @@ -4,6 +4,9 @@ #include "ui/base/layout.h" +#include <cmath> +#include <limits> + #include "base/basictypes.h" #include "base/command_line.h" #include "base/logging.h" @@ -68,8 +71,21 @@ bool UseTouchOptimizedUI() { } const float kScaleFactorScales[] = {1.0, 2.0}; - +const size_t kScaleFactorScalesLength = arraysize(kScaleFactorScales); + +#if defined(OS_MACOSX) +std::vector<ui::ScaleFactor>& GetSupportedScaleFactorsInternal() { + static std::vector<ui::ScaleFactor>* supported_scale_factors = + new std::vector<ui::ScaleFactor>(); + if (supported_scale_factors->empty()) { + supported_scale_factors->push_back(ui::SCALE_FACTOR_100P); + supported_scale_factors->push_back(ui::SCALE_FACTOR_200P); + } + return *supported_scale_factors; } +#endif // OS_MACOSX + +} // namespace namespace ui { @@ -90,8 +106,42 @@ DisplayLayout GetDisplayLayout() { #endif } +ScaleFactor GetScaleFactorFromScale(float scale) { + size_t closest_match = 0; + float smallest_diff = std::numeric_limits<float>::max(); + for (size_t i = 0; i < kScaleFactorScalesLength; ++i) { + float diff = std::abs(kScaleFactorScales[i] - scale); + if (diff < smallest_diff) { + closest_match = i; + smallest_diff = diff; + } + } + return static_cast<ui::ScaleFactor>(closest_match); +} + float GetScaleFactorScale(ScaleFactor scale_factor) { return kScaleFactorScales[scale_factor]; } +#if defined(OS_MACOSX) +std::vector<ScaleFactor> GetSupportedScaleFactors() { + return GetSupportedScaleFactorsInternal(); +} + +namespace test { + +void SetSupportedScaleFactors( + const std::vector<ui::ScaleFactor>& scale_factors) { + std::vector<ui::ScaleFactor>& supported_scale_factors = + GetSupportedScaleFactorsInternal(); + supported_scale_factors.clear(); + + for (size_t i = 0; i < scale_factors.size(); ++i) + supported_scale_factors.push_back(scale_factors[i]); +} + +} // namespace test + +#endif // OS_MACOSX + } // namespace ui diff --git a/ui/base/layout.h b/ui/base/layout.h index e7cf919..71f8003 100644 --- a/ui/base/layout.h +++ b/ui/base/layout.h @@ -6,6 +6,8 @@ #define UI_BASE_LAYOUT_H_ #pragma once +#include <vector> + #include "ui/base/ui_export.h" namespace ui { @@ -42,6 +44,27 @@ enum ScaleFactor { // Returns the float scale value for |scale_factor|. UI_EXPORT float GetScaleFactorScale(ScaleFactor scale_factor); +// Returns the ScaleFactor which most closely matches |scale|. +// Converting from float to ScaleFactor is inefficient and should be done as +// little as possible. +UI_EXPORT ScaleFactor GetScaleFactorFromScale(float scale); + +#if defined(OS_MACOSX) + +// Returns a vector with the scale factors which are supported by this +// platform. +// Only required on Mac so far. +UI_EXPORT std::vector<ScaleFactor> GetSupportedScaleFactors(); + +namespace test { + +UI_EXPORT void SetSupportedScaleFactors( + const std::vector<ScaleFactor>& scale_factors); + +} // namespace test + +#endif + } // namespace ui #endif // UI_BASE_LAYOUT_H_ diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index c9326c3..5b190ec 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc @@ -45,6 +45,20 @@ const int kMediumFontSizeDelta = 3; const int kLargeFontSizeDelta = 8; #endif +// Returns the actual scale factor of |bitmap| given the image representations +// which have already been added to |image|. +// TODO(pkotwicz): Remove this once we are no longer loading 1x resources +// as part of 2x data packs. +ui::ScaleFactor GetActualScaleFactor(const gfx::ImageSkia& image, + const SkBitmap& bitmap, + ui::ScaleFactor data_pack_scale_factor) { + if (image.empty()) + return data_pack_scale_factor; + + return ui::GetScaleFactorFromScale( + static_cast<float>(bitmap.width()) / image.width()); +} + // If 2x resource is missing from |image| or is the incorrect size, // logs the resource id and creates a 2x version of the resource. // Blends the created resource with red to make it distinguishable from @@ -54,16 +68,15 @@ void Create2xResourceIfMissing(gfx::ImageSkia image, int idr) { if (command_line->HasSwitch( switches::kHighlightMissing2xResources) && command_line->HasSwitch(switches::kLoad2xResources) && - !image.HasBitmapForScale(2.0f)) { - float bitmap_scale; - SkBitmap bitmap = image.GetBitmapForScale(2.0f, &bitmap_scale); + !image.HasRepresentation(ui::SCALE_FACTOR_200P)) { + gfx::ImageSkiaRep image_rep = image.GetRepresentation(SCALE_FACTOR_200P); - if (bitmap_scale == 1.0f) + if (image_rep.scale_factor() == ui::SCALE_FACTOR_100P) LOG(INFO) << "Missing 2x resource with id " << idr; else LOG(INFO) << "Incorrectly sized 2x resource with id " << idr; - SkBitmap bitmap2x = skia::ImageOperations::Resize(bitmap, + SkBitmap bitmap2x = skia::ImageOperations::Resize(image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, image.width() * 2, image.height() * 2); @@ -75,7 +88,7 @@ void Create2xResourceIfMissing(gfx::ImageSkia image, int idr) { mask.eraseColor(SK_ColorRED); SkBitmap result = SkBitmapOperations::CreateBlendedBitmap(bitmap2x, mask, 0.2); - image.AddBitmapForScale(result, 2.0f); + image.AddRepresentation(gfx::ImageSkiaRep(result, SCALE_FACTOR_200P)); } } @@ -283,11 +296,14 @@ gfx::Image& ResourceBundle::GetImageNamed(int resource_id) { for (size_t i = 0; i < data_packs_.size(); ++i) { scoped_ptr<SkBitmap> bitmap(LoadBitmap(*data_packs_[i], resource_id)); if (bitmap.get()) { - if (gfx::Screen::IsDIPEnabled()) - image_skia.AddBitmapForScale(*bitmap, - ui::GetScaleFactorScale(data_packs_[i]->GetScaleFactor())); - else - image_skia.AddBitmapForScale(*bitmap, 1.0f); + ui::ScaleFactor scale_factor; + if (gfx::Screen::IsDIPEnabled()) { + scale_factor = GetActualScaleFactor(image_skia, *bitmap, + data_packs_[i]->GetScaleFactor()); + } else { + scale_factor = ui::SCALE_FACTOR_100P; + } + image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale_factor)); } } diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index 5dbb00e..a7bc247 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc @@ -474,8 +474,12 @@ const SkBitmap& Canvas::GetBitmapToPaint(const gfx::ImageSkia& image, float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * user_additional_scale_y; - const SkBitmap& bitmap = image.GetBitmapForScale(scale_x, scale_y, - bitmap_scale_factor); + ui::ScaleFactor request_scale_factor = + ui::GetScaleFactorFromScale((scale_x + scale_y) / 2); + const gfx::ImageSkiaRep& image_rep = + image.GetRepresentation(request_scale_factor); + const SkBitmap& bitmap = image_rep.sk_bitmap(); + *bitmap_scale_factor = image_rep.GetScale(); if (!bitmap.isNull() && (scale_x < *bitmap_scale_factor || scale_y < *bitmap_scale_factor)) const_cast<SkBitmap&>(bitmap).buildMipMap(); diff --git a/ui/gfx/image/image.cc b/ui/gfx/image/image.cc index d194147a..0b93fb9 100644 --- a/ui/gfx/image/image.cc +++ b/ui/gfx/image/image.cc @@ -226,6 +226,13 @@ Image::Image(const ImageSkia& image) AddRepresentation(rep); } +Image::Image(const ImageSkiaRep& image_skia_rep) + : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { + internal::ImageRepSkia* rep = + new internal::ImageRepSkia(new ImageSkia(image_skia_rep)); + AddRepresentation(rep); +} + Image::Image(const SkBitmap& bitmap) : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { internal::ImageRepSkia* rep = diff --git a/ui/gfx/image/image.h b/ui/gfx/image/image.h index da4b392..39ce4b7 100644 --- a/ui/gfx/image/image.h +++ b/ui/gfx/image/image.h @@ -38,6 +38,7 @@ class ImageMacTest; namespace gfx { class ImageSkia; +class ImageSkiaRep; #if defined(TOOLKIT_GTK) class CairoCachedSurface; @@ -66,8 +67,13 @@ class UI_EXPORT Image { // representation. explicit Image(const ImageSkia& image); + // Creates a new image by copying the image rep for use as the default + // representation. + explicit Image(const ImageSkiaRep& image_rep); + // Creates a new image by copying the bitmap for use as the default // representation. + // TODO(pkotwicz): Get rid of this constructor. explicit Image(const SkBitmap& bitmap); #if defined(TOOLKIT_GTK) diff --git a/ui/gfx/image/image_mac_unittest.mm b/ui/gfx/image/image_mac_unittest.mm index e49217f..36ffaeb 100644 --- a/ui/gfx/image/image_mac_unittest.mm +++ b/ui/gfx/image/image_mac_unittest.mm @@ -7,7 +7,6 @@ #include "base/logging.h" #include "base/memory/scoped_nsobject.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_unittest_util.h" @@ -16,6 +15,16 @@ namespace { class ImageMacTest : public testing::Test { public: + ImageMacTest() { + } + + ~ImageMacTest() { + } + + virtual void SetUp() OVERRIDE { + gfx::test::SetSupportedScaleFactorsTo1xAnd2x(); + } + void BitmapImageRep(int width, int height, NSBitmapImageRep** image_rep) { *image_rep = [[[NSBitmapImageRep alloc] @@ -32,72 +41,103 @@ class ImageMacTest : public testing::Test { bitsPerPixel:0] autorelease]; } + private: + DISALLOW_COPY_AND_ASSIGN(ImageMacTest); }; namespace gt = gfx::test; -TEST_F(ImageMacTest, NSImageWithResizedNSImageRepToImageSkia) { +TEST_F(ImageMacTest, MultiResolutionNSImageToImageSkia) { const int kWidth1x = 10; const int kHeight1x = 12; const int kWidth2x = 20; const int kHeight2x = 24; - NSBitmapImageRep* image_rep; - BitmapImageRep(kWidth2x, kHeight2x, &image_rep); - + NSBitmapImageRep* ns_image_rep1; + BitmapImageRep(kWidth1x, kHeight1x, &ns_image_rep1); + NSBitmapImageRep* ns_image_rep2; + BitmapImageRep(kWidth2x, kHeight2x, &ns_image_rep2); scoped_nsobject<NSImage> ns_image( [[NSImage alloc] initWithSize:NSMakeSize(kWidth1x, kHeight1x)]); - [ns_image addRepresentation:image_rep]; - - [image_rep setSize:NSMakeSize(kWidth1x, kHeight1x)]; + [ns_image addRepresentation:ns_image_rep1]; + [ns_image addRepresentation:ns_image_rep2]; gfx::Image image(ns_image.release()); + + EXPECT_EQ(1u, image.RepresentationCount()); + const gfx::ImageSkia* image_skia = image.ToImageSkia(); + EXPECT_EQ(2u, image_skia->image_reps().size()); + + EXPECT_EQ(kWidth1x, image_skia->width()); + EXPECT_EQ(kHeight1x, image_skia->height()); + + const gfx::ImageSkiaRep& image_rep1x = + image_skia->GetRepresentation(ui::SCALE_FACTOR_100P); + EXPECT_TRUE(!image_rep1x.is_null()); + EXPECT_EQ(kWidth1x, image_rep1x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep1x.GetHeight()); + EXPECT_EQ(kWidth1x, image_rep1x.pixel_width()); + EXPECT_EQ(kHeight1x, image_rep1x.pixel_height()); + EXPECT_EQ(ui::SCALE_FACTOR_100P, image_rep1x.scale_factor()); + + const gfx::ImageSkiaRep& image_rep2x = + image_skia->GetRepresentation(ui::SCALE_FACTOR_200P); + EXPECT_TRUE(!image_rep2x.is_null()); + EXPECT_EQ(kWidth1x, image_rep2x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep2x.GetHeight()); + EXPECT_EQ(kWidth2x, image_rep2x.pixel_width()); + EXPECT_EQ(kHeight2x, image_rep2x.pixel_height()); + EXPECT_EQ(ui::SCALE_FACTOR_200P, image_rep2x.scale_factor()); - float scale_factor; - const SkBitmap& bitmap = image_skia->GetBitmapForScale(2.0f, 2.0f, - &scale_factor); - EXPECT_EQ(2.0f, scale_factor); - EXPECT_EQ(kWidth2x, bitmap.width()); - EXPECT_EQ(kHeight2x, bitmap.height()); + // ToImageSkia should create a second representation. + EXPECT_EQ(2u, image.RepresentationCount()); } -TEST_F(ImageMacTest, MultiResolutionNSImageToImageSkia) { +// Test that convertng to an ImageSkia from an NSImage with scale factors +// other than 1x and 2x results in an ImageSkia with scale factors 1x and +// 2x; +TEST_F(ImageMacTest, UnalignedMultiResolutionNSImageToImageSkia) { const int kWidth1x = 10; - const int kHeight1x = 12; + const int kHeight1x= 12; const int kWidth2x = 20; const int kHeight2x = 24; + const int kWidth4x = 40; + const int kHeight4x = 48; - NSBitmapImageRep* image_rep_1; - BitmapImageRep(kWidth1x, kHeight1x, &image_rep_1); - NSBitmapImageRep* image_rep_2; - BitmapImageRep(kWidth2x, kHeight2x, &image_rep_2); + NSBitmapImageRep* ns_image_rep4; + BitmapImageRep(kWidth4x, kHeight4x, &ns_image_rep4); scoped_nsobject<NSImage> ns_image( [[NSImage alloc] initWithSize:NSMakeSize(kWidth1x, kHeight1x)]); - [ns_image addRepresentation:image_rep_1]; - [ns_image addRepresentation:image_rep_2]; + [ns_image addRepresentation:ns_image_rep4]; gfx::Image image(ns_image.release()); EXPECT_EQ(1u, image.RepresentationCount()); const gfx::ImageSkia* image_skia = image.ToImageSkia(); - EXPECT_EQ(2u, image_skia->bitmaps().size()); - - float scale_factor; - const SkBitmap& bitmap1x = image_skia->GetBitmapForScale(1.0f, 1.0f, - &scale_factor); - EXPECT_TRUE(!bitmap1x.isNull()); - EXPECT_EQ(1.0f, scale_factor); - EXPECT_EQ(kWidth1x, bitmap1x.width()); - EXPECT_EQ(kHeight1x, bitmap1x.height()); - - const SkBitmap& bitmap2x = image_skia->GetBitmapForScale(2.0f, 2.0f, - &scale_factor); - EXPECT_TRUE(!bitmap2x.isNull()); - EXPECT_EQ(2.0f, scale_factor); - EXPECT_EQ(kWidth2x, bitmap2x.width()); - EXPECT_EQ(kHeight2x, bitmap2x.height()); + EXPECT_EQ(2u, image_skia->image_reps().size()); + + EXPECT_EQ(kWidth1x, image_skia->width()); + EXPECT_EQ(kHeight1x, image_skia->height()); + + const gfx::ImageSkiaRep& image_rep1x = + image_skia->GetRepresentation(ui::SCALE_FACTOR_100P); + EXPECT_TRUE(!image_rep1x.is_null()); + EXPECT_EQ(kWidth1x, image_rep1x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep1x.GetHeight()); + EXPECT_EQ(kWidth1x, image_rep1x.pixel_width()); + EXPECT_EQ(kHeight1x, image_rep1x.pixel_height()); + EXPECT_EQ(ui::SCALE_FACTOR_100P, image_rep1x.scale_factor()); + + const gfx::ImageSkiaRep& image_rep2x = + image_skia->GetRepresentation(ui::SCALE_FACTOR_200P); + EXPECT_TRUE(!image_rep2x.is_null()); + EXPECT_EQ(kWidth1x, image_rep2x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep2x.GetHeight()); + EXPECT_EQ(kWidth2x, image_rep2x.pixel_width()); + EXPECT_EQ(kHeight2x, image_rep2x.pixel_height()); + EXPECT_EQ(ui::SCALE_FACTOR_200P, image_rep2x.scale_factor()); // ToImageSkia should create a second representation. EXPECT_EQ(2u, image.RepresentationCount()); @@ -110,13 +150,15 @@ TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { const int kHeight2x = 24; gfx::ImageSkia image_skia; - image_skia.AddBitmapForScale(gt::CreateBitmap(kWidth1x, kHeight1x), 1.0f); - image_skia.AddBitmapForScale(gt::CreateBitmap(kWidth2x, kHeight2x), 2.0f); + image_skia.AddRepresentation(gfx::ImageSkiaRep( + gt::CreateBitmap(kWidth1x, kHeight1x), ui::SCALE_FACTOR_100P)); + image_skia.AddRepresentation(gfx::ImageSkiaRep( + gt::CreateBitmap(kWidth2x, kHeight2x), ui::SCALE_FACTOR_200P)); gfx::Image image(image_skia); EXPECT_EQ(1u, image.RepresentationCount()); - EXPECT_EQ(2u, image.ToImageSkia()->bitmaps().size()); + EXPECT_EQ(2u, image.ToImageSkia()->image_reps().size()); NSImage* ns_image = image; EXPECT_TRUE(ns_image); @@ -126,19 +168,19 @@ TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { EXPECT_EQ([ns_image size].height, kHeight1x); EXPECT_EQ(2u, [[image representations] count]); - NSImageRep* image_rep_1 = [[image representations] objectAtIndex:0]; - NSImageRep* image_rep_2 = [[image representations] objectAtIndex:1]; - - if ([image_rep_1 size].width == kWidth1x) { - EXPECT_EQ([image_rep_1 size].width, kWidth1x); - EXPECT_EQ([image_rep_1 size].height, kHeight1x); - EXPECT_EQ([image_rep_2 size].width, kWidth2x); - EXPECT_EQ([image_rep_2 size].height, kHeight2x); + NSImageRep* ns_image_rep1 = [[image representations] objectAtIndex:0]; + NSImageRep* ns_image_rep2 = [[image representations] objectAtIndex:1]; + + if ([ns_image_rep1 size].width == kWidth1x) { + EXPECT_EQ([ns_image_rep1 size].width, kWidth1x); + EXPECT_EQ([ns_image_rep1 size].height, kHeight1x); + EXPECT_EQ([ns_image_rep2 size].width, kWidth2x); + EXPECT_EQ([ns_image_rep2 size].height, kHeight2x); } else { - EXPECT_EQ([image_rep_1 size].width, kWidth2x); - EXPECT_EQ([image_rep_1 size].height, kHeight2x); - EXPECT_EQ([image_rep_2 size].width, kWidth1x); - EXPECT_EQ([image_rep_2 size].height, kHeight1x); + EXPECT_EQ([ns_image_rep1 size].width, kWidth2x); + EXPECT_EQ([ns_image_rep1 size].height, kHeight2x); + EXPECT_EQ([ns_image_rep2 size].width, kWidth1x); + EXPECT_EQ([ns_image_rep2 size].height, kHeight1x); } // Cast to NSImage* should create a second representation. diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc index d268086..e5fb8e3 100644 --- a/ui/gfx/image/image_skia.cc +++ b/ui/gfx/image/image_skia.cc @@ -23,17 +23,7 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { ImageSkiaStorage() { } - void AddBitmap(const SkBitmap& bitmap) { - bitmaps_.push_back(bitmap); - } - - void RemoveBitmap(int position) { - DCHECK_GE(position, 0); - DCHECK_LT(static_cast<size_t>(position), bitmaps_.size()); - bitmaps_.erase(bitmaps_.begin() + position); - } - - const std::vector<SkBitmap>& bitmaps() const { return bitmaps_; } + std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } void set_size(const gfx::Size& size) { size_ = size; } const gfx::Size& size() const { return size_; } @@ -42,8 +32,8 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { ~ImageSkiaStorage() { } - // Bitmaps at different densities. - std::vector<SkBitmap> bitmaps_; + // Vector of bitmaps and their associated scale factor. + std::vector<gfx::ImageSkiaRep> image_reps_; // Size of the image in DIP. gfx::Size size_; @@ -53,18 +43,15 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { } // internal -// static -SkBitmap* ImageSkia::null_bitmap_ = new SkBitmap(); - ImageSkia::ImageSkia() : storage_(NULL) { } ImageSkia::ImageSkia(const SkBitmap& bitmap) { - Init(bitmap); + Init(ImageSkiaRep(bitmap)); } -ImageSkia::ImageSkia(const SkBitmap& bitmap, float dip_scale_factor) { - Init(bitmap, dip_scale_factor); +ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { + Init(image_rep); } ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { @@ -76,81 +63,70 @@ ImageSkia& ImageSkia::operator=(const ImageSkia& other) { } ImageSkia& ImageSkia::operator=(const SkBitmap& other) { + Init(ImageSkiaRep(other)); + return *this; +} + +ImageSkia& ImageSkia::operator=(const ImageSkiaRep& other) { Init(other); return *this; } ImageSkia::operator SkBitmap&() const { - if (isNull()) { - return *null_bitmap_; - } - - return const_cast<SkBitmap&>(storage_->bitmaps()[0]); -} + if (isNull()) + return const_cast<SkBitmap&>(NullImageRep().sk_bitmap()); -ImageSkia::~ImageSkia() { + return const_cast<SkBitmap&>(storage_->image_reps()[0].sk_bitmap()); } -void ImageSkia::AddBitmapForScale(const SkBitmap& bitmap, - float dip_scale_factor) { - DCHECK(!bitmap.isNull()); +ImageSkia::operator ImageSkiaRep&() const { + if (isNull()) + return NullImageRep(); - if (isNull()) { - Init(bitmap, dip_scale_factor); - } else { - // TODO(pkotwicz): Figure out a way of dealing with adding HDA bitmaps. In - // HDA, width() * |dip_scale_factor| != |bitmap|.width(). - storage_->AddBitmap(bitmap); - } + return storage_->image_reps()[0]; } -void ImageSkia::RemoveBitmapForScale(float dip_scale_factor) { - float bitmap_scale_factor; - int remove_candidate = GetBitmapIndexForScale(dip_scale_factor, - dip_scale_factor, - &bitmap_scale_factor); - // TODO(pkotwicz): Allow for small errors between scale factors due to - // rounding errors in computing |bitmap_scale_factor|. - if (remove_candidate >= 0 && dip_scale_factor == bitmap_scale_factor) - storage_->RemoveBitmap(remove_candidate); +ImageSkia::~ImageSkia() { } -bool ImageSkia::HasBitmapForScale(float dip_scale_factor) { - float bitmap_scale_factor; - int candidate = GetBitmapIndexForScale(dip_scale_factor, - dip_scale_factor, - &bitmap_scale_factor); - // TODO(pkotwicz): Allow for small errors between scale factors due to - // rounding errors in computing |bitmap_scale_factor|. - return (candidate >= 0 && bitmap_scale_factor == dip_scale_factor); +void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { + DCHECK(!image_rep.is_null()); + + if (isNull()) + Init(image_rep); + else + storage_->image_reps().push_back(image_rep); } -const SkBitmap& ImageSkia::GetBitmapForScale(float scale_factor, - float* bitmap_scale_factor) const { - return ImageSkia::GetBitmapForScale(scale_factor, - scale_factor, - bitmap_scale_factor); +void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { + if (isNull()) + return; + + ImageSkiaReps& image_reps = storage_->image_reps(); + ImageSkiaReps::iterator it = FindRepresentation(scale_factor); + if (it != image_reps.end() && it->scale_factor() == scale_factor) + image_reps.erase(it); } -float ImageSkia::GetScaleAtIndex(size_t index) const { - const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); +bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) { + if (isNull()) + return false; - DCHECK_GE(index, 0u); - DCHECK_LT(index, bitmaps.size()); - return static_cast<float>(bitmaps[index].width()) / width(); + ImageSkiaReps::iterator it = FindRepresentation(scale_factor); + return (it != storage_->image_reps().end() && + it->scale_factor() == scale_factor); } -const SkBitmap& ImageSkia::GetBitmapForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const { - int closest_index = GetBitmapIndexForScale(x_scale_factor, y_scale_factor, - bitmap_scale_factor); +const ImageSkiaRep& ImageSkia::GetRepresentation( + ui::ScaleFactor scale_factor) const { + if (isNull()) + return NullImageRep(); - if (closest_index < 0) - return *null_bitmap_; + ImageSkiaReps::iterator it = FindRepresentation(scale_factor); + if (it == storage_->image_reps().end()) + return NullImageRep(); - const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); - return bitmaps[closest_index]; + return *it; } bool ImageSkia::empty() const { @@ -168,15 +144,12 @@ int ImageSkia::height() const { bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { if (isNull()) return false; - gfx::ImageSkia image; - int dip_width = width(); - const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); - for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); - it != bitmaps.end(); ++it) { - const SkBitmap& bitmap = *it; - int px_width = it->width(); - float dip_scale = static_cast<float>(px_width) / - static_cast<float>(dip_width); + ImageSkia image; + ImageSkiaReps& image_reps = storage_->image_reps(); + for (ImageSkiaReps::iterator it = image_reps.begin(); + it != image_reps.end(); ++it) { + const ImageSkiaRep& image_rep = *it; + float dip_scale = image_rep.GetScale(); // Rounding boundary in case of a non-integer scale factor. int x = static_cast<int>(subset.left() * dip_scale + 0.5); int y = static_cast<int>(subset.top() * dip_scale + 0.5); @@ -184,8 +157,9 @@ bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { int h = static_cast<int>(subset.height() * dip_scale + 0.5); SkBitmap dst_bitmap; SkIRect scaled_subset = SkIRect::MakeXYWH(x, y, w, h); - if (bitmap.extractSubset(&dst_bitmap, scaled_subset)) - image.AddBitmapForScale(dst_bitmap, dip_scale); + if (image_rep.sk_bitmap().extractSubset(&dst_bitmap, scaled_subset)) + image.AddRepresentation(ImageSkiaRep(dst_bitmap, + image_rep.scale_factor())); } if (image.empty()) return false; @@ -194,72 +168,59 @@ bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { return true; } -const std::vector<SkBitmap> ImageSkia::bitmaps() const { +std::vector<ImageSkiaRep> ImageSkia::image_reps() const { if (isNull()) - return std::vector<SkBitmap>(); + return std::vector<ImageSkiaRep>(); - return storage_->bitmaps(); + return storage_->image_reps(); } const SkBitmap* ImageSkia::bitmap() const { if (isNull()) { - // Callers expect an SkBitmap even if it is |isNull()|. + // Callers expect a ImageSkiaRep even if it is |isNull()|. // TODO(pkotwicz): Fix this. - return null_bitmap_; + return &NullImageRep().sk_bitmap(); } - return &storage_->bitmaps()[0]; -} - -void ImageSkia::Init(const SkBitmap& bitmap) { - Init(bitmap, 1.0f); + return &storage_->image_reps()[0].sk_bitmap(); } -void ImageSkia::Init(const SkBitmap& bitmap, float scale_factor) { - DCHECK_GT(scale_factor, 0.0f); - // TODO(pkotwicz): The image should be null whenever bitmap is null. - if (bitmap.empty() && bitmap.isNull()) { +void ImageSkia::Init(const ImageSkiaRep& image_rep) { + // TODO(pkotwicz): The image should be null whenever image rep is null. + if (image_rep.sk_bitmap().empty()) { storage_ = NULL; return; } storage_ = new internal::ImageSkiaStorage(); - storage_->set_size(gfx::Size(static_cast<int>(bitmap.width() / scale_factor), - static_cast<int>(bitmap.height() / scale_factor))); - storage_->AddBitmap(bitmap); + storage_->set_size(gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); + storage_->image_reps().push_back(image_rep); } -int ImageSkia::GetBitmapIndexForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const { - // Initialize |bitmap_scale_factor|. - *bitmap_scale_factor = 0.0f; - - if (empty()) - return -1; +// static +ImageSkiaRep& ImageSkia::NullImageRep() { + CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ()); + return null_image_rep; +} - // Get the desired bitmap width and height given |x_scale_factor|, - // |y_scale_factor| and size at 1x density. - float desired_width = width() * x_scale_factor; - float desired_height = height() * y_scale_factor; +std::vector<ImageSkiaRep>::iterator ImageSkia::FindRepresentation( + ui::ScaleFactor scale_factor) const { + DCHECK(!isNull()); - const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); - int closest_index = -1; + float scale = ui::GetScaleFactorScale(scale_factor); + ImageSkiaReps& image_reps = storage_->image_reps(); + ImageSkiaReps::iterator closest_iter = image_reps.end(); float smallest_diff = std::numeric_limits<float>::max(); - for (size_t i = 0; i < bitmaps.size(); ++i) { - float diff = std::abs(bitmaps[i].width() - desired_width) + - std::abs(bitmaps[i].height() - desired_height); + for (ImageSkiaReps::iterator it = image_reps.begin(); + it < image_reps.end(); + ++it) { + float diff = std::abs(it->GetScale() - scale); if (diff < smallest_diff) { - closest_index = static_cast<int>(i); + closest_iter = it; smallest_diff = diff; } } - if (closest_index >= 0) { - *bitmap_scale_factor = static_cast<float>(bitmaps[closest_index].width()) / - width(); - } - - return closest_index; + return closest_iter; } } // namespace gfx diff --git a/ui/gfx/image/image_skia.h b/ui/gfx/image/image_skia.h index 63ec001..9ebeb5f 100644 --- a/ui/gfx/image/image_skia.h +++ b/ui/gfx/image/image_skia.h @@ -10,8 +10,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/ui_export.h" +#include "ui/gfx/image/image_skia_rep.h" namespace gfx { @@ -23,13 +23,14 @@ class ImageSkiaStorage; // Image height and width are in DIP (Device Indepent Pixel) coordinates. // // ImageSkia should be used whenever possible instead of SkBitmap. -// Functions that mutate the image should operate on the SkBitmap returned -// from ImageSkia::GetBitmapForScale, not on ImageSkia. +// Functions that mutate the image should operate on the gfx::ImageSkiaRep +// returned from ImageSkia::GetRepresentation, not on ImageSkia. // // ImageSkia is cheap to copy and intentionally supports copy semantics. -// TODO(pkotwicz): Change API to take in ui::DISPLAY_LAYOUT instead of floats. class UI_EXPORT ImageSkia { public: + typedef std::vector<ImageSkiaRep> ImageSkiaReps; + // Creates instance with no bitmaps. ImageSkia(); @@ -39,9 +40,7 @@ class UI_EXPORT ImageSkia { // done. ImageSkia(const SkBitmap& bitmap); - // Adds ref to passed in bitmap. - // DIP width and height are set based on |dip_scale_factor|. - ImageSkia(const SkBitmap& bitmap, float dip_scale_factor); + ImageSkia(const gfx::ImageSkiaRep& image_rep); // Copies a reference to |other|'s storage. ImageSkia(const ImageSkia& other); @@ -56,43 +55,37 @@ class UI_EXPORT ImageSkia { // done. ImageSkia& operator=(const SkBitmap& other); - // Converts to SkBitmap. + // Converts from gfx::ImageSkiaRep. + // Adds ref to passed in image rep. + // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is + // done. + ImageSkia& operator=(const gfx::ImageSkiaRep& other); + + // Converts to gfx::ImageSkiaRep and SkBitmap. // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is // done. operator SkBitmap&() const; + operator gfx::ImageSkiaRep&() const; ~ImageSkia(); - // Adds |bitmap| for |dip_scale_factor| to bitmaps contained by this object. - // Adds ref to passed in bitmap. - // DIP width and height are set based on |dip_scale_factor|. - void AddBitmapForScale(const SkBitmap& bitmap, float dip_scale_factor); - - // Removes component bitmap of |dip_scale_factor| if present. - void RemoveBitmapForScale(float dip_scale_factor); - - // Returns true if the object owns a bitmap whose density matches - // |dip_scale_factor| exactly. - bool HasBitmapForScale(float dip_scale_factor); - - // Returns the bitmap whose density best matches |scale_factor|. - // Returns a null bitmap if the object contains no bitmaps. - // |bitmap_scale_factor| is set to the scale factor of the returned bitmap. - const SkBitmap& GetBitmapForScale(float scale_factor, - float* bitmap_scale_factor) const; - - // Returns the bitmap whose density best matches |x_scale_factor| and - // |y_scale_factor|. - // Returns a null bitmap if the object contains no bitmaps. - // |bitmap_scale_factor| is set to the scale factor of the returned bitmap. - const SkBitmap& GetBitmapForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const; - - // Returns the scale of the bitmap at |index|. - float GetScaleAtIndex(size_t index) const; - - // Returns true if object is null or |size_| is empty. + // Adds |image_rep| to the image reps contained by this object. + void AddRepresentation(const gfx::ImageSkiaRep& image_rep); + + // Removes the image rep of |scale_factor| if present. + void RemoveRepresentation(ui::ScaleFactor scale_factor); + + // Returns true if the object owns a image rep whose density matches + // |scale_factor| exactly. + bool HasRepresentation(ui::ScaleFactor scale_factor); + + // Returns the image rep whose density best matches + // |scale_factor|. + // Returns a null image rep if the object contains no image reps. + const gfx::ImageSkiaRep& GetRepresentation( + ui::ScaleFactor scale_factor) const; + + // Returns true if object is null or its size is empty. bool empty() const; // Returns true if this is a null object. @@ -104,7 +97,7 @@ class UI_EXPORT ImageSkia { int height() const; // Wrapper function for SkBitmap::extractBitmap. - // Operates on each stored bitmap. + // Operates on each stored image rep. bool extractSubset(ImageSkia* dst, const SkIRect& subset) const; // Returns pointer to an SkBitmap contained by this object. @@ -112,32 +105,22 @@ class UI_EXPORT ImageSkia { // done. const SkBitmap* bitmap() const; - // Returns a vector with the SkBitmaps contained in this object. - const std::vector<SkBitmap> bitmaps() const; + // Returns a vector with the image reps contained in this object. + std::vector<gfx::ImageSkiaRep> image_reps() const; private: // Initialize ImageSkiaStorage with passed in parameters. - // If |bitmap.isNull()|, ImageStorage is set to NULL. - // Scale factor is set based on default scale factor of 1x. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - void Init(const SkBitmap& bitmap); + // If the image rep's bitmap is empty, ImageStorage is set to NULL. + void Init(const gfx::ImageSkiaRep& image_rep); - // Initialize ImageSkiaStorage with passed in parameters. - // If |bitmap.isNull()|, ImageStorage is set to NULL. - void Init(const SkBitmap& bitmap, float scale_factor); - - // Returns the index of the bitmap whose density best matches - // |x_scale_factor| and |y_scale_factor|. - // Returns -1 if the object contains no bitmaps. - // |bitmap_scale_factor| is set to the scale factor of the bitmap - // at the returned index. - int GetBitmapIndexForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const; - - // A null bitmap to return as not to return a temporary. - static SkBitmap* null_bitmap_; + // A null image rep to return as not to return a temporary. + static gfx::ImageSkiaRep& NullImageRep(); + + // Returns the iterator of the image rep whose density best matches + // |scale_factor|. + // ImageSkiaStorage cannot be NULL when this function is called. + ImageSkiaReps::iterator FindRepresentation( + ui::ScaleFactor scale_factor) const; // A refptr so that ImageRepSkia can be copied cheaply. scoped_refptr<internal::ImageSkiaStorage> storage_; diff --git a/ui/gfx/image/image_skia_rep.cc b/ui/gfx/image/image_skia_rep.cc new file mode 100644 index 0000000..fe38230 --- /dev/null +++ b/ui/gfx/image/image_skia_rep.cc @@ -0,0 +1,61 @@ +// 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 "ui/gfx/image/image_skia_rep.h" + +namespace gfx { + +ImageSkiaRep::ImageSkiaRep() + : scale_factor_(ui::SCALE_FACTOR_NONE) { +} + +ImageSkiaRep::~ImageSkiaRep() { +} + +ImageSkiaRep::ImageSkiaRep(int width, int height, + ui::ScaleFactor scale_factor) + : scale_factor_(scale_factor) { + float scale = ui::GetScaleFactorScale(scale_factor); + bitmap_.setConfig(SkBitmap::kARGB_8888_Config, + static_cast<int>(width * scale), + static_cast<int>(height * scale)); + bitmap_.allocPixels(); +} + +ImageSkiaRep::ImageSkiaRep(const SkBitmap& src) + : bitmap_(src), + scale_factor_(ui::SCALE_FACTOR_NONE) { +} + +ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, + ui::ScaleFactor scale_factor) + : bitmap_(src), + scale_factor_(scale_factor) { +} + +ImageSkiaRep& ImageSkiaRep::operator=(const SkBitmap& other) { + bitmap_ = other; + scale_factor_ = ui::SCALE_FACTOR_NONE; + return *this; +} + +ImageSkiaRep::operator SkBitmap&() const { + return const_cast<SkBitmap&>(bitmap_); +} + +int ImageSkiaRep::GetWidth() const { + return static_cast<int>(bitmap_.width() / + ui::GetScaleFactorScale(scale_factor_)); +} + +int ImageSkiaRep::GetHeight() const { + return static_cast<int>(bitmap_.height() / + ui::GetScaleFactorScale(scale_factor_)); +} + +float ImageSkiaRep::GetScale() const { + return ui::GetScaleFactorScale(scale_factor_); +} + +} // namespace gfx diff --git a/ui/gfx/image/image_skia_rep.h b/ui/gfx/image/image_skia_rep.h new file mode 100644 index 0000000..ce209d1 --- /dev/null +++ b/ui/gfx/image/image_skia_rep.h @@ -0,0 +1,66 @@ +// 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. + +#ifndef UI_GFX_IMAGE_IMAGE_SKIA_REP_H_ +#define UI_GFX_IMAGE_IMAGE_SKIA_REP_H_ +#pragma once + +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/layout.h" +#include "ui/base/ui_export.h" + +namespace gfx { + +// An ImageSkiaRep represents a bitmap and the scale factor it is intended for. +class UI_EXPORT ImageSkiaRep { + public: + // Create null bitmap. + ImageSkiaRep(); + ~ImageSkiaRep(); + + // Creates a bitmap with kARGB_8888_Config config with given DIP |width| and + // |height| and |scale_factor|. + // Allocates pixels. + ImageSkiaRep(int width, int height, ui::ScaleFactor scale_factor); + + // Creates a bitmap with a default scale factor of 1x. + // Adds ref to |src|. + // TODO(pkotwicz): This is temporary and should be removed ASAP. + ImageSkiaRep(const SkBitmap& src); + + // Creates a bitmap with given scale factor. + // Adds ref to |src|. + ImageSkiaRep(const SkBitmap& src, ui::ScaleFactor scale_factor); + + // Converts to and from SkBitmap. + // TODO(pkotwicz): This is temporary and should be removed ASAP. + ImageSkiaRep& operator=(const SkBitmap& other); + operator SkBitmap&() const; + + // Returns true if the backing bitmap is null. + bool is_null() const { return bitmap_.isNull(); } + + // Get width and height of bitmap in DIP. + int GetWidth() const; + int GetHeight() const; + + // Get width and height of bitmap in pixels. + int pixel_width() const { return bitmap_.width(); } + int pixel_height() const { return bitmap_.height(); } + + // Retrieves the scale that the bitmap will be painted at. + float GetScale() const; + ui::ScaleFactor scale_factor() const { return scale_factor_; } + + // Returns backing bitmap. + const SkBitmap& sk_bitmap() const { return bitmap_; } + + private: + SkBitmap bitmap_; + ui::ScaleFactor scale_factor_; +}; + +} // namespace gfx + +#endif // UI_GFX_IMAGE_IMAGE_SKIA_REP_H_ diff --git a/ui/gfx/image/image_skia_util_mac.mm b/ui/gfx/image/image_skia_util_mac.mm index d558481..70b7859 100644 --- a/ui/gfx/image/image_skia_util_mac.mm +++ b/ui/gfx/image/image_skia_util_mac.mm @@ -4,6 +4,9 @@ #include "ui/gfx/image/image_skia_util_mac.h" +#include <cmath> +#include <limits> + #import <AppKit/AppKit.h> #include "base/mac/mac_util.h" @@ -13,6 +16,31 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image_skia.h" +namespace { + +// Returns NSImageRep whose pixel size most closely matches |desired_size|. +NSImageRep* GetNSImageRepWithPixelSize(NSImage* image, + NSSize desired_size) { + float smallest_diff = std::numeric_limits<float>::max(); + NSImageRep* closest_match = nil; + for (NSImageRep* image_rep in [image representations]) { + float diff = std::abs(desired_size.width - [image_rep pixelsWide]) + + std::abs(desired_size.height - [image_rep pixelsHigh]); + if (diff < smallest_diff) { + smallest_diff = diff; + closest_match = image_rep; + } + } + return closest_match; +} + +// Returns true if NSImage has no representations +bool IsNSImageEmpty(NSImage* image) { + return ([image representations].count == 0); +} + +} // namespace + namespace gfx { gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image) { @@ -23,19 +51,30 @@ gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image, NSSize desired_size) { // Resize and convert to ImageSkia simultaneously to save on computation. // TODO(pkotwicz): Separate resizing NSImage and converting to ImageSkia. - float resize_scale_x = desired_size.width / [image size].width; - float resize_scale_y = desired_size.height / [image size].height; + // Convert to ImageSkia by finding the most appropriate NSImageRep for + // each supported scale factor and resizing if necessary. + + if (IsNSImageEmpty(image)) + return gfx::ImageSkia(); + + std::vector<ui::ScaleFactor> supported_scale_factors = + ui::GetSupportedScaleFactors(); gfx::ImageSkia image_skia; - for (NSImageRep* image_rep in [image representations]) { - NSSize image_rep_size = NSMakeSize([image_rep pixelsWide] * resize_scale_x, - [image_rep pixelsHigh] * resize_scale_y); - SkBitmap bitmap(gfx::NSImageRepToSkBitmap(image_rep, image_rep_size, - false)); - if (!bitmap.isNull() && !bitmap.empty()) { - float scale_factor = image_rep_size.width / desired_size.width; - image_skia.AddBitmapForScale(bitmap, scale_factor); - } + for (size_t i = 0; i < supported_scale_factors.size(); ++i) { + float scale = ui::GetScaleFactorScale(supported_scale_factors[i]); + NSSize desired_size_for_scale = NSMakeSize(desired_size.width * scale, + desired_size.height * scale); + NSImageRep* ns_image_rep = GetNSImageRepWithPixelSize(image, + desired_size_for_scale); + + SkBitmap bitmap(gfx::NSImageRepToSkBitmap(ns_image_rep, + desired_size_for_scale, false)); + if (bitmap.isNull() || bitmap.empty()) + continue; + + image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, + supported_scale_factors[i])); } return image_skia; } @@ -52,10 +91,11 @@ NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) { scoped_nsobject<NSImage> image([[NSImage alloc] init]); - const std::vector<SkBitmap> bitmaps = image_skia.bitmaps(); - for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); - it != bitmaps.end(); ++it) { - [image addRepresentation:gfx::SkBitmapToNSBitmapImageRep(*it)]; + std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps(); + for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin(); + it != image_reps.end(); ++it) { + [image addRepresentation: + gfx::SkBitmapToNSBitmapImageRep(it->sk_bitmap())]; } [image setSize:NSMakeSize(image_skia.width(), image_skia.height())]; diff --git a/ui/gfx/image/image_unittest.cc b/ui/gfx/image/image_unittest.cc index 1c964ef..0cdc237 100644 --- a/ui/gfx/image/image_unittest.cc +++ b/ui/gfx/image/image_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_unittest_util.h" @@ -257,25 +256,32 @@ TEST_F(ImageTest, MultiResolutionImage) { const int kHeight2x = 24; gfx::ImageSkia image_skia; - image_skia.AddBitmapForScale(gt::CreateBitmap(kWidth1x, kHeight1x), 1.0f); - image_skia.AddBitmapForScale(gt::CreateBitmap(kWidth2x, kHeight2x), 2.0f); - - EXPECT_EQ(2u, image_skia.bitmaps().size()); - - float scale_factor; - const SkBitmap& bitmap1x = image_skia.GetBitmapForScale(1.0f, 1.0f, - &scale_factor); - EXPECT_TRUE(!bitmap1x.isNull()); - EXPECT_EQ(1.0f, scale_factor); - EXPECT_EQ(kWidth1x, bitmap1x.width()); - EXPECT_EQ(kHeight1x, bitmap1x.height()); - - const SkBitmap& bitmap2x = image_skia.GetBitmapForScale(2.0f, 2.0f, - &scale_factor); - EXPECT_TRUE(!bitmap2x.isNull()); - EXPECT_EQ(2.0f, scale_factor); - EXPECT_EQ(kWidth2x, bitmap2x.width()); - EXPECT_EQ(kHeight2x, bitmap2x.height()); + image_skia.AddRepresentation(gfx::ImageSkiaRep( + gt::CreateBitmap(kWidth1x, kHeight1x), + ui::SCALE_FACTOR_100P)); + image_skia.AddRepresentation(gfx::ImageSkiaRep( + gt::CreateBitmap(kWidth2x, kHeight2x), + ui::SCALE_FACTOR_200P)); + + EXPECT_EQ(2u, image_skia.image_reps().size()); + + const gfx::ImageSkiaRep& image_rep1x = + image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); + EXPECT_TRUE(!image_rep1x.is_null()); + EXPECT_EQ(ui::SCALE_FACTOR_100P, image_rep1x.scale_factor()); + EXPECT_EQ(kWidth1x, image_rep1x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep1x.GetHeight()); + EXPECT_EQ(kWidth1x, image_rep1x.pixel_width()); + EXPECT_EQ(kHeight1x, image_rep1x.pixel_height()); + + const gfx::ImageSkiaRep& image_rep2x = + image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); + EXPECT_TRUE(!image_rep2x.is_null()); + EXPECT_EQ(ui::SCALE_FACTOR_200P, image_rep2x.scale_factor()); + EXPECT_EQ(kWidth1x, image_rep2x.GetWidth()); + EXPECT_EQ(kHeight1x, image_rep2x.GetHeight()); + EXPECT_EQ(kWidth2x, image_rep2x.pixel_width()); + EXPECT_EQ(kHeight2x, image_rep2x.pixel_height()); // Check that the image has a single representation. gfx::Image image(image_skia); @@ -288,14 +294,15 @@ TEST_F(ImageTest, RemoveFromMultiResolutionImage) { gfx::ImageSkia image_skia; - image_skia.AddBitmapForScale(gt::CreateBitmap(kWidth2x, kHeight2x), 2.0f); - EXPECT_EQ(1u, image_skia.bitmaps().size()); + image_skia.AddRepresentation(gfx::ImageSkiaRep( + gt::CreateBitmap(kWidth2x, kHeight2x), ui::SCALE_FACTOR_200P)); + EXPECT_EQ(1u, image_skia.image_reps().size()); - image_skia.RemoveBitmapForScale(1.0f); - EXPECT_EQ(1u, image_skia.bitmaps().size()); + image_skia.RemoveRepresentation(ui::SCALE_FACTOR_100P); + EXPECT_EQ(1u, image_skia.image_reps().size()); - image_skia.RemoveBitmapForScale(2.0f); - EXPECT_EQ(0u, image_skia.bitmaps().size()); + image_skia.RemoveRepresentation(ui::SCALE_FACTOR_200P); + EXPECT_EQ(0u, image_skia.image_reps().size()); } // Tests that gfx::Image does indeed take ownership of the SkBitmap it is @@ -303,9 +310,9 @@ TEST_F(ImageTest, RemoveFromMultiResolutionImage) { TEST_F(ImageTest, OwnershipTest) { gfx::Image image; { - SkBitmap bitmap = gt::CreateBitmap(10, 10); + SkBitmap bitmap(gt::CreateBitmap(10, 10)); EXPECT_TRUE(!bitmap.isNull()); - image = gfx::Image(bitmap); + image = gfx::Image(gfx::ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P)); } EXPECT_TRUE(!image.ToSkBitmap()->isNull()); } diff --git a/ui/gfx/image/image_unittest_util.cc b/ui/gfx/image/image_unittest_util.cc index c58c58b..7d00378 100644 --- a/ui/gfx/image/image_unittest_util.cc +++ b/ui/gfx/image/image_unittest_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -6,6 +6,7 @@ // implementation files, this header contains the reusable components. #include "base/memory/scoped_ptr.h" +#include "ui/base/layout.h" #include "ui/gfx/image/image_unittest_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -20,6 +21,17 @@ namespace gfx { namespace test { +#if defined(OS_MACOSX) + +void SetSupportedScaleFactorsTo1xAnd2x() { + std::vector<ui::ScaleFactor> supported_scale_factors; + supported_scale_factors.push_back(ui::SCALE_FACTOR_100P); + supported_scale_factors.push_back(ui::SCALE_FACTOR_200P); + ui::test::SetSupportedScaleFactors(supported_scale_factors); +} + +#endif // OS_MACOSX + const SkBitmap CreateBitmap(int width, int height) { SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); diff --git a/ui/gfx/image/image_unittest_util.h b/ui/gfx/image/image_unittest_util.h index e617f26..8ac8d8d 100644 --- a/ui/gfx/image/image_unittest_util.h +++ b/ui/gfx/image/image_unittest_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -21,6 +21,10 @@ typedef GdkPixbuf* PlatformImage; typedef const SkBitmap PlatformImage; #endif +#if defined(OS_MACOSX) +void SetSupportedScaleFactorsTo1xAnd2x(); +#endif + const SkBitmap CreateBitmap(int width, int height); gfx::Image CreateImage(); @@ -342,6 +342,8 @@ 'gfx/image/image.h', 'gfx/image/image_skia.cc', 'gfx/image/image_skia.h', + 'gfx/image/image_skia_rep.cc', + 'gfx/image/image_skia_rep.h', 'gfx/image/image_skia_util_mac.h', 'gfx/image/image_skia_util_mac.mm', 'gfx/image/image_util.cc', diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc index 383cafd..1af311b 100644 --- a/ui/views/controls/button/image_button.cc +++ b/ui/views/controls/button/image_button.cc @@ -75,8 +75,8 @@ void ImageButton::OnPaint(gfx::Canvas* canvas) { // Call the base class first to paint any background/borders. View::OnPaint(canvas); - float current_device_scale = GetCurrentDeviceScale(); - gfx::ImageSkia img = GetImageToPaint(current_device_scale); + ui::ScaleFactor current_device_scale_factor = GetCurrentDeviceScaleFactor(); + gfx::ImageSkia img = GetImageToPaint(current_device_scale_factor); if (!img.isNull()) { int x = 0, y = 0; @@ -91,8 +91,10 @@ void ImageButton::OnPaint(gfx::Canvas* canvas) { else if (v_alignment_ == ALIGN_BOTTOM) y = height() - img.height(); - if (!background_image_.result_.HasBitmapForScale(current_device_scale)) - UpdateButtonBackground(current_device_scale); + if (!background_image_.result_.HasRepresentation( + current_device_scale_factor)) { + UpdateButtonBackground(current_device_scale_factor); + } if (!background_image_.result_.empty()) canvas->DrawImageInt(background_image_.result_, x, y); @@ -107,26 +109,27 @@ void ImageButton::OnPaint(gfx::Canvas* canvas) { //////////////////////////////////////////////////////////////////////////////// // ImageButton, protected: -float ImageButton::GetCurrentDeviceScale() { +ui::ScaleFactor ImageButton::GetCurrentDeviceScaleFactor() { gfx::Display display = gfx::Screen::GetDisplayNearestWindow( GetWidget() ? GetWidget()->GetNativeView() : NULL); - return display.device_scale_factor(); + return ui::GetScaleFactorFromScale(display.device_scale_factor()); } -gfx::ImageSkia ImageButton::GetImageToPaint(float scale) { +gfx::ImageSkia ImageButton::GetImageToPaint(ui::ScaleFactor scale_factor) { gfx::ImageSkia img; if (!images_[BS_HOT].isNull() && hover_animation_->is_animating()) { - float normal_bitmap_scale; - float hot_bitmap_scale; - SkBitmap normal_bitmap = images_[BS_NORMAL].GetBitmapForScale( - scale, &normal_bitmap_scale); - SkBitmap hot_bitmap = images_[BS_HOT].GetBitmapForScale(scale, - &hot_bitmap_scale); - DCHECK_EQ(normal_bitmap_scale, hot_bitmap_scale); + gfx::ImageSkiaRep normal_image_rep = images_[BS_NORMAL].GetRepresentation( + scale_factor); + gfx::ImageSkiaRep hot_image_rep = images_[BS_HOT].GetRepresentation( + scale_factor); + DCHECK_EQ(normal_image_rep.scale_factor(), hot_image_rep.scale_factor()); SkBitmap blended_bitmap = SkBitmapOperations::CreateBlendedBitmap( - normal_bitmap, hot_bitmap, hover_animation_->GetCurrentValue()); - img = gfx::ImageSkia(blended_bitmap, normal_bitmap_scale); + normal_image_rep.sk_bitmap(), + hot_image_rep.sk_bitmap(), + hover_animation_->GetCurrentValue()); + img = gfx::ImageSkia(gfx::ImageSkiaRep(blended_bitmap, + normal_image_rep.scale_factor())); } else { img = images_[state_]; } @@ -134,21 +137,22 @@ gfx::ImageSkia ImageButton::GetImageToPaint(float scale) { return !img.isNull() ? img : images_[BS_NORMAL]; } -void ImageButton::UpdateButtonBackground(float scale) { - float bitmap_scale; - float mask_scale; - SkBitmap bitmap = background_image_.src_image_.GetBitmapForScale( - scale, &bitmap_scale); - SkBitmap mask_bitmap = background_image_.src_mask_.GetBitmapForScale( - scale, &mask_scale); - if (bitmap.isNull() || mask_bitmap.isNull() || - background_image_.result_.HasBitmapForScale(bitmap_scale)) { +void ImageButton::UpdateButtonBackground(ui::ScaleFactor scale_factor) { + gfx::ImageSkiaRep image_rep = + background_image_.src_image_.GetRepresentation(scale_factor); + gfx::ImageSkiaRep mask_image_rep = + background_image_.src_mask_.GetRepresentation(scale_factor); + if (image_rep.is_null() || mask_image_rep.is_null() || + background_image_.result_.HasRepresentation(image_rep.scale_factor())) { return; } - DCHECK_EQ(bitmap_scale, mask_scale); + DCHECK_EQ(image_rep.scale_factor(), mask_image_rep.scale_factor()); SkBitmap result = SkBitmapOperations::CreateButtonBackground( - background_image_.src_color_, bitmap, mask_bitmap); - background_image_.result_.AddBitmapForScale(result, bitmap_scale); + background_image_.src_color_, + image_rep.sk_bitmap(), + mask_image_rep.sk_bitmap()); + background_image_.result_.AddRepresentation(gfx::ImageSkiaRep( + result, image_rep.scale_factor())); } //////////////////////////////////////////////////////////////////////////////// diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h index 49f44b8..413a4bc 100644 --- a/ui/views/controls/button/image_button.h +++ b/ui/views/controls/button/image_button.h @@ -63,18 +63,18 @@ class VIEWS_EXPORT ImageButton : public CustomButton { } protected: - // Returns the current device scale of the view. + // Returns the current device scale factor of the view. // TODO(pkotwicz): Remove this once scale factor can be queried from canvas. - float GetCurrentDeviceScale(); + ui::ScaleFactor GetCurrentDeviceScaleFactor(); // Returns the image to paint. This is invoked from paint and returns a value // from images. - // |scale| is the scale at which the view is painted and the scale - // which should be used when mutating ImageSkias. - virtual gfx::ImageSkia GetImageToPaint(float scale); + // |scale_factor| is the scale factor at which the view is painted and the + // scale factor which should be used when mutating ImageSkias. + virtual gfx::ImageSkia GetImageToPaint(ui::ScaleFactor scale_factor); - // Updates button background for |scale|. - void UpdateButtonBackground(float scale); + // Updates button background for |scale_factor|. + void UpdateButtonBackground(ui::ScaleFactor scale_factor); // The images used to render the different states of this button. gfx::ImageSkia images_[BS_COUNT]; diff --git a/ui/views/controls/button/image_button_unittest.cc b/ui/views/controls/button/image_button_unittest.cc index 8f5ea5f..617a855 100644 --- a/ui/views/controls/button/image_button_unittest.cc +++ b/ui/views/controls/button/image_button_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/layout.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/test/views_test_base.h" @@ -24,10 +25,10 @@ typedef ViewsTestBase ImageButtonTest; TEST_F(ImageButtonTest, Basics) { ImageButton button(NULL); - float kRequestedScale = 1.0f; + ui::ScaleFactor kRequestedScaleFactor = ui::SCALE_FACTOR_100P; // Our image to paint starts empty. - EXPECT_TRUE(button.GetImageToPaint(kRequestedScale).empty()); + EXPECT_TRUE(button.GetImageToPaint(kRequestedScaleFactor).empty()); // Without a theme, buttons are 16x14 by default. EXPECT_EQ("16x14", button.GetPreferredSize().ToString()); @@ -41,9 +42,9 @@ TEST_F(ImageButtonTest, Basics) { button.SetImage(CustomButton::BS_NORMAL, &normal_image); // Image uses normal image for painting. - EXPECT_FALSE(button.GetImageToPaint(kRequestedScale).empty()); - EXPECT_EQ(10, button.GetImageToPaint(kRequestedScale).width()); - EXPECT_EQ(20, button.GetImageToPaint(kRequestedScale).height()); + EXPECT_FALSE(button.GetImageToPaint(kRequestedScaleFactor).empty()); + EXPECT_EQ(10, button.GetImageToPaint(kRequestedScaleFactor).width()); + EXPECT_EQ(20, button.GetImageToPaint(kRequestedScaleFactor).height()); // Preferred size is the normal button size. EXPECT_EQ("10x20", button.GetPreferredSize().ToString()); @@ -57,9 +58,9 @@ TEST_F(ImageButtonTest, Basics) { EXPECT_EQ("10x20", button.GetPreferredSize().ToString()); // We're still painting the normal image. - EXPECT_FALSE(button.GetImageToPaint(kRequestedScale).empty()); - EXPECT_EQ(10, button.GetImageToPaint(kRequestedScale).width()); - EXPECT_EQ(20, button.GetImageToPaint(kRequestedScale).height()); + EXPECT_FALSE(button.GetImageToPaint(kRequestedScaleFactor).empty()); + EXPECT_EQ(10, button.GetImageToPaint(kRequestedScaleFactor).width()); + EXPECT_EQ(20, button.GetImageToPaint(kRequestedScaleFactor).height()); // Set an overlay image. gfx::ImageSkia overlay_image = CreateTestImage(12, 22); @@ -72,9 +73,9 @@ TEST_F(ImageButtonTest, Basics) { EXPECT_EQ("10x20", button.GetPreferredSize().ToString()); // We're still painting the normal image. - EXPECT_FALSE(button.GetImageToPaint(kRequestedScale).empty()); - EXPECT_EQ(10, button.GetImageToPaint(kRequestedScale).width()); - EXPECT_EQ(20, button.GetImageToPaint(kRequestedScale).height()); + EXPECT_FALSE(button.GetImageToPaint(kRequestedScaleFactor).empty()); + EXPECT_EQ(10, button.GetImageToPaint(kRequestedScaleFactor).width()); + EXPECT_EQ(20, button.GetImageToPaint(kRequestedScaleFactor).height()); // Reset the overlay image. button.SetOverlayImage(NULL); |