From f54bd1779f114be16dd4b4007f1ed68c2041cc68 Mon Sep 17 00:00:00 2001 From: "varunjain@chromium.org" Date: Fri, 11 May 2012 20:43:10 +0000 Subject: [PATCH] Aura: Adds custom cursors for drag and drop (second attempt: first attempt reverted due to build break: http://codereview.chromium.org/10316019 ) BUG=121135 TEST=none Review URL: https://chromiumcodereview.appspot.com/10378079 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@136653 0039d316-1c4b-4281-b951-d872f2087c98 --- ash/drag_drop/drag_drop_controller.cc | 2 +- content/test/DEPS | 3 +- content/test/content_test_suite.cc | 7 ++++ content/test/content_test_suite.h | 14 ++++++- ui/aura/aura.gyp | 35 ++++++++++++++++ ui/aura/root_window_host_linux.cc | 55 +++++++++++++++++++++++++- ui/aura/root_window_host_linux.h | 3 ++ ui/aura/test/test_aura_initializer.cc | 31 +++++++++++++++ ui/aura/test/test_aura_initializer.h | 28 +++++++++++++ ui/base/x/x11_util.cc | 21 ++++++++++ ui/base/x/x11_util.h | 7 ++++ ui/gfx/codec/png_codec.cc | 21 +--------- ui/gfx/skia_util.cc | 25 ++++++++++++ ui/gfx/skia_util.h | 7 +++- ui/resources/ui_resources_2x.grd | 2 + ui/resources/ui_resources_standard.grd | 2 + ui/resources/ui_resources_touch.grd | 2 + ui/ui.gyp | 1 + webkit/glue/webcursor_aurax11.cc | 35 +++------------- 19 files changed, 248 insertions(+), 53 deletions(-) create mode 100644 ui/aura/test/test_aura_initializer.cc create mode 100644 ui/aura/test/test_aura_initializer.h diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc index 5a3f7df11af78d..6c2348bf037368 100644 --- a/ash/drag_drop/drag_drop_controller.cc +++ b/ash/drag_drop/drag_drop_controller.cc @@ -114,7 +114,7 @@ void DragDropController::DragUpdate(aura::Window* target, drag_operation_); int op = delegate->OnDragUpdated(e); gfx::NativeCursor cursor = (op == ui::DragDropTypes::DRAG_NONE)? - ui::kCursorMove : ui::kCursorHand; + ui::kCursorNoDrop : ui::kCursorCopy; Shell::GetRootWindow()->SetCursor(cursor); } } diff --git a/content/test/DEPS b/content/test/DEPS index 1d027360795108..6a0754aa06274a 100644 --- a/content/test/DEPS +++ b/content/test/DEPS @@ -3,5 +3,6 @@ include_rules = [ # Testing utilities can access anything in content/ "+content", "+media/base", # For ChannelLayout in WebRTC tests. - "+ui/base/resource/data_pack.h" + "+ui/aura/test/test_aura_initializer.h", + "+ui/base/resource/data_pack.h", ] diff --git a/content/test/content_test_suite.cc b/content/test/content_test_suite.cc index 20071563c635b2..60506ac0c7c873 100644 --- a/content/test/content_test_suite.cc +++ b/content/test/content_test_suite.cc @@ -13,6 +13,10 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ui_base_paths.h" +#if defined(USE_AURA) +#include "ui/aura/test/test_aura_initializer.h" +#endif + #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" #endif @@ -45,6 +49,9 @@ class TestInitializationListener : public testing::EmptyTestEventListener { ContentTestSuite::ContentTestSuite(int argc, char** argv) : base::TestSuite(argc, argv) { +#if defined(USE_AURA) + aura_initializer_.reset(new aura::test::TestAuraInitializer); +#endif } ContentTestSuite::~ContentTestSuite() { diff --git a/content/test/content_test_suite.h b/content/test/content_test_suite.h index 6a2b94821cb0fb..bff61de5a393af 100644 --- a/content/test/content_test_suite.h +++ b/content/test/content_test_suite.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. @@ -10,6 +10,14 @@ #include "base/test/test_suite.h" #include "base/win/scoped_com_initializer.h" +#if defined(USE_AURA) +namespace aura { +namespace test { +class TestAuraInitializer; +} // namespace test +} // namespace aura +#endif + class ContentTestSuite : public base::TestSuite { public: ContentTestSuite(int argc, char** argv); @@ -21,6 +29,10 @@ class ContentTestSuite : public base::TestSuite { private: base::win::ScopedCOMInitializer com_initializer_; +#if defined(USE_AURA) + scoped_ptr aura_initializer_; +#endif + DISALLOW_COPY_AND_ASSIGN(ContentTestSuite); }; diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index 00e80543e97397..2edd11c415b2c6 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp @@ -19,6 +19,8 @@ '../ui.gyp:gfx_resources', '../ui.gyp:ui', '../ui.gyp:ui_resources', + '../ui.gyp:ui_resources_2x', + '../ui.gyp:ui_resources_standard', ], 'defines': [ 'AURA_IMPLEMENTATION', @@ -130,6 +132,7 @@ '../../testing/gtest.gyp:gtest', '../ui.gyp:ui', 'aura', + 'test_support_aura_pak', ], 'include_dirs': [ '..', @@ -143,6 +146,8 @@ 'test/event_generator.h', 'test/test_activation_client.cc', 'test/test_activation_client.h', + 'test/test_aura_initializer.cc', + 'test/test_aura_initializer.h', 'test/test_event_filter.cc', 'test/test_event_filter.h', 'test/test_screen.cc', @@ -155,6 +160,36 @@ 'test/test_window_delegate.h', ], }, + { + # We build a minimal set of resources required for test_support_aura. + 'target_name': 'test_support_aura_pak', + 'type': 'none', + 'dependencies': [ + '<(DEPTH)/ui/ui.gyp:ui_resources_standard', + ], + 'variables': { + 'repack_path': '<(DEPTH)/tools/grit/grit/format/repack.py', + }, + 'actions': [ + { + 'action_name': 'repack_test_support_aura_pack', + 'variables': { + 'pak_inputs': [ + '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources_standard/ui_resources_standard.pak', + ], + }, + 'inputs': [ + '<(repack_path)', + '<@(pak_inputs)', + ], + 'outputs': [ + '<(PRODUCT_DIR)/test_support_aura_resources.pak', + ], + 'action': ['python', '<(repack_path)', '<@(_outputs)', + '<@(pak_inputs)'], + }, + ], + }, { 'target_name': 'aura_demo', 'type': 'executable', diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc index 83ca3eec18e85d..d9b9cd38d25b16 100644 --- a/ui/aura/root_window_host_linux.cc +++ b/ui/aura/root_window_host_linux.cc @@ -5,6 +5,7 @@ #include "ui/aura/root_window_host_linux.h" #include +#include #include #include #include @@ -14,6 +15,8 @@ #include "base/message_pump_x.h" #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/user_gesture_client.h" #include "ui/aura/dispatcher_linux.h" #include "ui/aura/env.h" @@ -21,10 +24,12 @@ #include "ui/aura/root_window.h" #include "ui/base/cursor/cursor.h" #include "ui/base/keycodes/keyboard_codes.h" +#include "ui/base/resource/resource_bundle.h" #include "ui/base/touch/touch_factory.h" #include "ui/base/view_prop.h" #include "ui/base/x/x11_util.h" #include "ui/compositor/layer.h" +#include "ui/gfx/image/image.h" using std::max; using std::min; @@ -292,6 +297,51 @@ const char* kAtomList[] = { } // namespace +// A utility class that provides X Cursor for NativeCursors for which we have +// image resources. +class RootWindowHostLinux::ImageCursors { + public: + ImageCursors() { + LoadImageCursor(ui::kCursorNoDrop, IDR_AURA_CURSOR_NO_DROP); + LoadImageCursor(ui::kCursorCopy, IDR_AURA_CURSOR_COPY); + // TODO (varunjain): add more cursors once we have assets. + } + + ~ImageCursors() { + std::map::const_iterator it; + for (it = cursors_.begin(); it != cursors_.end(); ++it) + ui::UnrefCustomXCursor(it->second); + } + + // Returns true if we have an image resource loaded for the |native_cursor|. + bool IsImageCursor(gfx::NativeCursor native_cursor) { + return cursors_.find(native_cursor.native_type()) != cursors_.end(); + } + + // Gets the X Cursor corresponding to the |native_cursor|. + ::Cursor ImageCursorFromNative(gfx::NativeCursor native_cursor) { + DCHECK(cursors_.find(native_cursor.native_type()) != cursors_.end()); + return cursors_[native_cursor.native_type()]; + } + + private: + // Creates an X Cursor from an image resource and puts it in the cursor map. + void LoadImageCursor(int id, int resource_id) { + const SkBitmap* bitmap = + ui::ResourceBundle::GetSharedInstance().GetImageNamed( + resource_id).ToSkBitmap(); + + XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap, gfx::Point(0, 0)); + cursors_[id] = ui::CreateReffedCustomXCursor(image); + // |bitmap| is owned by the resource bundle. So we do not need to free it. + } + + // A map to hold all image cursors. It maps the cursor ID to the X Cursor. + std::map cursors_; + + DISALLOW_COPY_AND_ASSIGN(ImageCursors); +}; + RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) : root_window_(NULL), xdisplay_(base::MessagePumpX::GetDefaultXDisplay()), @@ -301,7 +351,8 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) cursor_shown_(true), bounds_(bounds), focus_when_shown_(false), - pointer_barriers_(NULL) { + pointer_barriers_(NULL), + image_cursors_(new ImageCursors) { XSetWindowAttributes swa; memset(&swa, 0, sizeof(swa)); swa.background_pixmap = None; @@ -794,6 +845,8 @@ bool RootWindowHostLinux::IsWindowManagerPresent() { void RootWindowHostLinux::SetCursorInternal(gfx::NativeCursor cursor) { ::Cursor xcursor = + image_cursors_->IsImageCursor(cursor) ? + image_cursors_->ImageCursorFromNative(cursor) : cursor == ui::kCursorNone ? invisible_cursor_ : cursor == ui::kCursorCustom ? diff --git a/ui/aura/root_window_host_linux.h b/ui/aura/root_window_host_linux.h index ae435e98fa7b24..34484e44b61e02 100644 --- a/ui/aura/root_window_host_linux.h +++ b/ui/aura/root_window_host_linux.h @@ -101,6 +101,9 @@ class RootWindowHostLinux : public RootWindowHost, scoped_ptr prop_; + class ImageCursors; + scoped_ptr image_cursors_; + DISALLOW_COPY_AND_ASSIGN(RootWindowHostLinux); }; diff --git a/ui/aura/test/test_aura_initializer.cc b/ui/aura/test/test_aura_initializer.cc new file mode 100644 index 00000000000000..f586d650ffd843 --- /dev/null +++ b/ui/aura/test/test_aura_initializer.cc @@ -0,0 +1,31 @@ +// 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/aura/test/test_aura_initializer.h" + +#include "base/base_paths.h" +#include "base/path_service.h" +#include "ui/base/resource/resource_bundle.h" + +namespace aura { +namespace test { + +TestAuraInitializer::TestAuraInitializer() { +#if defined(OS_LINUX) + FilePath pak_file; + PathService::Get(base::DIR_MODULE, &pak_file); + pak_file = pak_file.Append(FILE_PATH_LITERAL( + "test_support_aura_resources.pak")); + ui::ResourceBundle::InitSharedInstanceWithPakFile(pak_file); +#endif +} + +TestAuraInitializer::~TestAuraInitializer() { +#if defined(OS_LINUX) + ui::ResourceBundle::CleanupSharedInstance(); +#endif +} + +} // namespace test +} // namespace aura diff --git a/ui/aura/test/test_aura_initializer.h b/ui/aura/test/test_aura_initializer.h new file mode 100644 index 00000000000000..cb276ceacb7da0 --- /dev/null +++ b/ui/aura/test/test_aura_initializer.h @@ -0,0 +1,28 @@ +// 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_AURA_TEST_TEST_AURA_INITIALIZER_H_ +#define UI_AURA_TEST_TEST_AURA_INITIALIZER_H_ +#pragma once + +#include "base/basictypes.h" + +namespace aura { +namespace test { + +// Initializes various objects needed to run unit tests that use aura::* +// objects. +class TestAuraInitializer { + public: + TestAuraInitializer(); + virtual ~TestAuraInitializer(); + + private: + DISALLOW_COPY_AND_ASSIGN(TestAuraInitializer); +}; + +} // namespace test +} // namespace aura + +#endif // UI_AURA_TEST_TEST_AURA_INITIALIZER_H_ diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 5df42c04eb09c3..a7b1bc3ad03f90 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -37,6 +37,8 @@ #if defined(USE_AURA) #include +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/skia_util.h" #endif #if defined(TOOLKIT_GTK) @@ -411,6 +413,25 @@ void RefCustomXCursor(::Cursor cursor) { void UnrefCustomXCursor(::Cursor cursor) { XCustomCursorCache::GetInstance()->Unref(cursor); } + +XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap, + const gfx::Point& hotspot) { + DCHECK(bitmap->config() == SkBitmap::kARGB_8888_Config); + XcursorImage* image = XcursorImageCreate(bitmap->width(), bitmap->height()); + image->xhot = hotspot.x(); + image->yhot = hotspot.y(); + + if (bitmap->width() && bitmap->height()) { + bitmap->lockPixels(); + gfx::ConvertSkiaToRGBA( + static_cast(bitmap->getPixels()), + bitmap->width() * bitmap->height(), + reinterpret_cast(image->pixels)); + bitmap->unlockPixels(); + } + + return image; +} #endif XID GetX11RootWindow() { diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 771e8ef3705359..bf89c3bd13297a 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h @@ -18,6 +18,7 @@ #include "base/basictypes.h" #include "ui/base/events.h" #include "ui/base/ui_export.h" +#include "ui/gfx/point.h" typedef unsigned long Atom; typedef unsigned long XID; @@ -35,6 +36,7 @@ typedef struct _GtkWindow GtkWindow; namespace gfx { class Rect; } +class SkBitmap; namespace ui { @@ -89,6 +91,11 @@ UI_EXPORT void RefCustomXCursor(::Cursor cursor); // Decreases the refcount of the custom cursor, and destroys it if it reaches 0. UI_EXPORT void UnrefCustomXCursor(::Cursor cursor); + +// Creates a XcursorImage and copies the SkBitmap |bitmap| on it. |bitmap| +// should be non-null. Caller owns the returned object. +UI_EXPORT XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap, + const gfx::Point& hotspot); #endif // These functions do not cache their results -------------------------- diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc index 1ca139d1ceaf31..da73928384aefe 100644 --- a/ui/gfx/codec/png_codec.cc +++ b/ui/gfx/codec/png_codec.cc @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "base/string_util.h" #include "ui/gfx/size.h" +#include "ui/gfx/skia_util.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkUnPreMultiply.h" #include "third_party/skia/include/core/SkColorPriv.h" @@ -76,25 +77,7 @@ void ConvertSkiatoRGB(const unsigned char* skia, int pixel_width, void ConvertSkiatoRGBA(const unsigned char* skia, int pixel_width, unsigned char* rgba, bool* is_opaque) { - int total_length = pixel_width * 4; - for (int i = 0; i < total_length; i += 4) { - const uint32_t pixel_in = *reinterpret_cast(&skia[i]); - - // Pack the components here. - int alpha = SkGetPackedA32(pixel_in); - if (alpha != 0 && alpha != 255) { - SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); - rgba[i + 0] = SkColorGetR(unmultiplied); - rgba[i + 1] = SkColorGetG(unmultiplied); - rgba[i + 2] = SkColorGetB(unmultiplied); - rgba[i + 3] = alpha; - } else { - rgba[i + 0] = SkGetPackedR32(pixel_in); - rgba[i + 1] = SkGetPackedG32(pixel_in); - rgba[i + 2] = SkGetPackedB32(pixel_in); - rgba[i + 3] = alpha; - } - } + gfx::ConvertSkiaToRGBA(skia, pixel_width, rgba); } } // namespace diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc index bfee3789f24df2..a459cddf944ca5 100644 --- a/ui/gfx/skia_util.cc +++ b/ui/gfx/skia_util.cc @@ -8,6 +8,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColorPriv.h" #include "third_party/skia/include/core/SkShader.h" +#include "third_party/skia/include/core/SkUnPreMultiply.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/gfx/rect.h" @@ -101,4 +102,28 @@ string16 RemoveAcceleratorChar(const string16& s, return accelerator_removed; } +void ConvertSkiaToRGBA(const unsigned char* skia, + int pixel_width, + unsigned char* rgba) { + int total_length = pixel_width * 4; + for (int i = 0; i < total_length; i += 4) { + const uint32_t pixel_in = *reinterpret_cast(&skia[i]); + + // Pack the components here. + int alpha = SkGetPackedA32(pixel_in); + if (alpha != 0 && alpha != 255) { + SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel_in); + rgba[i + 0] = SkColorGetR(unmultiplied); + rgba[i + 1] = SkColorGetG(unmultiplied); + rgba[i + 2] = SkColorGetB(unmultiplied); + rgba[i + 3] = alpha; + } else { + rgba[i + 0] = SkGetPackedR32(pixel_in); + rgba[i + 1] = SkGetPackedG32(pixel_in); + rgba[i + 2] = SkGetPackedB32(pixel_in); + rgba[i + 3] = alpha; + } + } +} + } // namespace gfx diff --git a/ui/gfx/skia_util.h b/ui/gfx/skia_util.h index de7b8f4ac08ba5..152b731c7fa972 100644 --- a/ui/gfx/skia_util.h +++ b/ui/gfx/skia_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. @@ -50,6 +50,11 @@ UI_EXPORT string16 RemoveAcceleratorChar(const string16& s, int* accelerated_char_pos, int* accelerated_char_span); +// Converts Skia ARGB format pixels in |skia| to RGBA. +UI_EXPORT void ConvertSkiaToRGBA(const unsigned char* skia, + int pixel_width, + unsigned char* rgba); + } // namespace gfx #endif // UI_GFX_SKIA_UTIL_H_ diff --git a/ui/resources/ui_resources_2x.grd b/ui/resources/ui_resources_2x.grd index fc13cd62c141d0..f5674d8064296f 100644 --- a/ui/resources/ui_resources_2x.grd +++ b/ui/resources/ui_resources_2x.grd @@ -78,6 +78,8 @@ + + diff --git a/ui/resources/ui_resources_standard.grd b/ui/resources/ui_resources_standard.grd index 926779eb3403f5..d63dc98ab2a7ae 100644 --- a/ui/resources/ui_resources_standard.grd +++ b/ui/resources/ui_resources_standard.grd @@ -75,6 +75,8 @@ + + diff --git a/ui/resources/ui_resources_touch.grd b/ui/resources/ui_resources_touch.grd index 59eb2a2c959bfc..a21b0ce44da94a 100644 --- a/ui/resources/ui_resources_touch.grd +++ b/ui/resources/ui_resources_touch.grd @@ -75,6 +75,8 @@ + + diff --git a/ui/ui.gyp b/ui/ui.gyp index 4f19641d9fc235..5eca3fa9b0fc78 100644 --- a/ui/ui.gyp +++ b/ui/ui.gyp @@ -493,6 +493,7 @@ ], 'link_settings': { 'libraries': [ + '-lXcursor', # For XCursor* function calls in x11_util.cc. '-lXrender', # For XRender* function calls in x11_util.cc. ], }, diff --git a/webkit/glue/webcursor_aurax11.cc b/webkit/glue/webcursor_aurax11.cc index fe221e29f80bd7..b3f69890068827 100644 --- a/webkit/glue/webcursor_aurax11.cc +++ b/webkit/glue/webcursor_aurax11.cc @@ -10,7 +10,6 @@ #include "base/logging.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" -#include "third_party/skia/include/core/SkUnPreMultiply.h" #include "ui/base/cursor/cursor.h" #include "ui/base/x/x11_util.h" @@ -18,35 +17,13 @@ const ui::PlatformCursor WebCursor::GetPlatformCursor() { if (platform_cursor_) return platform_cursor_; - XcursorImage* image = - XcursorImageCreate(custom_size_.width(), custom_size_.height()); - image->xhot = hotspot_.x(); - image->yhot = hotspot_.y(); - uint32* pixels = image->pixels; - - if (custom_size_.width() && custom_size_.height()) { - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - custom_size_.width(), custom_size_.height()); - bitmap.allocPixels(); - memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size()); - - bitmap.lockPixels(); - int height = bitmap.height(), width = bitmap.width(); - for (int y = 0, i = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - uint32 pixel = bitmap.getAddr32(0, y)[x]; - int alpha = SkColorGetA(pixel); - if (alpha != 0 && alpha != 255) - pixels[i] = SkUnPreMultiply::PMColorToColor(pixel); - else - pixels[i] = pixel; - ++i; - } - } - bitmap.unlockPixels(); - } + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + custom_size_.width(), custom_size_.height()); + bitmap.allocPixels(); + memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size()); + XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot_); platform_cursor_ = ui::CreateReffedCustomXCursor(image); return platform_cursor_; }