diff --git a/BUILD.gn b/BUILD.gn index bd6786e..7c9522e 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -284,6 +284,7 @@ "//services:service_junit_tests", "//testing/android/junit:junit_unit_tests", "//third_party/android_async_task:android_async_task_java", + "//third_party/catapult/devil", "//third_party/errorprone:chromium_errorprone", "//third_party/smhasher:murmurhash3", "//tools/android:android_tools",
diff --git a/DEPS b/DEPS index feb40e2b..901fbd31 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'fb49909acafba5e031b90a265a6ce059cda85019', + 'skia_revision': '8744405448b9402e1368aebd321c4f555543301a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '65ef03f8a0fb9bd4f2cfa9afe60ba312cbb3ea08', + 'v8_revision': '71ba1026417321cbdf2bd0f9728a11622a9715e3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'b4eb70c319cb0f38d1a7764e7d9fb56dc96f8bcf', + 'catapult_revision': '3db1a306cf177f6977aee7ba79d6df325b99d052', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc index 9946a8a87..28788566 100644 --- a/apps/app_restore_service_browsertest.cc +++ b/apps/app_restore_service_browsertest.cc
@@ -11,6 +11,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/notification_types.h" #include "extensions/common/extension.h" @@ -20,6 +21,7 @@ using extensions::ExtensionPrefs; using extensions::ExtensionSystem; using extensions::FileSystemChooseEntryFunction; +using extensions::SavedFileEntry; // TODO(benwells): Move PlatformAppBrowserTest to apps namespace in apps // component.
diff --git a/apps/saved_files_service.cc b/apps/saved_files_service.cc index 14e25ff..c2f01d7 100644 --- a/apps/saved_files_service.cc +++ b/apps/saved_files_service.cc
@@ -16,6 +16,7 @@ #include "base/value_conversions.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_service.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" @@ -30,6 +31,7 @@ using extensions::Extension; using extensions::ExtensionHost; using extensions::ExtensionPrefs; +using extensions::SavedFileEntry; namespace { @@ -140,17 +142,6 @@ } // namespace -SavedFileEntry::SavedFileEntry() : is_directory(false), sequence_number(0) {} - -SavedFileEntry::SavedFileEntry(const std::string& id, - const base::FilePath& path, - bool is_directory, - int sequence_number) - : id(id), - path(path), - is_directory(is_directory), - sequence_number(sequence_number) {} - class SavedFilesService::SavedFiles { public: SavedFiles(content::BrowserContext* context, const std::string& extension_id);
diff --git a/apps/saved_files_service.h b/apps/saved_files_service.h index 927f22b..e414e3e 100644 --- a/apps/saved_files_service.h +++ b/apps/saved_files_service.h
@@ -16,6 +16,7 @@ #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "extensions/browser/api/file_system/saved_files_service_interface.h" namespace content { class BrowserContext; @@ -28,38 +29,15 @@ namespace extensions { class Extension; +struct SavedFileEntry; } namespace apps { -// Represents a file entry that a user has given an app permission to -// access. Will be persisted to disk (in the Preferences file), so should remain -// serializable. -struct SavedFileEntry { - SavedFileEntry(); - - SavedFileEntry(const std::string& id, - const base::FilePath& path, - bool is_directory, - int sequence_number); - - // The opaque id of this file entry. - std::string id; - - // The path to a file entry that the app had permission to access. - base::FilePath path; - - // Whether or not the entry refers to a directory. - bool is_directory; - - // The sequence number in the LRU of the file entry. The value 0 indicates - // that the entry is not in the LRU. - int sequence_number; -}; - // Tracks the files that apps have retained access to both while running and // when suspended. -class SavedFilesService : public KeyedService, +class SavedFilesService : public extensions::SavedFilesServiceInterface, + public KeyedService, public content::NotificationObserver { public: explicit SavedFilesService(content::BrowserContext* context); @@ -67,31 +45,21 @@ static SavedFilesService* Get(content::BrowserContext* context); - // Registers a file entry with the saved files service, making it eligible to - // be put into the queue. File entries that are in the retained files queue at - // object construction are automatically registered. + // extensions::SavedFilesServiceInterface: void RegisterFileEntry(const std::string& extension_id, const std::string& id, const base::FilePath& file_path, - bool is_directory); - - // If the file with |id| is not in the queue of files to be retained - // permanently, adds the file to the back of the queue, evicting the least - // recently used entry at the front of the queue if it is full. If it is - // already present, moves it to the back of the queue. The |id| must have been - // registered. - void EnqueueFileEntry(const std::string& extension_id, const std::string& id); - - // Returns whether the file entry with the given |id| has been registered. - bool IsRegistered(const std::string& extension_id, const std::string& id); - - // Gets a borrowed pointer to the file entry with the specified |id|. Returns - // NULL if the file entry has not been registered. - const SavedFileEntry* GetFileEntry(const std::string& extension_id, - const std::string& id); + bool is_directory) override; + void EnqueueFileEntry(const std::string& extension_id, + const std::string& id) override; + bool IsRegistered(const std::string& extension_id, + const std::string& id) override; + const extensions::SavedFileEntry* GetFileEntry( + const std::string& extension_id, + const std::string& id) override; // Returns all registered file entries. - std::vector<SavedFileEntry> GetAllFileEntries( + std::vector<extensions::SavedFileEntry> GetAllFileEntries( const std::string& extension_id); // Clears all retained files if the app does not have the
diff --git a/apps/saved_files_service_unittest.cc b/apps/saved_files_service_unittest.cc index fe215c6..3d7c373c 100644 --- a/apps/saved_files_service_unittest.cc +++ b/apps/saved_files_service_unittest.cc
@@ -11,6 +11,7 @@ #include "base/values.h" #include "chrome/browser/extensions/test_extension_environment.h" #include "chrome/test/base/testing_profile.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" @@ -22,8 +23,8 @@ expression; \ } while (0) -using apps::SavedFileEntry; using apps::SavedFilesService; +using extensions::SavedFileEntry; namespace {
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index 948fb78a..9812cb8 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -11,8 +11,10 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" +#include "ash/shell_port.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_app_list_view_presenter_impl.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/macros.h" @@ -34,6 +36,15 @@ return display::Screen::GetScreen()->GetPrimaryDisplay().id(); } +void SetShelfAlignment(ShelfAlignment alignment) { + test::AshTestBase::GetPrimaryShelf()->SetAlignment(alignment); +} + +void EnableMaximizeMode(bool enable) { + Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + enable); +} + } // namespace class AppListPresenterDelegateTest : public test::AshTestBase, @@ -192,11 +203,260 @@ EXPECT_GE(app_list_view_top, kMinimalAppListMargin); } +// Tests that the app list initializes in fullscreen with side shelf alignment +// and that the state transitions via text input act properly. +TEST_F(AppListPresenterDelegateTest, SideShelfAlignmentTextStateTransitions) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + SetShelfAlignment(ShelfAlignment::SHELF_ALIGNMENT_LEFT); + + // Open the app list with side shelf alignment, then check that it is in + // fullscreen mode. + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_TRUE(app_list->is_fullscreen()); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + // Enter text in the searchbox, the app list should transition to fullscreen + // search. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + + // Delete the text in the searchbox, the app list should transition to + // fullscreen all apps. + generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); +} + +// Tests that the app list initializes in peeking with bottom shelf alignment +// and that the state transitions via text input act properly. +TEST_F(AppListPresenterDelegateTest, BottomShelfAlignmentTextStateTransitions) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_FALSE(app_list->is_fullscreen()); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + + // Enter text in the searchbox, this should transition the app list to half + // state. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Empty the searchbox, this should transition the app list to it's previous + // state. + generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); +} + +// Tests that the app list initializes in fullscreen with maximize mode active +// and that the state transitions via text input act properly. +TEST_F(AppListPresenterDelegateTest, MaximizeModeTextStateTransitions) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + EnableMaximizeMode(true); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + // Enter text in the searchbox, the app list should transition to fullscreen + // search. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + + // Delete the text in the searchbox, the app list should transition to + // fullscreen all apps. generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); +} + +// Tests that the app list state responds correctly to maximize mode being +// enabled while the app list is being shown. +TEST_F(AppListPresenterDelegateTest, + PeekingToFullscreenWhenMaximizeModeIsActive) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + // Enable maximize mode, this should force the app list to switch to the + // fullscreen equivalent of the current state. + EnableMaximizeMode(true); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + // Disable maximize mode, the state of the app list should not change. + EnableMaximizeMode(false); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + // Enter text in the searchbox, the app list should transition to fullscreen + // search. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + + // Delete the text in the searchbox, the app list should transition to + // fullscreen all apps. generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); +} + +// Tests that the app list state responds correctly to maximize mode being +// enabled while the app list is being shown with half launcher. +TEST_F(AppListPresenterDelegateTest, HalfToFullscreenWhenMaximizeModeIsActive) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + + // Enter text in the search box to transition to half app list. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Enable maximize mode and force the app list to transition to the fullscreen + // equivalent of the current state. + EnableMaximizeMode(true); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); +} + +// Tests that the app list view handles drag properly in laptop mode. +TEST_F(AppListPresenterDelegateTest, AppListViewDragHandler) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + + ui::test::EventGenerator& generator = GetEventGenerator(); + // Execute a slow short upwards drag this should fail to transition the app + // list. + int top_of_app_list = app_list_presenter_impl() + ->GetView() + ->GetWidget() + ->GetWindowBoundsInScreen() + .y(); + generator.GestureScrollSequence(gfx::Point(0, top_of_app_list + 20), + gfx::Point(0, top_of_app_list - 20), + base::TimeDelta::FromMilliseconds(500), 50); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + + // Execute a long upwards drag, this should transition the app list. + generator.GestureScrollSequence(gfx::Point(10, top_of_app_list + 20), + gfx::Point(10, 10), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + // Execute a short downward drag, this should fail to transition the app list. + generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 100), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + // Execute a long downward drag, this should transition the app list. + generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 900), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING); + + // Transition to fullscreen. + generator.GestureScrollSequence(gfx::Point(10, top_of_app_list + 20), + gfx::Point(10, 10), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + // Enter text to transition to |FULLSCREEN_SEARCH|. + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + + // Execute a short downward drag, this should fail to close the app list. + generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 100), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + + // Execute a long downward drag, this should close the app list. + generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 900), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED); +} + +// Tests that the app list view handles drag properly in maximize mode. +TEST_F(AppListPresenterDelegateTest, + AppListViewDragHandlerMaximizeModeFromAllApps) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + EnableMaximizeMode(true); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + + ui::test::EventGenerator& generator = GetEventGenerator(); + // Drag down. + generator.GestureScrollSequence(gfx::Point(0, 0), gfx::Point(0, 720), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED); +} + +// Tests that the state of the app list changes properly with drag input from +// fullscreen search. +TEST_F(AppListPresenterDelegateTest, + AppListViewDragHandlerMaximizeModeFromSearch) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + // Reset the app list. + EnableFullscreenAppList(); + EnableMaximizeMode(true); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_ALL_APPS); + // Type in the search box to transition to |FULLSCREEN_SEARCH|. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), + app_list::AppListView::FULLSCREEN_SEARCH); + // Drag down, this should close the app list. + generator.GestureScrollSequence(gfx::Point(0, 0), gfx::Point(0, 720), + base::TimeDelta::FromMilliseconds(100), 10); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED); +} + +// Tests that the bottom shelf background is hidden when the app list is shown +// in laptop mode. +TEST_F(AppListPresenterDelegateTest, + ShelfBackgroundIsHiddenWhenAppListIsShown) { + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + ShelfLayoutManager* shelf_layout_manager = + Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId())) + ->shelf_layout_manager(); + EXPECT_TRUE(shelf_layout_manager->GetShelfBackgroundType() == + ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT); +} + // Tests that the peeking app list closes if the user taps outside its // bounds. TEST_F(AppListPresenterDelegateTest, TapAndClickOutsideClosesPeekingAppList) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 EnableFullscreenAppList(); - app_list_presenter_impl()->Show(GetPrimaryDisplayId()); EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility()); ui::test::EventGenerator& generator = GetEventGenerator(); @@ -262,4 +522,51 @@ SHELF_BACKGROUND_DEFAULT); } +// Tests that the half app list closes if the user taps outside its bounds. +TEST_F(AppListPresenterDelegateTest, TapAndClickOutsideClosesHalfAppList) { + // TODO(newcomer): Investigate mash failures crbug.com/726838 + EnableFullscreenAppList(); + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + ui::test::EventGenerator& generator = GetEventGenerator(); + + // Transition to half app list by entering text. + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Grab the bounds of the search box, + // which is guaranteed to be inside the app list. + gfx::Point tap_point = app_list_presenter_impl() + ->GetView() + ->search_box_widget() + ->GetContentsView() + ->GetBoundsInScreen() + .CenterPoint(); + + // Tapping inside the bounds doesn't close the app list. + generator.GestureTapAt(tap_point); + EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility()); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Clicking inside the bounds doesn't close the app list. + generator.MoveMouseTo(tap_point); + generator.ClickLeftButton(); + EXPECT_TRUE(app_list_presenter_impl()->IsVisible()); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Tapping outside the bounds closes the app list. + generator.GestureTapAt(gfx::Point(10, 10)); + EXPECT_FALSE(app_list_presenter_impl()->IsVisible()); + + // Reset the app list to half state. + app_list_presenter_impl()->Show(GetPrimaryDisplayId()); + generator.PressKey(ui::KeyboardCode::VKEY_0, 0); + EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF); + + // Clicking outside the bounds closes the app list. + generator.MoveMouseTo(gfx::Point(10, 10)); + generator.ClickLeftButton(); + EXPECT_FALSE(app_list_presenter_impl()->IsVisible()); +} + } // namespace ash
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn index 72de32ac..d55c14e 100644 --- a/ash/mus/BUILD.gn +++ b/ash/mus/BUILD.gn
@@ -194,6 +194,7 @@ sources = [ "app_launch_unittest.cc", "bridge/shell_port_mash_test_api.h", + "display_synchronizer_unittest.cc", "non_client_frame_controller_unittest.cc", "top_level_window_factory_unittest.cc", "window_manager_unittest.cc",
diff --git a/ash/mus/display_synchronizer.cc b/ash/mus/display_synchronizer.cc index f948e2f..ca00f7c 100644 --- a/ash/mus/display_synchronizer.cc +++ b/ash/mus/display_synchronizer.cc
@@ -15,10 +15,12 @@ aura::WindowManagerClient* window_manager_client) : window_manager_client_(window_manager_client) { Shell::Get()->window_tree_host_manager()->AddObserver(this); + Shell::Get()->display_manager()->AddObserver(this); SendDisplayConfigurationToServer(); } DisplaySynchronizer::~DisplaySynchronizer() { + Shell::Get()->display_manager()->RemoveObserver(this); Shell::Get()->window_tree_host_manager()->RemoveObserver(this); } @@ -44,6 +46,8 @@ window_manager_client_->SetDisplayConfiguration( displays, std::move(metrics), WindowTreeHostManager::GetPrimaryDisplayId()); + + sent_initial_config_ = true; } void DisplaySynchronizer::OnDisplaysInitialized() { @@ -54,4 +58,15 @@ SendDisplayConfigurationToServer(); } +void DisplaySynchronizer::OnDisplayMetricsChanged( + const display::Display& display, + uint32_t changed_metrics) { + // Changing only the work area doesn't trigger + // OnDisplayConfigurationChanged(). + // Wait for the initial config before sending anything as initial display + // creation may trigger numerous calls to OnDisplayConfigurationChanged(). + if (sent_initial_config_ && changed_metrics == DISPLAY_METRIC_WORK_AREA) + SendDisplayConfigurationToServer(); +} + } // namespace ash
diff --git a/ash/mus/display_synchronizer.h b/ash/mus/display_synchronizer.h index 791fffe3..3428cc53 100644 --- a/ash/mus/display_synchronizer.h +++ b/ash/mus/display_synchronizer.h
@@ -7,6 +7,7 @@ #include "ash/display/window_tree_host_manager.h" #include "base/macros.h" +#include "ui/display/display_observer.h" namespace aura { class WindowManagerClient; @@ -17,7 +18,8 @@ // DisplaySynchronizer keeps the display state in mus in sync with ash's display // state. As ash controls the overall display state this synchronization is one // way (from ash to mus). -class DisplaySynchronizer : public ash::WindowTreeHostManager::Observer { +class DisplaySynchronizer : public WindowTreeHostManager::Observer, + public display::DisplayObserver { public: explicit DisplaySynchronizer( aura::WindowManagerClient* window_manager_client); @@ -30,8 +32,14 @@ void OnDisplaysInitialized() override; void OnDisplayConfigurationChanged() override; + // display::DisplayObserver: + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + aura::WindowManagerClient* window_manager_client_; + bool sent_initial_config_ = false; + DISALLOW_COPY_AND_ASSIGN(DisplaySynchronizer); };
diff --git a/ash/mus/display_synchronizer_unittest.cc b/ash/mus/display_synchronizer_unittest.cc new file mode 100644 index 0000000..7a146e63 --- /dev/null +++ b/ash/mus/display_synchronizer_unittest.cc
@@ -0,0 +1,55 @@ +// Copyright 2017 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 "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/ash_test_helper.h" +#include "ui/aura/test/mus/test_window_manager_client.h" +#include "ui/aura/test/mus/test_window_tree_client_setup.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/insets.h" + +namespace ash { +namespace mus { + +using DisplaySynchronizerTest = test::AshTestBase; + +TEST_F(DisplaySynchronizerTest, ChangingWorkAreaNotifesServer) { + aura::TestWindowManagerClient* test_window_manager_client = + ash_test_helper() + ->window_tree_client_setup() + ->test_window_manager_client(); + const size_t initial_count = + test_window_manager_client->GetChangeCountForType( + aura::WindowManagerClientChangeType::SET_DISPLAY_CONFIGURATION); + gfx::Insets work_area_insets = + display::Screen::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets(); + work_area_insets += gfx::Insets(1); + Shell::Get()->SetDisplayWorkAreaInsets(Shell::GetPrimaryRootWindow(), + work_area_insets); + EXPECT_EQ( + initial_count + 1, + test_window_manager_client->GetChangeCountForType( + aura::WindowManagerClientChangeType::SET_DISPLAY_CONFIGURATION)); +} + +TEST_F(DisplaySynchronizerTest, AddingDisplayNotifies) { + aura::TestWindowManagerClient* test_window_manager_client = + ash_test_helper() + ->window_tree_client_setup() + ->test_window_manager_client(); + const size_t initial_count = + test_window_manager_client->GetChangeCountForType( + aura::WindowManagerClientChangeType::SET_DISPLAY_CONFIGURATION); + UpdateDisplay("400x400,400x400"); + // Multiple calls may be sent, so we only check the count changes. + EXPECT_NE( + initial_count, + test_window_manager_client->GetChangeCountForType( + aura::WindowManagerClientChangeType::SET_DISPLAY_CONFIGURATION)); +} + +} // namespace mus +} // namespace ash
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py index 6269bfb..e7bf827 100755 --- a/build/android/gradle/generate_gradle.py +++ b/build/android/gradle/generate_gradle.py
@@ -44,6 +44,7 @@ # because it has resources as deps of android_apk() rather than using an # android_library() intermediate target. # '//android_webview:system_webview_apk', + '//android_webview/test/embedded_test_server:aw_net_test_support_apk', '//android_webview/test:webview_instrumentation_apk', '//android_webview/test:webview_instrumentation_test_apk', '//base:base_junit_tests',
diff --git a/build/android/pylib/utils/logging_utils.py b/build/android/pylib/utils/logging_utils.py index 41c61338..29c67cb 100644 --- a/build/android/pylib/utils/logging_utils.py +++ b/build/android/pylib/utils/logging_utils.py
@@ -22,7 +22,7 @@ logging.DEBUG: colorama.Fore.CYAN, logging.WARNING: colorama.Fore.YELLOW, logging.ERROR: colorama.Fore.RED, - logging.CRITICAL: colorama.Back.RED + colorama.Style.BRIGHT, + logging.CRITICAL: colorama.Back.RED, } def __init__(self, wrapped_formatter=None):
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 3753483..8574607 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -189,7 +189,10 @@ def ProcessCommonOptions(args): """Processes and handles all common options.""" run_tests_helper.SetLogLevel(args.verbose_count, add_handler=False) - handler = logging_utils.ColorStreamHandler() + if args.verbose_count > 0: + handler = logging_utils.ColorStreamHandler() + else: + handler = logging.StreamHandler(sys.stdout) handler.setFormatter(run_tests_helper.CustomFormatter()) logging.getLogger().addHandler(handler)
diff --git a/build/secondary/third_party/catapult/devil/BUILD.gn b/build/secondary/third_party/catapult/devil/BUILD.gn new file mode 100644 index 0000000..50e6050c --- /dev/null +++ b/build/secondary/third_party/catapult/devil/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2017 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. + +import("//testing/android/empty_apk/empty_apk.gni") + +empty_apk("empty_system_webview_apk") { + package_name = "com.android.webview" + apk_name = "EmptySystemWebView" +} + +group("devil") { + testonly = true + deps = [ + ":empty_system_webview_apk", + "//tools/android/forwarder2", + "//tools/android/md5sum", + ] +}
diff --git a/build/toolchain/mac/compile_xcassets.py b/build/toolchain/mac/compile_xcassets.py index 7e2dbca..1a6e0c6 100644 --- a/build/toolchain/mac/compile_xcassets.py +++ b/build/toolchain/mac/compile_xcassets.py
@@ -68,6 +68,8 @@ continue if 'Error Domain=IBMessageChannelErrorDomain Code=4' in line: continue + if 'Attempting to remove the stale service in order to add' in line: + continue sys.stderr.write(stdout) sys.exit(1)
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 0ffd466..bb6312a 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -778,6 +778,7 @@ "paint/discardable_image_map_unittest.cc", "paint/display_item_list_unittest.cc", "paint/paint_op_buffer_unittest.cc", + "paint/solid_color_analyzer_unittest.cc", "quads/draw_polygon_unittest.cc", "quads/draw_quad_unittest.cc", "quads/nine_patch_generator_unittest.cc",
diff --git a/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/cc/benchmarks/rasterize_and_record_benchmark_impl.cc index 203f770..3052425 100644 --- a/cc/benchmarks/rasterize_and_record_benchmark_impl.cc +++ b/cc/benchmarks/rasterize_and_record_benchmark_impl.cc
@@ -45,8 +45,10 @@ base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval); SkColor color = SK_ColorTRANSPARENT; - *is_solid_color = raster_source->PerformSolidColorAnalysis( - content_rect, contents_scale, &color); + gfx::Rect layer_rect = + gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); + *is_solid_color = + raster_source->PerformSolidColorAnalysis(layer_rect, &color); do { SkBitmap bitmap;
diff --git a/cc/layers/recording_source.cc b/cc/layers/recording_source.cc index e48e0ce..06defb1 100644 --- a/cc/layers/recording_source.cc +++ b/cc/layers/recording_source.cc
@@ -12,6 +12,7 @@ #include "cc/base/region.h" #include "cc/layers/content_layer_client.h" #include "cc/paint/display_item_list.h" +#include "cc/paint/solid_color_analyzer.h" #include "cc/raster/raster_source.h" #include "skia/ext/analysis_canvas.h" @@ -142,15 +143,14 @@ is_solid_color_ = false; solid_color_ = SK_ColorTRANSPARENT; + // TODO(vmpstr): We can probably remove this check. if (!display_list_->ShouldBeAnalyzedForSolidColor()) return; TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount", display_list_->op_count()); - gfx::Size layer_size = GetSize(); - skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height()); - display_list_->Raster(&canvas); - is_solid_color_ = canvas.GetColorIfSolid(&solid_color_); + is_solid_color_ = + display_list_->GetColorIfSolidInRect(gfx::Rect(GetSize()), &solid_color_); } } // namespace cc
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn index baa9458a..57de616 100644 --- a/cc/paint/BUILD.gn +++ b/cc/paint/BUILD.gn
@@ -35,6 +35,8 @@ "record_paint_canvas.h", "skia_paint_canvas.cc", "skia_paint_canvas.h", + "solid_color_analyzer.cc", + "solid_color_analyzer.h", ] defines = [ "CC_PAINT_IMPLEMENTATION=1" ]
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc index a79d886c..8945e5a 100644 --- a/cc/paint/display_item_list.cc +++ b/cc/paint/display_item_list.cc
@@ -15,6 +15,7 @@ #include "cc/base/render_surface_filters.h" #include "cc/debug/picture_debug_util.h" #include "cc/paint/discardable_image_store.h" +#include "cc/paint/solid_color_analyzer.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "ui/gfx/geometry/rect.h" @@ -200,4 +201,23 @@ return record; } +bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect, + SkColor* color) { + std::vector<size_t>* indices_to_use = nullptr; + std::vector<size_t> indices; + if (!rect.Contains(rtree_.GetBounds())) { + indices = rtree_.Search(rect); + indices_to_use = &indices; + } + + base::Optional<SkColor> solid_color = + SolidColorAnalyzer::DetermineIfSolidColor(&paint_op_buffer_, rect, + indices_to_use); + if (solid_color) { + *color = *solid_color; + return true; + } + return false; +} + } // namespace cc
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h index fe3bdc7..e419e04 100644 --- a/cc/paint/display_item_list.h +++ b/cc/paint/display_item_list.h
@@ -138,6 +138,8 @@ // an empty state. sk_sp<PaintRecord> ReleaseAsRecord(); + bool GetColorIfSolidInRect(const gfx::Rect& rect, SkColor* color); + private: FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoOps); FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithOps);
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h index 07e579a..6954892d 100644 --- a/cc/paint/paint_flags.h +++ b/cc/paint/paint_flags.h
@@ -27,6 +27,7 @@ kStroke_Style = SkPaint::kStroke_Style, kStrokeAndFill_Style = SkPaint::kStrokeAndFill_Style, }; + ALWAYS_INLINE bool nothingToDraw() const { return paint_.nothingToDraw(); } ALWAYS_INLINE Style getStyle() const { return static_cast<Style>(paint_.getStyle()); }
diff --git a/cc/paint/solid_color_analyzer.cc b/cc/paint/solid_color_analyzer.cc new file mode 100644 index 0000000..9aac466a --- /dev/null +++ b/cc/paint/solid_color_analyzer.cc
@@ -0,0 +1,255 @@ +// Copyright 2017 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 "cc/paint/solid_color_analyzer.h" + +#include "base/trace_event/trace_event.h" +#include "cc/paint/paint_op_buffer.h" +#include "third_party/skia/include/utils/SkNoDrawCanvas.h" + +namespace cc { +namespace { +const int kMaxOpsToAnalyze = 1; + +bool ActsLikeClear(SkBlendMode mode, unsigned src_alpha) { + switch (mode) { + case SkBlendMode::kClear: + return true; + case SkBlendMode::kSrc: + case SkBlendMode::kSrcIn: + case SkBlendMode::kDstIn: + case SkBlendMode::kSrcOut: + case SkBlendMode::kDstATop: + return src_alpha == 0; + case SkBlendMode::kDstOut: + return src_alpha == 0xFF; + default: + return false; + } +} + +bool IsSolidColor(SkColor color, SkBlendMode blendmode) { + return SkColorGetA(color) == 255 && + (blendmode == SkBlendMode::kSrc || blendmode == SkBlendMode::kSrcOver); +} + +bool IsSolidColorPaint(const PaintFlags& flags) { + SkBlendMode blendmode = flags.getBlendMode(); + + // Paint is solid color if the following holds: + // - Alpha is 1.0, style is fill, and there are no special effects + // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent + // to kSrc if source alpha is 1.0, which is already checked). + return IsSolidColor(flags.getColor(), blendmode) && !flags.HasShader() && + !flags.getLooper() && !flags.getMaskFilter() && + !flags.getColorFilter() && !flags.getImageFilter() && + flags.getStyle() == PaintFlags::kFill_Style; +} + +// Returns true if the specified drawn_rect will cover the entire canvas, and +// that the canvas is not clipped (i.e. it covers ALL of the canvas). +bool IsFullQuad(const SkCanvas& canvas, const SkRect& drawn_rect) { + if (!canvas.isClipRect()) + return false; + + SkIRect clip_irect; + if (!canvas.getDeviceClipBounds(&clip_irect)) + return false; + + // if the clip is smaller than the canvas, we're partly clipped, so abort. + if (!clip_irect.contains(SkIRect::MakeSize(canvas.getBaseLayerSize()))) + return false; + + const SkMatrix& matrix = canvas.getTotalMatrix(); + // If the transform results in a non-axis aligned + // rect, then be conservative and return false. + if (!matrix.rectStaysRect()) + return false; + + SkRect device_rect; + matrix.mapRect(&device_rect, drawn_rect); + SkRect clip_rect; + clip_rect.set(clip_irect); + return device_rect.contains(clip_rect); +} + +void CheckIfSolidColor(const SkCanvas& canvas, + SkColor color, + SkBlendMode blendmode, + bool* is_solid_color, + bool* is_transparent, + SkColor* out_color) { + SkRect rect; + if (!canvas.getLocalClipBounds(&rect)) { + *is_transparent = false; + *is_solid_color = false; + return; + } + + bool does_cover_canvas = IsFullQuad(canvas, rect); + uint8_t alpha = SkColorGetA(color); + if (does_cover_canvas && ActsLikeClear(blendmode, alpha)) + *is_transparent = true; + else if (alpha != 0 || blendmode != SkBlendMode::kSrc) + *is_transparent = false; + + if (does_cover_canvas && IsSolidColor(color, blendmode)) { + *is_solid_color = true; + *out_color = color; + } else { + *is_solid_color = false; + } +} + +void CheckIfSolidRect(const SkCanvas& canvas, + const SkRect& rect, + const PaintFlags& flags, + bool* is_solid_color, + bool* is_transparent, + SkColor* color) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "SolidColorAnalyzer::HandleDrawRect"); + if (flags.nothingToDraw()) + return; + + bool does_cover_canvas = IsFullQuad(canvas, rect); + SkBlendMode blendmode = flags.getBlendMode(); + if (does_cover_canvas && ActsLikeClear(blendmode, flags.getAlpha())) + *is_transparent = true; + else if (flags.getAlpha() != 0 || blendmode != SkBlendMode::kSrc) + *is_transparent = false; + + if (does_cover_canvas && IsSolidColorPaint(flags)) { + *is_solid_color = true; + *color = flags.getColor(); + } else { + *is_solid_color = false; + } +} + +} // namespace + +base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor( + const PaintOpBuffer* buffer, + const gfx::Rect& rect, + const std::vector<size_t>* indices) { + if (buffer->size() == 0 || (indices && indices->empty())) + return SK_ColorTRANSPARENT; + + bool is_solid = false; + bool is_transparent = true; + SkColor color = SK_ColorTRANSPARENT; + + struct Frame { + Frame() = default; + Frame(PaintOpBuffer::Iterator iter, + const SkMatrix& original_ctm, + int save_count) + : iter(iter), original_ctm(original_ctm), save_count(save_count) {} + + PaintOpBuffer::Iterator iter; + const SkMatrix original_ctm; + int save_count = 0; + }; + + SkNoDrawCanvas canvas(rect.width(), rect.height()); + canvas.translate(-rect.x(), -rect.y()); + canvas.clipRect(gfx::RectToSkRect(rect), SkClipOp::kIntersect, false); + + std::vector<Frame> stack; + // We expect to see at least one DrawRecordOp because of the way items are + // constructed. Reserve this to 2, and go from there. + stack.reserve(2); + stack.emplace_back(PaintOpBuffer::Iterator(buffer, indices), + canvas.getTotalMatrix(), canvas.getSaveCount()); + + int num_ops = 0; + while (!stack.empty()) { + auto& frame = stack.back(); + if (!frame.iter) { + canvas.restoreToCount(frame.save_count); + stack.pop_back(); + if (!stack.empty()) + ++stack.back().iter; + continue; + } + + const PaintOp* op = *frame.iter; + const SkMatrix& original_ctm = frame.original_ctm; + switch (op->GetType()) { + case PaintOpType::DrawRecord: { + const DrawRecordOp* record_op = static_cast<const DrawRecordOp*>(op); + stack.emplace_back(PaintOpBuffer::Iterator(record_op->record.get()), + canvas.getTotalMatrix(), canvas.getSaveCount()); + continue; + } + + // Any of the following ops result in non solid content. + case PaintOpType::DrawArc: + case PaintOpType::DrawCircle: + case PaintOpType::DrawDRRect: + case PaintOpType::DrawImage: + case PaintOpType::DrawImageRect: + case PaintOpType::DrawIRect: + case PaintOpType::DrawLine: + case PaintOpType::DrawOval: + case PaintOpType::DrawPath: + case PaintOpType::DrawPosText: + case PaintOpType::DrawRRect: + case PaintOpType::DrawText: + case PaintOpType::DrawTextBlob: + // Anything that has to do a save layer is probably not solid. As it will + // likely need more than one draw op. + // TODO(vmpstr): We could investigate handling these. + case PaintOpType::SaveLayer: + case PaintOpType::SaveLayerAlpha: + // Complex clips will probably result in non solid color as it might not + // cover the canvas. + // TODO(vmpstr): We could investigate handling these. + case PaintOpType::ClipPath: + case PaintOpType::ClipRRect: + return base::nullopt; + + case PaintOpType::DrawRect: { + if (++num_ops > kMaxOpsToAnalyze) + return base::nullopt; + const DrawRectOp* rect_op = static_cast<const DrawRectOp*>(op); + CheckIfSolidRect(canvas, rect_op->rect, rect_op->flags, &is_solid, + &is_transparent, &color); + break; + } + case PaintOpType::DrawColor: { + if (++num_ops > kMaxOpsToAnalyze) + return base::nullopt; + const DrawColorOp* color_op = static_cast<const DrawColorOp*>(op); + CheckIfSolidColor(canvas, color_op->color, color_op->mode, &is_solid, + &is_transparent, &color); + break; + } + + // The rest of the ops should only affect our state canvas. + case PaintOpType::Annotate: + case PaintOpType::ClipRect: + case PaintOpType::Concat: + case PaintOpType::Scale: + case PaintOpType::SetMatrix: + case PaintOpType::Restore: + case PaintOpType::Rotate: + case PaintOpType::Save: + case PaintOpType::Translate: + case PaintOpType::Noop: + op->Raster(&canvas, original_ctm); + break; + } + ++frame.iter; + } + + if (is_transparent) + return SK_ColorTRANSPARENT; + if (is_solid) + return color; + return base::nullopt; +} + +} // namespace cc
diff --git a/cc/paint/solid_color_analyzer.h b/cc/paint/solid_color_analyzer.h new file mode 100644 index 0000000..f0d9f26 --- /dev/null +++ b/cc/paint/solid_color_analyzer.h
@@ -0,0 +1,30 @@ +// Copyright 2017 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 CC_PAINT_SOLID_COLOR_ANALYZER_H_ +#define CC_PAINT_SOLID_COLOR_ANALYZER_H_ + +#include <vector> + +#include "base/optional.h" +#include "cc/paint/paint_export.h" +#include "cc/paint/paint_flags.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/skia_util.h" + +namespace cc { + +class CC_PAINT_EXPORT SolidColorAnalyzer { + public: + SolidColorAnalyzer() = delete; + + static base::Optional<SkColor> DetermineIfSolidColor( + const PaintOpBuffer* buffer, + const gfx::Rect& rect, + const std::vector<size_t>* indices = nullptr); +}; + +} // namespace cc + +#endif // CC_PAINT_SOLID_COLOR_ANALYZER_H_
diff --git a/cc/paint/solid_color_analyzer_unittest.cc b/cc/paint/solid_color_analyzer_unittest.cc new file mode 100644 index 0000000..a56d107 --- /dev/null +++ b/cc/paint/solid_color_analyzer_unittest.cc
@@ -0,0 +1,250 @@ +// Copyright 2017 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 "cc/paint/solid_color_analyzer.h" +#include "base/optional.h" +#include "cc/paint/record_paint_canvas.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/effects/SkOffsetImageFilter.h" +#include "ui/gfx/skia_util.h" + +namespace cc { +namespace { + +class SolidColorAnalyzerTest : public testing::Test { + public: + void SetUp() override {} + + void TearDown() override { + canvas_.reset(); + buffer_.Reset(); + } + + void Initialize(const gfx::Rect& rect = gfx::Rect(0, 0, 100, 100)) { + canvas_.emplace(&buffer_, gfx::RectToSkRect(rect)); + rect_ = rect; + } + RecordPaintCanvas* canvas() { return &*canvas_; } + PaintOpBuffer* paint_op_buffer() { return &buffer_; } + + bool IsSolidColor() { + auto color = + SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, nullptr); + return !!color; + } + + SkColor GetColor() const { + auto color = + SolidColorAnalyzer::DetermineIfSolidColor(&buffer_, rect_, nullptr); + EXPECT_TRUE(color); + return color ? *color : SK_ColorTRANSPARENT; + } + + private: + gfx::Rect rect_; + PaintOpBuffer buffer_; + base::Optional<RecordPaintCanvas> canvas_; + base::Optional<SolidColorAnalyzer> analyzer_; +}; + +TEST_F(SolidColorAnalyzerTest, Empty) { + Initialize(); + EXPECT_EQ(SK_ColorTRANSPARENT, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, ClearTransparent) { + Initialize(); + SkColor color = SkColorSetARGB(0, 12, 34, 56); + canvas()->clear(color); + EXPECT_EQ(SK_ColorTRANSPARENT, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, ClearSolid) { + Initialize(); + SkColor color = SkColorSetARGB(255, 65, 43, 21); + canvas()->clear(color); + EXPECT_EQ(color, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, ClearTranslucent) { + Initialize(); + SkColor color = SkColorSetARGB(128, 11, 22, 33); + canvas()->clear(color); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawColor) { + Initialize(); + SkColor color = SkColorSetARGB(255, 11, 22, 33); + canvas()->drawColor(color); + EXPECT_EQ(color, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawOval) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + canvas()->drawOval(SkRect::MakeWH(100, 100), flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawBitmap) { + Initialize(); + SkBitmap bitmap; + bitmap.allocN32Pixels(16, 16); + canvas()->drawBitmap(bitmap, 0, 0, nullptr); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRect) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->clipRect(rect, SkClipOp::kIntersect, false); + canvas()->drawRect(rect, flags); + EXPECT_EQ(color, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectClipped) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->clipRect(SkRect::MakeWH(50, 50), SkClipOp::kIntersect, false); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateNotSolid) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(100, 100); + canvas()->translate(1, 1); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateSolid) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(101, 101); + canvas()->translate(1, 1); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, TwoOpsNotSolid) { + Initialize(); + SkColor color = SkColorSetARGB(255, 65, 43, 21); + canvas()->clear(color); + canvas()->clear(color); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeClear) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + flags.setBlendMode(SkBlendMode::kClear); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->drawRect(rect, flags); + EXPECT_EQ(SK_ColorTRANSPARENT, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeSrcOver) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + flags.setBlendMode(SkBlendMode::kSrcOver); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->drawRect(rect, flags); + EXPECT_EQ(color, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectRotated) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->rotate(50); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectScaledNotSolid) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->scale(0.1f, 0.1f); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectScaledSolid) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + SkRect rect = SkRect::MakeWH(10, 10); + canvas()->scale(10, 10); + canvas()->drawRect(rect, flags); + EXPECT_EQ(color, GetColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectFilterPaint) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + flags.setImageFilter(SkOffsetImageFilter::Make(10, 10, nullptr)); + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, DrawRectClipPath) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + + SkPath path; + path.moveTo(0, 0); + path.lineTo(128, 50); + path.lineTo(255, 0); + path.lineTo(255, 255); + path.lineTo(0, 255); + + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->clipPath(path, SkClipOp::kIntersect); + canvas()->drawRect(rect, flags); + EXPECT_FALSE(IsSolidColor()); +} + +TEST_F(SolidColorAnalyzerTest, SaveLayer) { + Initialize(); + PaintFlags flags; + SkColor color = SkColorSetARGB(255, 11, 22, 33); + flags.setColor(color); + + SkRect rect = SkRect::MakeWH(200, 200); + canvas()->saveLayer(&rect, &flags); + EXPECT_FALSE(IsSolidColor()); +} + +} // namespace +} // namespace cc
diff --git a/cc/raster/raster_source.cc b/cc/raster/raster_source.cc index 9294cd6..124d5c5 100644 --- a/cc/raster/raster_source.cc +++ b/cc/raster/raster_source.cc
@@ -237,21 +237,12 @@ return display_list_->BytesUsed() + painter_reported_memory_usage_; } -bool RasterSource::PerformSolidColorAnalysis(const gfx::Rect& content_rect, - float contents_scale, +bool RasterSource::PerformSolidColorAnalysis(gfx::Rect layer_rect, SkColor* color) const { TRACE_EVENT0("cc", "RasterSource::PerformSolidColorAnalysis"); - gfx::Rect layer_rect = - gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); - layer_rect.Intersect(gfx::Rect(size_)); - skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); - canvas.translate(-layer_rect.x(), -layer_rect.y()); - // Note that because no color conversion is applied to solid color analysis, - // the resulting solid color will be known to be sRGB. - RasterCommon(&canvas, &canvas); - return canvas.GetColorIfSolid(color); + return display_list_->GetColorIfSolidInRect(layer_rect, color); } void RasterSource::GetDiscardableImagesInRect(
diff --git a/cc/raster/raster_source.h b/cc/raster/raster_source.h index 92e429b..8479de1a 100644 --- a/cc/raster/raster_source.h +++ b/cc/raster/raster_source.h
@@ -89,9 +89,7 @@ // Returns whether the given rect at given scale is of solid color in // this raster source, as well as the solid color value. - bool PerformSolidColorAnalysis(const gfx::Rect& content_rect, - float contents_scale, - SkColor* color) const; + bool PerformSolidColorAnalysis(gfx::Rect content_rect, SkColor* color) const; // Returns true iff the whole raster source is of solid color. bool IsSolidColor() const;
diff --git a/cc/raster/raster_source_unittest.cc b/cc/raster/raster_source_unittest.cc index 5cb06aaf..c75fcb8 100644 --- a/cc/raster/raster_source_unittest.cc +++ b/cc/raster/raster_source_unittest.cc
@@ -53,7 +53,7 @@ for (int y = 0; y <= 300; y += 100) { for (int x = 0; x <= 300; x += 100) { gfx::Rect rect(x, y, 100, 100); - is_solid_color = raster->PerformSolidColorAnalysis(rect, 1.f, &color); + is_solid_color = raster->PerformSolidColorAnalysis(rect, &color); EXPECT_TRUE(is_solid_color) << rect.ToString(); EXPECT_EQ(solid_color, color) << rect.ToString(); } @@ -68,124 +68,35 @@ color = SK_ColorTRANSPARENT; is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), 1.f, &color); + raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), &color); EXPECT_FALSE(is_solid_color); color = SK_ColorTRANSPARENT; - is_solid_color = raster->PerformSolidColorAnalysis( - gfx::Rect(100, 0, 100, 100), 1.f, &color); + is_solid_color = + raster->PerformSolidColorAnalysis(gfx::Rect(100, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color); EXPECT_EQ(solid_color, color); // Boundaries should be clipped. color = SK_ColorTRANSPARENT; - is_solid_color = raster->PerformSolidColorAnalysis( - gfx::Rect(350, 0, 100, 100), 1.f, &color); + is_solid_color = + raster->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), &color); EXPECT_TRUE(is_solid_color); EXPECT_EQ(solid_color, color); color = SK_ColorTRANSPARENT; - is_solid_color = raster->PerformSolidColorAnalysis( - gfx::Rect(0, 350, 100, 100), 1.f, &color); + is_solid_color = + raster->PerformSolidColorAnalysis(gfx::Rect(0, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color); EXPECT_EQ(solid_color, color); color = SK_ColorTRANSPARENT; - is_solid_color = raster->PerformSolidColorAnalysis( - gfx::Rect(350, 350, 100, 100), 1.f, &color); + is_solid_color = + raster->PerformSolidColorAnalysis(gfx::Rect(350, 350, 100, 100), &color); EXPECT_TRUE(is_solid_color); EXPECT_EQ(solid_color, color); } -TEST(RasterSourceTest, AnalyzeIsSolidScaled) { - gfx::Size layer_bounds(400, 400); - - std::unique_ptr<FakeRecordingSource> recording_source = - FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - - SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - SkColor color = SK_ColorTRANSPARENT; - PaintFlags solid_flags; - bool is_solid_color = false; - solid_flags.setColor(solid_color); - - SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67); - PaintFlags non_solid_flags; - non_solid_flags.setColor(non_solid_color); - - recording_source->add_draw_rect_with_flags(gfx::Rect(0, 0, 400, 400), - solid_flags); - recording_source->Rerecord(); - - scoped_refptr<RasterSource> raster = - RasterSource::CreateFromRecordingSource(recording_source.get(), false); - - // Ensure everything is solid. - for (int y = 0; y <= 30; y += 10) { - for (int x = 0; x <= 30; x += 10) { - gfx::Rect rect(x, y, 10, 10); - is_solid_color = raster->PerformSolidColorAnalysis(rect, 0.1f, &color); - EXPECT_TRUE(is_solid_color) << rect.ToString(); - EXPECT_EQ(color, solid_color) << rect.ToString(); - } - } - - // Add one non-solid pixel and recreate the raster source. - recording_source->add_draw_rect_with_flags(gfx::Rect(50, 50, 1, 1), - non_solid_flags); - recording_source->Rerecord(); - raster = - RasterSource::CreateFromRecordingSource(recording_source.get(), false); - - color = SK_ColorTRANSPARENT; - is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 10, 10), 0.1f, &color); - EXPECT_FALSE(is_solid_color); - - color = SK_ColorTRANSPARENT; - is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(10, 0, 10, 10), 0.1f, &color); - EXPECT_TRUE(is_solid_color); - EXPECT_EQ(color, solid_color); - - // Boundaries should be clipped. - color = SK_ColorTRANSPARENT; - is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(35, 0, 10, 10), 0.1f, &color); - EXPECT_TRUE(is_solid_color); - EXPECT_EQ(color, solid_color); - - color = SK_ColorTRANSPARENT; - is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(0, 35, 10, 10), 0.1f, &color); - EXPECT_TRUE(is_solid_color); - EXPECT_EQ(color, solid_color); - - color = SK_ColorTRANSPARENT; - is_solid_color = raster->PerformSolidColorAnalysis(gfx::Rect(35, 35, 10, 10), - 0.1f, &color); - EXPECT_TRUE(is_solid_color); - EXPECT_EQ(color, solid_color); -} - -TEST(RasterSourceTest, AnalyzeIsSolidEmpty) { - gfx::Size layer_bounds(400, 400); - - std::unique_ptr<FakeRecordingSource> recording_source = - FakeRecordingSource::CreateFilledRecordingSource(layer_bounds); - recording_source->Rerecord(); - - scoped_refptr<RasterSource> raster = - RasterSource::CreateFromRecordingSource(recording_source.get(), false); - - SkColor color = SK_ColorTRANSPARENT; - bool is_solid_color = - raster->PerformSolidColorAnalysis(gfx::Rect(0, 0, 400, 400), 1.f, &color); - - EXPECT_TRUE(is_solid_color); - EXPECT_EQ(color, SkColorSetARGB(0, 0, 0, 0)); -} - TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { gfx::Size layer_bounds(512, 512);
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc index 2e78129..d9a680d6 100644 --- a/cc/tiles/tile_manager.cc +++ b/cc/tiles/tile_manager.cc
@@ -685,11 +685,9 @@ // canvas which is reset between tiles. tile->set_solid_color_analysis_performed(true); SkColor color = SK_ColorTRANSPARENT; - gfx::RectF layer_rect = tile->raster_transform().InverseMapRect( - gfx::RectF(tile->content_rect())); bool is_solid_color = prioritized_tile.raster_source()->PerformSolidColorAnalysis( - gfx::ToEnclosingRect(layer_rect), 1.f, &color); + tile->enclosing_layer_rect(), &color); if (is_solid_color) { tile->draw_info().set_solid_color(color); client_->NotifyTileStateChanged(tile);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java index 6d265c65..f74c4f7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -78,6 +78,7 @@ private boolean mSearchEnginePromoCompleted; private boolean mSearchEnginePromoShownThisSession; + private boolean mSearchEnginePromoCheckedThisSession; // LocaleManager is a singleton and it should not have strong reference to UI objects. // SnackbarManager is owned by ChromeActivity and is not null as long as the activity is alive. @@ -244,8 +245,15 @@ final Activity activity, final @Nullable Callback<Boolean> onSearchEngineFinalized) { assert TemplateUrlService.getInstance().isLoaded(); + final Callback<Boolean> finalizeInternalCallback = new Callback<Boolean>() { + @Override + public void onResult(Boolean result) { + if (result != null && result) mSearchEnginePromoCheckedThisSession = true; + if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(result); + } + }; if (TemplateUrlService.getInstance().isDefaultSearchManaged()) { - if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(true); + finalizeInternalCallback.onResult(true); return; } @@ -253,14 +261,14 @@ Callable<PromoDialog> dialogCreator; switch (shouldShow) { case SEARCH_ENGINE_PROMO_DONT_SHOW: - if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(true); + finalizeInternalCallback.onResult(true); return; case SEARCH_ENGINE_PROMO_SHOW_SOGOU: dialogCreator = new Callable<PromoDialog>() { @Override public PromoDialog call() throws Exception { return new SogouPromoDialog( - activity, LocaleManager.this, onSearchEngineFinalized); + activity, LocaleManager.this, finalizeInternalCallback); } }; break; @@ -270,20 +278,20 @@ @Override public PromoDialog call() throws Exception { return new DefaultSearchEnginePromoDialog( - activity, shouldShow, onSearchEngineFinalized); + activity, shouldShow, finalizeInternalCallback); } }; break; default: assert false; - if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(true); + finalizeInternalCallback.onResult(true); return; } // If the activity has been destroyed by the time the TemplateUrlService has // loaded, then do not attempt to show the dialog. if (ApplicationStatus.getStateForActivity(activity) == ActivityState.DESTROYED) { - if (onSearchEngineFinalized != null) onSearchEngineFinalized.onResult(false); + finalizeInternalCallback.onResult(false); return; } @@ -466,7 +474,7 @@ } finally { StrictMode.setThreadPolicy(oldPolicy); } - return state == SEARCH_ENGINE_PROMO_SHOULD_CHECK; + return !mSearchEnginePromoCheckedThisSession && state == SEARCH_ENGINE_PROMO_SHOULD_CHECK; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java index a64514d..26e30c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.tab; -import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; @@ -25,10 +24,6 @@ * Class that controls navigations and allows to intercept them. It is used on Android to 'convert' * certain navigations to Intents to 3rd party applications and to "pause" navigations when data use * tracking has ended. - * Note the Intent is often created together with a new empty tab which then shoud be closed - * immediately. This task of closing tab should be done in an asynchrnous fashion by posting - * the task onto UI thread again to avoid accessing the WebContents and the associated objects - * afterwards since they will have been destroyed as well. see https://crbug.com/732260. */ public class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate { private final Tab mTab; @@ -248,14 +243,7 @@ // crbug.com/487938. mTab.getActivity().moveTaskToBack(false); } - // Defer closing a tab (and the associated WebContents) till the navigation - // request and the throttle finishes the job with it. - ThreadUtils.postOnUiThread(new Runnable() { - @Override - public void run() { - mTab.getTabModelSelector().closeTab(mTab); - } - }); + mTab.getTabModelSelector().closeTab(mTab); } else if (mTab.getTabRedirectHandler().isOnNavigation()) { int lastCommittedEntryIndexBeforeNavigation = mTab.getTabRedirectHandler() .getLastCommittedEntryIndexBeforeStartingNavigation();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java index ace20d0..e691062 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
@@ -17,7 +17,7 @@ * Performs native VrShell initialization. */ void initializeNative( - Tab currentTab, boolean forWebVr, boolean webVrAutopresented, boolean inCct); + Tab currentTab, boolean forWebVr, boolean webVrAutopresentationExpected, boolean inCct); /** * Pauses VrShell. @@ -38,7 +38,7 @@ * Sets whether we're presenting WebVR content or not. */ // TODO: Refactor needed. See crbug.com/735169. - void setWebVrModeEnabled(boolean enabled, boolean autoPresented, boolean showToast); + void setWebVrModeEnabled(boolean enabled, boolean showToast); /** * Returns true if we're presenting WebVR content.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java index 8f5cbecf..4b44c09 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -580,14 +580,18 @@ return false; } - if (mListeningForWebVrActivateBeforePause && !mRequestedWebVr) { + // If the page is listening for vrdisplayactivate we assume it wants to request + // presentation. Go into WebVR mode tentatively. If the page doesn't request presentation + // in the vrdisplayactivate handler we will exit presentation later. Note that in the + // case of autopresentation, we don't want to enter WebVR mode so that we can show the + // splash screen. In this case, we enter WebVR mode when the site requests presentation. + boolean tentativeWebVrMode = + mListeningForWebVrActivateBeforePause && !mRequestedWebVr && !mAutopresentWebVr; + if (tentativeWebVrMode) { nativeDisplayActivate(mNativeVrShellDelegate); } - // If the page is listening for vrdisplayactivate we assume it wants to request - // presentation. Go into WebVR mode tentatively. If the page doesn't request presentation - // in the vrdisplayactivate handler we will exit presentation later. - enterVr(mListeningForWebVrActivateBeforePause && !mRequestedWebVr); + enterVr(tentativeWebVrMode); // The user has successfully completed a DON flow. RecordUserAction.record("VR.DON"); @@ -648,11 +652,10 @@ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); addVrViews(); - boolean webVrMode = mRequestedWebVr || tentativeWebVrMode; + boolean webVrMode = mRequestedWebVr || tentativeWebVrMode && !mAutopresentWebVr; mVrShell.initializeNative(mActivity.getActivityTab(), webVrMode, mAutopresentWebVr, mActivity instanceof CustomTabActivity); - mVrShell.setWebVrModeEnabled(webVrMode, mAutopresentWebVr, false); - mAutopresentWebVr = false; + mVrShell.setWebVrModeEnabled(webVrMode, false); // We're entering VR, but not in WebVr mode. mVrBrowserUsed = !webVrMode; @@ -676,6 +679,7 @@ // we're not in vr. assert !mInVr; mAutopresentWebVr = true; + mDonSucceeded = true; } /** @@ -748,7 +752,7 @@ mRequestedWebVr = true; switch (enterVrInternal()) { case ENTER_VR_NOT_NECESSARY: - mVrShell.setWebVrModeEnabled(true, mAutopresentWebVr, true); + mVrShell.setWebVrModeEnabled(true, true); maybeSetPresentResult(true); break; case ENTER_VR_CANCELLED: @@ -762,6 +766,7 @@ default: Log.e(TAG, "Unexpected enum."); } + mAutopresentWebVr = false; } /** @@ -803,7 +808,7 @@ } else { mVrBrowserUsed = true; mAutopresentWebVr = false; - mVrShell.setWebVrModeEnabled(false, false, false); + mVrShell.setWebVrModeEnabled(false, false); } return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java index 6b69793..a6c2d01 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -5,8 +5,12 @@ package org.chromium.chrome.browser.vr_shell; import android.annotation.SuppressLint; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; import android.os.StrictMode; import android.view.MotionEvent; import android.view.Surface; @@ -20,10 +24,12 @@ import com.google.vr.ndk.base.AndroidCompat; import com.google.vr.ndk.base.GvrLayout; +import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.NativePage; @@ -209,8 +215,7 @@ } @Override - public void onWebContentsSwapped( - Tab tab, boolean didStartLoad, boolean didFinishLoad) { + public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) { onContentChanged(tab); } @@ -310,14 +315,39 @@ addView(mRenderToSurfaceLayoutParent); } + private void setSplashScreenIcon() { + new AsyncTask<Void, Void, Bitmap>() { + @Override + protected Bitmap doInBackground(Void... params) { + Drawable drawable = ApiCompatibilityUtils.getDrawable( + mActivity.getResources(), R.mipmap.app_icon); + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bd = (BitmapDrawable) drawable; + return bd.getBitmap(); + } + assert false : "The drawable was not a bitmap drawable as expected"; + return null; + } + @Override + protected void onPostExecute(Bitmap bitmap) { + nativeSetSplashScreenIcon(mNativeVrShell, bitmap); + } + } + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + @Override - public void initializeNative( - Tab currentTab, boolean forWebVr, boolean webVrAutopresented, boolean inCct) { + public void initializeNative(Tab currentTab, boolean forWebVr, + boolean webVrAutopresentationExpected, boolean inCct) { mContentVrWindowAndroid = new VrWindowAndroid(mActivity, mContentVirtualDisplay); mNativeVrShell = nativeInit(mDelegate, mContentVrWindowAndroid.getNativePointer(), forWebVr, - webVrAutopresented, inCct, getGvrApi().getNativeGvrContext(), + webVrAutopresentationExpected, inCct, getGvrApi().getNativeGvrContext(), mReprojectedRendering); + // We need to set the icon bitmap from here because we can't read the app icon from native + // code. + setSplashScreenIcon(); + // Set the UI and content sizes before we load the UI. updateWebVrDisplaySize(forWebVr); @@ -538,10 +568,9 @@ } @Override - public void setWebVrModeEnabled(boolean enabled, boolean autoPresented, boolean showToast) { + public void setWebVrModeEnabled(boolean enabled, boolean showToast) { mContentVrWindowAndroid.setVSyncPaused(enabled); - nativeSetWebVrMode(mNativeVrShell, enabled, autoPresented, showToast); - + nativeSetWebVrMode(mNativeVrShell, enabled, showToast); updateWebVrDisplaySize(enabled); } @@ -706,9 +735,10 @@ } private native long nativeInit(VrShellDelegate delegate, long nativeWindowAndroid, - boolean forWebVR, boolean webVRAutopresented, boolean inCct, long gvrApi, + boolean forWebVR, boolean webVrAutopresentationExpected, boolean inCct, long gvrApi, boolean reprojectedRendering); private native void nativeSetSurface(long nativeVrShell, Surface surface); + private native void nativeSetSplashScreenIcon(long nativeVrShell, Bitmap bitmap); private native void nativeSwapContents( long nativeVrShell, WebContents webContents, MotionEventSynthesizer eventSynthesizer); private native void nativeDestroy(long nativeVrShell); @@ -720,8 +750,7 @@ long nativeVrShell, WebContents webContents, int width, int height); private native void nativeContentPhysicalBoundsChanged(long nativeVrShell, int width, int height, float dpr); - private native void nativeSetWebVrMode( - long nativeVrShell, boolean enabled, boolean autoPresented, boolean showToast); + private native void nativeSetWebVrMode(long nativeVrShell, boolean enabled, boolean showToast); private native boolean nativeGetWebVrMode(long nativeVrShell); private native void nativeOnTabListCreated(long nativeVrShell, Tab[] mainTabs, Tab[] incognitoTabs);
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn index 36f0663..d4e01f1 100644 --- a/chrome/browser/android/vr_shell/BUILD.gn +++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -48,6 +48,8 @@ "textures/presentation_toast_texture.h", "textures/render_text_wrapper.cc", "textures/render_text_wrapper.h", + "textures/splash_screen_icon_texture.cc", + "textures/splash_screen_icon_texture.h", "textures/system_indicator_texture.cc", "textures/system_indicator_texture.h", "textures/ui_texture.cc", @@ -71,6 +73,8 @@ "ui_elements/presentation_toast.h", "ui_elements/screen_dimmer.cc", "ui_elements/screen_dimmer.h", + "ui_elements/splash_screen_icon.cc", + "ui_elements/splash_screen_icon.h", "ui_elements/system_indicator.cc", "ui_elements/system_indicator.h", "ui_elements/textured_element.cc",
diff --git a/chrome/browser/android/vr_shell/color_scheme.cc b/chrome/browser/android/vr_shell/color_scheme.cc index 01f1941..5545ecd 100644 --- a/chrome/browser/android/vr_shell/color_scheme.cc +++ b/chrome/browser/android/vr_shell/color_scheme.cc
@@ -67,6 +67,7 @@ normal_scheme.disabled = 0x33333333; normal_scheme.dimmer_inner = 0xCC0D0D0D; normal_scheme.dimmer_outer = 0xE6000000; + normal_scheme.splash_screen_background = SK_ColorBLACK; kColorSchemes[ColorScheme::kModeFullscreen] = kColorSchemes[ColorScheme::kModeNormal]; @@ -121,6 +122,7 @@ incognito_scheme.prompt_button_background_hover = 0xFF8C8C8C; incognito_scheme.prompt_button_background_down = 0xE6FFFFFF; incognito_scheme.disabled = 0x33E6E6E6; + incognito_scheme.splash_screen_background = SK_ColorBLACK; initialized = true; }
diff --git a/chrome/browser/android/vr_shell/color_scheme.h b/chrome/browser/android/vr_shell/color_scheme.h index c943841..b6516343 100644 --- a/chrome/browser/android/vr_shell/color_scheme.h +++ b/chrome/browser/android/vr_shell/color_scheme.h
@@ -78,6 +78,9 @@ // Screen dimmer colors. SkColor dimmer_outer; SkColor dimmer_inner; + + // Splash screen colors. + SkColor splash_screen_background; }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.cc b/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.cc new file mode 100644 index 0000000..6bc62a4 --- /dev/null +++ b/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.cc
@@ -0,0 +1,38 @@ +// Copyright 2017 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 "chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h" + +#include "ui/gfx/canvas.h" + +namespace vr_shell { + +SplashScreenIconTexture::SplashScreenIconTexture() = default; + +SplashScreenIconTexture::~SplashScreenIconTexture() = default; + +void SplashScreenIconTexture::SetSplashScreenIconBitmap( + const SkBitmap& bitmap) { + splash_screen_icon_ = SkImage::MakeFromBitmap(bitmap); + set_dirty(); +} + +void SplashScreenIconTexture::Draw(SkCanvas* sk_canvas, + const gfx::Size& texture_size) { + size_.set_width(texture_size.width()); + size_.set_height(texture_size.height()); + + sk_canvas->drawImage(splash_screen_icon_, 0, 0); +} + +gfx::Size SplashScreenIconTexture::GetPreferredTextureSize( + int maximum_width) const { + return gfx::Size(maximum_width, maximum_width); +} + +gfx::SizeF SplashScreenIconTexture::GetDrawnSize() const { + return size_; +} + +} // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h b/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h new file mode 100644 index 0000000..d2a4959 --- /dev/null +++ b/chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h
@@ -0,0 +1,34 @@ +// Copyright 2017 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 CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SPLASH_SCREEN_ICON_TEXTURE_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SPLASH_SCREEN_ICON_TEXTURE_H_ + +#include "base/macros.h" +#include "chrome/browser/android/vr_shell/textures/ui_texture.h" +#include "third_party/skia/include/core/SkImage.h" + +namespace vr_shell { + +class SplashScreenIconTexture : public UiTexture { + public: + SplashScreenIconTexture(); + ~SplashScreenIconTexture() override; + gfx::Size GetPreferredTextureSize(int width) const override; + gfx::SizeF GetDrawnSize() const override; + + void SetSplashScreenIconBitmap(const SkBitmap& bitmap); + + private: + void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override; + + sk_sp<SkImage> splash_screen_icon_; + gfx::SizeF size_; + + DISALLOW_COPY_AND_ASSIGN(SplashScreenIconTexture); +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_SPLASH_SCREEN_ICON_TEXTURE_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc new file mode 100644 index 0000000..dc67480 --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.cc
@@ -0,0 +1,27 @@ +// Copyright 2017 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 "chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h" + +#include "base/memory/ptr_util.h" +#include "chrome/browser/android/vr_shell/textures/splash_screen_icon_texture.h" + +namespace vr_shell { + +SplashScreenIcon::SplashScreenIcon(int preferred_width) + : TexturedElement(preferred_width), + texture_(base::MakeUnique<SplashScreenIconTexture>()) {} + +SplashScreenIcon::~SplashScreenIcon() = default; + +void SplashScreenIcon::SetSplashScreenIconBitmap(const SkBitmap& bitmap) { + texture_->SetSplashScreenIconBitmap(bitmap); + UpdateTexture(); +} + +UiTexture* SplashScreenIcon::GetTexture() const { + return texture_.get(); +} + +} // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h new file mode 100644 index 0000000..feaf6be --- /dev/null +++ b/chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h
@@ -0,0 +1,36 @@ +// Copyright 2017 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 CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_ +#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_ + +#include <memory> + +#include "base/macros.h" +#include "chrome/browser/android/vr_shell/ui_elements/textured_element.h" + +class SkBitmap; + +namespace vr_shell { + +class SplashScreenIconTexture; + +class SplashScreenIcon : public TexturedElement { + public: + explicit SplashScreenIcon(int preferred_width); + ~SplashScreenIcon() override; + + void SetSplashScreenIconBitmap(const SkBitmap& bitmap); + + private: + UiTexture* GetTexture() const override; + + std::unique_ptr<SplashScreenIconTexture> texture_; + + DISALLOW_COPY_AND_ASSIGN(SplashScreenIcon); +}; + +} // namespace vr_shell + +#endif // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_SPLASH_SCREEN_ICON_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h b/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h index 9f1a13e..26c2f6a7 100644 --- a/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h +++ b/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h
@@ -30,6 +30,7 @@ kTransientUrlBar, kLocationAccessIndicator, kPresentationToast, + kSplashScreenIcon, }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_interface.h b/chrome/browser/android/vr_shell/ui_interface.h index 1a0f0c6..f8904642 100644 --- a/chrome/browser/android/vr_shell/ui_interface.h +++ b/chrome/browser/android/vr_shell/ui_interface.h
@@ -8,6 +8,7 @@ #include "components/security_state/core/security_state.h" class GURL; +class SkBitmap; namespace vr_shell { @@ -25,9 +26,7 @@ virtual ~UiInterface() {} - virtual void SetWebVrMode(bool enabled, - bool auto_presented, - bool show_toast) = 0; + virtual void SetWebVrMode(bool enabled, bool show_toast) = 0; virtual void SetURL(const GURL& url) = 0; virtual void SetFullscreen(bool enabled) = 0; virtual void SetSecurityInfo(security_state::SecurityLevel level, @@ -42,6 +41,7 @@ virtual void SetVideoCapturingIndicator(bool enabled) = 0; virtual void SetScreenCapturingIndicator(bool enabled) = 0; virtual void SetAudioCapturingIndicator(bool enabled) = 0; + virtual void SetSplashScreenIcon(const SkBitmap& bitmap) = 0; // Tab handling. virtual void InitTabList() {}
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc index 1df212c..5956b75 100644 --- a/chrome/browser/android/vr_shell/ui_scene.cc +++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -188,7 +188,9 @@ } SkColor UiScene::GetWorldBackgroundColor() const { - return ColorScheme::GetColorScheme(mode_).world_background; + return showing_splash_screen_ + ? ColorScheme::GetColorScheme(mode_).splash_screen_background + : ColorScheme::GetColorScheme(mode_).world_background; } void UiScene::SetBackgroundDistance(float distance) { @@ -215,6 +217,10 @@ is_prompting_to_exit_ = prompting; } +void UiScene::set_showing_splash_screen(bool showing) { + showing_splash_screen_ = showing; +} + const std::vector<std::unique_ptr<UiElement>>& UiScene::GetUiElements() const { return ui_elements_; }
diff --git a/chrome/browser/android/vr_shell/ui_scene.h b/chrome/browser/android/vr_shell/ui_scene.h index df949d2c..12bf9df 100644 --- a/chrome/browser/android/vr_shell/ui_scene.h +++ b/chrome/browser/android/vr_shell/ui_scene.h
@@ -80,8 +80,10 @@ bool is_exiting() const { return is_exiting_; } void set_is_exiting(); - bool is_prompting_to_exit() { return is_prompting_to_exit_; } + bool is_prompting_to_exit() const { return is_prompting_to_exit_; } void set_is_prompting_to_exit(bool prompting); + bool showing_splash_screen() const { return showing_splash_screen_; } + void set_showing_splash_screen(bool showing); void OnGLInitialized(); @@ -98,6 +100,7 @@ bool gl_initialized_ = false; bool is_exiting_ = false; bool is_prompting_to_exit_ = false; + bool showing_splash_screen_ = false; DISALLOW_COPY_AND_ASSIGN(UiScene); };
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index 22580916..5bc2200 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/android/vr_shell/ui_elements/permanent_security_warning.h" #include "chrome/browser/android/vr_shell/ui_elements/presentation_toast.h" #include "chrome/browser/android/vr_shell/ui_elements/screen_dimmer.h" +#include "chrome/browser/android/vr_shell/ui_elements/splash_screen_icon.h" #include "chrome/browser/android/vr_shell/ui_elements/system_indicator.h" #include "chrome/browser/android/vr_shell/ui_elements/transient_security_warning.h" #include "chrome/browser/android/vr_shell/ui_elements/transient_url_bar.h" @@ -89,6 +90,15 @@ static constexpr float kToastHeight = 0.16 * kToastDistance; static constexpr int kToastTimeoutSeconds = kTransientUrlBarTimeoutSeconds; +static constexpr float kSplashScreenDistance = 1; +static constexpr float kSplashScreenIconDMM = 0.12; +static constexpr float kSplashScreenIconHeight = + kSplashScreenIconDMM * kSplashScreenDistance; +static constexpr float kSplashScreenIconWidth = + kSplashScreenIconDMM * kSplashScreenDistance; +static constexpr float kSplashScreenIconVerticalOffset = + 0.2 * kSplashScreenDistance; + static constexpr float kCloseButtonDistance = 2.4; static constexpr float kCloseButtonHeight = kUrlBarHeightDMM * kCloseButtonDistance; @@ -122,13 +132,14 @@ UiScene* scene, bool in_cct, bool in_web_vr, - bool web_vr_autopresented) + bool web_vr_autopresentation_expected) : browser_(browser), scene_(scene), in_cct_(in_cct), web_vr_mode_(in_web_vr), - web_vr_autopresented_(web_vr_autopresented), + web_vr_autopresentation_expected_(web_vr_autopresentation_expected), weak_ptr_factory_(this) { + CreateSplashScreen(); CreateBackground(); CreateContentQuad(); CreateSecurityWarnings(); @@ -142,7 +153,6 @@ ConfigureScene(); ConfigureSecurityWarnings(); - ConfigureTransientUrlBar(); } UiSceneManager::~UiSceneManager() {} @@ -276,6 +286,20 @@ -kBackgroundDistanceMultiplier); } +void UiSceneManager::CreateSplashScreen() { + // Chrome icon. + std::unique_ptr<SplashScreenIcon> icon = + base::MakeUnique<SplashScreenIcon>(256); + icon->set_debug_id(kSplashScreenIcon); + icon->set_id(AllocateId()); + icon->set_hit_testable(false); + icon->set_size({kSplashScreenIconWidth, kSplashScreenIconHeight, 1.0}); + icon->set_translation( + {0, kSplashScreenIconVerticalOffset, -kSplashScreenDistance}); + splash_screen_icon_ = icon.get(); + scene_->AddUiElement(std::move(icon)); +} + void UiSceneManager::CreateBackground() { std::unique_ptr<UiElement> element; @@ -423,49 +447,55 @@ return weak_ptr_factory_.GetWeakPtr(); } -void UiSceneManager::SetWebVrMode(bool web_vr, - bool auto_presented, - bool show_toast) { - if (web_vr_mode_ == web_vr && web_vr_autopresented_ == auto_presented && - web_vr_show_toast_ == show_toast) { +void UiSceneManager::SetWebVrMode(bool web_vr, bool show_toast) { + if (web_vr_mode_ == web_vr && web_vr_show_toast_ == show_toast) { return; } web_vr_mode_ = web_vr; - web_vr_autopresented_ = auto_presented; + ConfigureTransientUrlBar(); + scene_->set_showing_splash_screen(false); + web_vr_autopresentation_expected_ = false; web_vr_show_toast_ = show_toast; toast_state_ = SET_FOR_WEB_VR; ConfigureScene(); ConfigureSecurityWarnings(); - ConfigureTransientUrlBar(); ConfigurePresentationToast(); } void UiSceneManager::ConfigureScene() { + // Splash screen. + scene_->set_showing_splash_screen(web_vr_autopresentation_expected_); + splash_screen_icon_->SetEnabled(!web_vr_mode_ && + web_vr_autopresentation_expected_); + + // Exit warning. exit_warning_->SetEnabled(scene_->is_exiting()); screen_dimmer_->SetEnabled(scene_->is_exiting()); + bool browsing_mode = !web_vr_mode_ && !scene_->showing_splash_screen(); + // Controls (URL bar, loading progress, etc). - bool controls_visible = !web_vr_mode_ && !fullscreen_; + bool controls_visible = browsing_mode && !fullscreen_; for (UiElement* element : control_elements_) { element->SetEnabled(controls_visible && !scene_->is_prompting_to_exit()); } // Close button is a special control element that needs to be hidden when in // WebVR, but it needs to be visible when in cct or fullscreen. - close_button_->SetEnabled(!web_vr_mode_ && (fullscreen_ || in_cct_)); + close_button_->SetEnabled(browsing_mode && (fullscreen_ || in_cct_)); // Content elements. for (UiElement* element : content_elements_) { - element->SetEnabled(!web_vr_mode_ && !scene_->is_prompting_to_exit()); + element->SetEnabled(browsing_mode && !scene_->is_prompting_to_exit()); } // Background elements. for (UiElement* element : background_elements_) { - element->SetEnabled(!web_vr_mode_); + element->SetEnabled(browsing_mode); } // Exit prompt. - bool showExitPrompt = !web_vr_mode_ && scene_->is_prompting_to_exit(); + bool showExitPrompt = browsing_mode && scene_->is_prompting_to_exit(); exit_prompt_->SetEnabled(showExitPrompt); exit_prompt_backplane_->SetEnabled(showExitPrompt); @@ -518,6 +548,11 @@ floor_->set_grid_color(color_scheme().floor_grid); } +void UiSceneManager::SetSplashScreenIcon(const SkBitmap& bitmap) { + splash_screen_icon_->SetSplashScreenIconBitmap(bitmap); + ConfigureScene(); +} + void UiSceneManager::SetAudioCapturingIndicator(bool enabled) { audio_capturing_ = enabled; ConfigureIndicators(); @@ -647,7 +682,7 @@ } void UiSceneManager::ConfigureTransientUrlBar() { - bool enabled = web_vr_mode_ && web_vr_autopresented_; + bool enabled = web_vr_mode_ && web_vr_autopresentation_expected_; transient_url_bar_->set_visible(enabled); if (enabled) { transient_url_bar_timer_.Start(
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h index a330af6..105bc2a 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.h +++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -13,10 +13,12 @@ #include "chrome/browser/android/vr_shell/color_scheme.h" #include "chrome/browser/android/vr_shell/ui_interface.h" #include "chrome/browser/android/vr_shell/ui_unsupported_mode.h" +#include "third_party/skia/include/core/SkBitmap.h" namespace vr_shell { class LoadingIndicator; +class SplashScreenIcon; class TransientUrlBar; class UiBrowserInterface; class UiElement; @@ -29,7 +31,7 @@ UiScene* scene, bool in_cct, bool in_web_vr, - bool web_vr_autopresented); + bool web_vr_autopresentation_expected); ~UiSceneManager(); base::WeakPtr<UiSceneManager> GetWeakPtr(); @@ -38,7 +40,7 @@ void SetIncognito(bool incognito); void SetURL(const GURL& gurl); void SetWebVrSecureOrigin(bool secure); - void SetWebVrMode(bool web_vr, bool auto_presented, bool show_toast); + void SetWebVrMode(bool web_vr, bool show_toast); void SetSecurityInfo(security_state::SecurityLevel level, bool malware); void SetLoading(bool loading); void SetLoadProgress(float progress); @@ -47,6 +49,7 @@ void SetScreenCapturingIndicator(bool enabled); void SetAudioCapturingIndicator(bool enabled); void SetLocationAccessIndicator(bool enabled); + void SetSplashScreenIcon(const SkBitmap& bitmap); // These methods are currently stubbed. void SetHistoryButtonsEnabled(bool can_go_back, bool can_go_forward); @@ -68,6 +71,7 @@ void CreateSecurityWarnings(); void CreateSystemIndicators(); void CreateContentQuad(); + void CreateSplashScreen(); void CreateBackground(); void CreateUrlBar(); void CreateTransientUrlBar(); @@ -115,6 +119,7 @@ UiElement* ceiling_ = nullptr; UiElement* floor_ = nullptr; UiElement* close_button_ = nullptr; + SplashScreenIcon* splash_screen_icon_ = nullptr; UrlBar* url_bar_ = nullptr; TransientUrlBar* transient_url_bar_ = nullptr; LoadingIndicator* loading_indicator_ = nullptr; @@ -123,8 +128,8 @@ bool in_cct_; bool web_vr_mode_; - bool web_vr_autopresented_ = false; bool web_vr_show_toast_ = false; + bool web_vr_autopresentation_expected_ = false; bool secure_origin_ = false; bool fullscreen_ = false; bool incognito_ = false;
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc index 38b8241..93d6988c 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
@@ -6,7 +6,8 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/test/scoped_task_environment.h" +#include "base/message_loop/message_loop.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "chrome/browser/android/vr_shell/ui_browser_interface.h" #include "chrome/browser/android/vr_shell/ui_elements/ui_element.h" #include "chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h" @@ -37,7 +38,6 @@ kContentQuad, kBackplane, kCeiling, kFloor, kUrlBar}; std::set<UiElementDebugId> kElementsVisibleWithExitPrompt = { kExitPrompt, kExitPromptBackplane, kCeiling, kFloor}; - } // namespace class UiSceneManagerTest : public testing::Test { @@ -69,7 +69,7 @@ void MakeAutoPresentedManager() { scene_ = base::MakeUnique<UiScene>(); manager_ = base::MakeUnique<UiSceneManager>( - browser_.get(), scene_.get(), kNotInCct, kInWebVr, kAutopresented); + browser_.get(), scene_.get(), kNotInCct, kNotInWebVr, kAutopresented); } bool IsVisible(UiElementDebugId debug_id) { @@ -102,7 +102,7 @@ return true; } - base::test::ScopedTaskEnvironment scoped_task_environment_; + base::MessageLoop message_loop_; std::unique_ptr<MockBrowserInterface> browser_; std::unique_ptr<UiScene> scene_; std::unique_ptr<UiSceneManager> manager_; @@ -132,7 +132,7 @@ EXPECT_TRUE(IsVisible(kWebVrPermanentHttpSecurityWarning)); EXPECT_TRUE(IsVisible(kWebVrTransientHttpSecurityWarning)); - manager_->SetWebVrMode(false, false, false); + manager_->SetWebVrMode(false, false); EXPECT_FALSE(IsVisible(kWebVrPermanentHttpSecurityWarning)); EXPECT_FALSE(IsVisible(kWebVrTransientHttpSecurityWarning)); } @@ -143,11 +143,26 @@ EXPECT_FALSE(IsVisible(kWebVrPermanentHttpSecurityWarning)); EXPECT_FALSE(IsVisible(kWebVrTransientHttpSecurityWarning)); - manager_->SetWebVrMode(true, false, false); + manager_->SetWebVrMode(true, false); EXPECT_TRUE(IsVisible(kWebVrPermanentHttpSecurityWarning)); EXPECT_TRUE(IsVisible(kWebVrTransientHttpSecurityWarning)); } +TEST_F(UiSceneManagerTest, WebVrTransientWarningTimesOut) { + base::ScopedMockTimeMessageLoopTaskRunner task_runner_; + + MakeManager(kNotInCct, kInWebVr); + EXPECT_TRUE(IsVisible(kWebVrTransientHttpSecurityWarning)); + + // Note: Fast-forwarding appears broken in conjunction with restarting timers. + // In this test, we can fast-forward by the appropriate time interval, but in + // other cases (until the bug is addressed), we could work around the problem + // by using FastForwardUntilNoTasksRemain() instead. + // See http://crbug.com/736558. + task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(31)); + EXPECT_FALSE(IsVisible(kWebVrTransientHttpSecurityWarning)); +} + TEST_F(UiSceneManagerTest, ToastVisibility) { // Tests toast not showing when directly entering VR though WebVR // presentation. @@ -160,19 +175,19 @@ manager_->SetFullscreen(true); EXPECT_TRUE(IsVisible(kPresentationToast)); - manager_->SetWebVrMode(true, false, true); + manager_->SetWebVrMode(true, true); EXPECT_TRUE(IsVisible(kPresentationToast)); - manager_->SetWebVrMode(false, false, false); + manager_->SetWebVrMode(false, false); EXPECT_FALSE(IsVisible(kPresentationToast)); manager_->SetFullscreen(false); EXPECT_FALSE(IsVisible(kPresentationToast)); - manager_->SetWebVrMode(true, false, false); + manager_->SetWebVrMode(true, false); EXPECT_FALSE(IsVisible(kPresentationToast)); - manager_->SetWebVrMode(false, false, true); + manager_->SetWebVrMode(false, true); EXPECT_TRUE(IsVisible(kPresentationToast)); } @@ -194,7 +209,7 @@ // Button should not be visible when in WebVR. MakeManager(kInCct, kInWebVr); EXPECT_FALSE(IsVisible(kCloseButton)); - manager_->SetWebVrMode(false, false, false); + manager_->SetWebVrMode(false, false); EXPECT_TRUE(IsVisible(kCloseButton)); // Button should be visible in Cct across transistions in fullscreen. @@ -261,23 +276,17 @@ } } -TEST_F(UiSceneManagerTest, WebVrAutopresentedInitially) { - MakeAutoPresentedManager(); - manager_->SetWebVrSecureOrigin(true); - VerifyElementsVisible("Autopresented", - std::set<UiElementDebugId>{kTransientUrlBar}); -} - TEST_F(UiSceneManagerTest, WebVrAutopresented) { - MakeManager(kNotInCct, kNotInWebVr); + MakeAutoPresentedManager(); manager_->SetWebVrSecureOrigin(true); - // Initial state. - VerifyElementsVisible("Initial", kElementsVisibleInBrowsing); + // Initially, we should only show the splash screen. + VerifyElementsVisible("Initial", + std::set<UiElementDebugId>{kSplashScreenIcon}); // Enter WebVR with autopresentation. - manager_->SetWebVrMode(true, true, false); + manager_->SetWebVrMode(true, false); VerifyElementsVisible("Autopresented", std::set<UiElementDebugId>{kTransientUrlBar}); @@ -370,7 +379,7 @@ manager_->SetLocationAccessIndicator(true); // Transition to WebVR mode - manager_->SetWebVrMode(true, false, false); + manager_->SetWebVrMode(true, false); manager_->SetWebVrSecureOrigin(true); // All elements should be hidden. @@ -393,9 +402,9 @@ EXPECT_TRUE(VerifyVisibility(indicators, true)); // Go into non-browser modes and make sure all indicators are hidden. - manager_->SetWebVrMode(true, false, false); + manager_->SetWebVrMode(true, false); EXPECT_TRUE(VerifyVisibility(indicators, false)); - manager_->SetWebVrMode(false, false, false); + manager_->SetWebVrMode(false, false); manager_->SetFullscreen(true); EXPECT_TRUE(VerifyVisibility(indicators, false)); manager_->SetFullscreen(false);
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.cc b/chrome/browser/android/vr_shell/vr_gl_thread.cc index b1fc9138..d814a04 100644 --- a/chrome/browser/android/vr_shell/vr_gl_thread.cc +++ b/chrome/browser/android/vr_shell/vr_gl_thread.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/android/vr_shell/vr_input_manager.h" #include "chrome/browser/android/vr_shell/vr_shell.h" #include "chrome/browser/android/vr_shell/vr_shell_gl.h" +#include "third_party/skia/include/core/SkBitmap.h" namespace vr_shell { @@ -20,7 +21,7 @@ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, gvr_context* gvr_api, bool initially_web_vr, - bool web_vr_autopresented, + bool web_vr_autopresentation_expected, bool in_cct, bool reprojected_rendering, bool daydream_support) @@ -29,7 +30,7 @@ main_thread_task_runner_(std::move(main_thread_task_runner)), gvr_api_(gvr_api), initially_web_vr_(initially_web_vr), - web_vr_autopresented_(web_vr_autopresented), + web_vr_autopresentation_expected_(web_vr_autopresentation_expected), in_cct_(in_cct), reprojected_rendering_(reprojected_rendering), daydream_support_(daydream_support) {} @@ -44,7 +45,8 @@ reprojected_rendering_, daydream_support_, scene_.get()); scene_manager_ = base::MakeUnique<UiSceneManager>( - this, scene_.get(), in_cct_, initially_web_vr_, web_vr_autopresented_); + this, scene_.get(), in_cct_, initially_web_vr_, + web_vr_autopresentation_expected_); weak_vr_shell_gl_ = vr_shell_gl_->GetWeakPtr(); weak_scene_manager_ = scene_manager_->GetWeakPtr(); @@ -191,13 +193,11 @@ weak_scene_manager_, gurl)); } -void VrGLThread::SetWebVrMode(bool enabled, - bool auto_presented, - bool show_toast) { +void VrGLThread::SetWebVrMode(bool enabled, bool show_toast) { WaitUntilThreadStarted(); task_runner()->PostTask( FROM_HERE, base::Bind(&UiSceneManager::SetWebVrMode, weak_scene_manager_, - enabled, auto_presented, show_toast)); + enabled, show_toast)); } void VrGLThread::SetWebVrSecureOrigin(bool secure) { @@ -231,6 +231,13 @@ weak_scene_manager_)); } +void VrGLThread::SetSplashScreenIcon(const SkBitmap& bitmap) { + WaitUntilThreadStarted(); + task_runner()->PostTask(FROM_HERE, + base::Bind(&UiSceneManager::SetSplashScreenIcon, + weak_scene_manager_, bitmap)); +} + void VrGLThread::CleanUp() { scene_manager_.reset(); vr_shell_gl_.reset();
diff --git a/chrome/browser/android/vr_shell/vr_gl_thread.h b/chrome/browser/android/vr_shell/vr_gl_thread.h index 95ff30ee..8e3b89d 100644 --- a/chrome/browser/android/vr_shell/vr_gl_thread.h +++ b/chrome/browser/android/vr_shell/vr_gl_thread.h
@@ -35,7 +35,7 @@ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, gvr_context* gvr_api, bool initially_web_vr, - bool web_vr_autopresented, + bool web_vr_autopresentation_expected, bool in_cct, bool reprojected_rendering, bool daydream_support); @@ -78,14 +78,13 @@ void SetSecurityInfo(security_state::SecurityLevel level, bool malware) override; void SetURL(const GURL& gurl) override; - void SetWebVrMode(bool enabled, - bool auto_presented, - bool show_toast) override; + void SetWebVrMode(bool enabled, bool show_toast) override; void SetWebVrSecureOrigin(bool secure) override; void SetVideoCapturingIndicator(bool enabled) override; void SetScreenCapturingIndicator(bool enabled) override; void SetAudioCapturingIndicator(bool enabled) override; void SetIsExiting() override; + void SetSplashScreenIcon(const SkBitmap& bitmap) override; protected: void Init() override; @@ -104,7 +103,7 @@ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; gvr_context* gvr_api_; bool initially_web_vr_; - bool web_vr_autopresented_; + bool web_vr_autopresentation_expected_; bool in_cct_; bool reprojected_rendering_; bool daydream_support_;
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc index b881c09..97878d9 100644 --- a/chrome/browser/android/vr_shell/vr_shell.cc +++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -56,6 +56,7 @@ #include "ui/base/page_transition_types.h" #include "ui/display/display.h" #include "ui/display/screen.h" +#include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" @@ -94,7 +95,7 @@ jobject obj, ui::WindowAndroid* window, bool for_web_vr, - bool web_vr_autopresented, + bool web_vr_autopresentation_expected, bool in_cct, VrShellDelegate* delegate, gvr_context* gvr_api, @@ -113,8 +114,8 @@ gl_thread_ = base::MakeUnique<VrGLThread>( weak_ptr_factory_.GetWeakPtr(), main_thread_task_runner_, gvr_api, - for_web_vr, web_vr_autopresented, in_cct, reprojected_rendering_, - HasDaydreamSupport(env)); + for_web_vr, web_vr_autopresentation_expected, in_cct, + reprojected_rendering_, HasDaydreamSupport(env)); ui_ = gl_thread_.get(); base::Thread::Options options(base::MessageLoop::TYPE_DEFAULT, 0); @@ -122,6 +123,13 @@ gl_thread_->StartWithOptions(options); } +void VrShell::SetSplashScreenIcon(JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& bitmap) { + ui_->SetSplashScreenIcon( + gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap))); +} + void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { delete this; } @@ -337,7 +345,6 @@ void VrShell::SetWebVrMode(JNIEnv* env, const JavaParamRef<jobject>& obj, bool enabled, - bool auto_presented, bool show_toast) { webvr_mode_ = enabled; if (metrics_helper_) @@ -345,7 +352,7 @@ WaitForGlThread(); PostToGlThread(FROM_HERE, base::Bind(&VrShellGl::SetWebVrMode, gl_thread_->GetVrShellGl(), enabled)); - ui_->SetWebVrMode(enabled, auto_presented, show_toast); + ui_->SetWebVrMode(enabled, show_toast); } void VrShell::OnFullscreenChanged(bool enabled) { @@ -708,13 +715,13 @@ const JavaParamRef<jobject>& delegate, jlong window_android, jboolean for_web_vr, - jboolean web_vr_autopresented, + jboolean web_vr_autopresentation_expected, jboolean in_cct, jlong gvr_api, jboolean reprojected_rendering) { return reinterpret_cast<intptr_t>(new VrShell( env, obj, reinterpret_cast<ui::WindowAndroid*>(window_android), - for_web_vr, web_vr_autopresented, in_cct, + for_web_vr, web_vr_autopresentation_expected, in_cct, VrShellDelegate::GetNativeVrShellDelegate(env, delegate), reinterpret_cast<gvr_context*>(gvr_api), reprojected_rendering)); }
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h index c675a37..26d1c49 100644 --- a/chrome/browser/android/vr_shell/vr_shell.h +++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -68,7 +68,7 @@ jobject obj, ui::WindowAndroid* window, bool for_web_vr, - bool web_vr_autopresented, + bool web_vr_autopresentation_expected, bool in_cct, VrShellDelegate* delegate, gvr_context* gvr_api, @@ -86,13 +86,15 @@ bool touched); void OnPause(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + void SetSplashScreenIcon(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& bitmap); void SetSurface(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jobject>& surface); void SetWebVrMode(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, bool enabled, - bool auto_presented, bool show_toast); bool GetWebVrMode(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc index c0a97bd..aa961325 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.cc +++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -1194,7 +1194,9 @@ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } std::vector<const UiElement*> elements = scene_->GetWorldElements(); - const bool draw_reticle = !(scene_->is_exiting() || ShouldDrawWebVr()); + const bool draw_reticle = + !(scene_->is_exiting() || scene_->showing_splash_screen() || + ShouldDrawWebVr()); DrawUiView(head_pose, elements, render_size_primary_, kViewportListPrimaryOffset, draw_reticle); }
diff --git a/chrome/browser/apps/app_url_redirector.cc b/chrome/browser/apps/app_url_redirector.cc index e5ec867..46321f2e 100644 --- a/chrome/browser/apps/app_url_redirector.cc +++ b/chrome/browser/apps/app_url_redirector.cc
@@ -113,7 +113,8 @@ new navigation_interception::InterceptNavigationThrottle( handle, base::Bind(&LaunchAppWithUrl, - scoped_refptr<const Extension>(*iter), handler->id))); + scoped_refptr<const Extension>(*iter), handler->id), + true)); } }
diff --git a/chrome/browser/browsing_data/downloads_counter_browsertest.cc b/chrome/browser/browsing_data/downloads_counter_browsertest.cc index 04b0e18..e451143b 100644 --- a/chrome/browser/browsing_data/downloads_counter_browsertest.cc +++ b/chrome/browser/browsing_data/downloads_counter_browsertest.cc
@@ -338,7 +338,13 @@ } // Tests that the counter takes time ranges into account. -IN_PROC_BROWSER_TEST_F(DownloadsCounterTest, TimeRanges) { +// Flaky on Mac (crbug.com/736820) +#if defined(OS_MACOSX) +#define MAYBE_TimeRanges DISABLED_TimeRanges +#else +#define MAYBE_TimeRanges TimeRanges +#endif +IN_PROC_BROWSER_TEST_F(DownloadsCounterTest, MAYBE_TimeRanges) { AddDownload(); AddDownload(); // 2 items
diff --git a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc index 620e32c..8d04694 100644 --- a/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc +++ b/chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/apps/app_info_dialog.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/api/device_permissions_manager.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/permissions/permissions_data.h" @@ -66,10 +67,10 @@ std::vector<base::FilePath> retained_file_paths; if (extension->permissions_data()->HasAPIPermission( APIPermission::kFileSystem)) { - std::vector<apps::SavedFileEntry> retained_file_entries = - apps::SavedFilesService::Get(profile_) - ->GetAllFileEntries(extension_id_); - for (const apps::SavedFileEntry& entry : retained_file_entries) + std::vector<SavedFileEntry> retained_file_entries = + apps::SavedFilesService::Get(profile_)->GetAllFileEntries( + extension_id_); + for (const SavedFileEntry& entry : retained_file_entries) retained_file_paths.push_back(entry.path); } std::vector<base::string16> retained_device_messages;
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc index 8d5c628b..9ca75b7f 100644 --- a/chrome/browser/extensions/api/file_system/file_system_api.cc +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -40,6 +40,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/api/file_handlers/app_file_handler_util.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/extension_prefs.h" @@ -75,7 +76,6 @@ #include "url/url_constants.h" #endif -using apps::SavedFileEntry; using apps::SavedFilesService; using storage::IsolatedContext;
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chrome/browser/extensions/api/file_system/file_system_apitest.cc index 19dd525..abd1da1 100644 --- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc +++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/extensions/api/file_system/file_system_api.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_observer.h" @@ -615,8 +616,9 @@ &test_file); ASSERT_TRUE(RunPlatformAppTest( "api_test/file_system/retain_entry")) << message_; - std::vector<apps::SavedFileEntry> file_entries = apps::SavedFilesService::Get( - profile())->GetAllFileEntries(GetSingleLoadedExtension()->id()); + std::vector<SavedFileEntry> file_entries = + apps::SavedFilesService::Get(profile())->GetAllFileEntries( + GetSingleLoadedExtension()->id()); ASSERT_EQ(1u, file_entries.size()); EXPECT_EQ(test_file, file_entries[0].path); EXPECT_EQ(1, file_entries[0].sequence_number); @@ -631,8 +633,9 @@ &test_directory); ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/retain_directory")) << message_; - std::vector<apps::SavedFileEntry> file_entries = apps::SavedFilesService::Get( - profile())->GetAllFileEntries(GetSingleLoadedExtension()->id()); + std::vector<SavedFileEntry> file_entries = + apps::SavedFilesService::Get(profile())->GetAllFileEntries( + GetSingleLoadedExtension()->id()); ASSERT_EQ(1u, file_entries.size()); EXPECT_EQ(test_directory, file_entries[0].path); EXPECT_EQ(1, file_entries[0].sequence_number);
diff --git a/chrome/browser/plugins/flash_download_interception.cc b/chrome/browser/plugins/flash_download_interception.cc index f9a7b44..b4f6678 100644 --- a/chrome/browser/plugins/flash_download_interception.cc +++ b/chrome/browser/plugins/flash_download_interception.cc
@@ -159,5 +159,5 @@ } return base::MakeUnique<navigation_interception::InterceptNavigationThrottle>( - handle, base::Bind(&InterceptNavigation, source_url)); + handle, base::Bind(&InterceptNavigation, source_url), true); }
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc index b740a7e..ef41145f 100644 --- a/chrome/browser/predictors/loading_test_util.cc +++ b/chrome/browser/predictors/loading_test_util.cc
@@ -207,6 +207,19 @@ return prediction; } +PreconnectPrediction CreatePreconnectPrediction( + std::string host, + bool is_redirected, + std::vector<GURL> preconnect_origins, + std::vector<GURL> preresolve_hosts) { + PreconnectPrediction prediction; + prediction.host = host; + prediction.is_redirected = is_redirected; + prediction.preconnect_origins = preconnect_origins; + prediction.preresolve_hosts = preresolve_hosts; + return prediction; +} + void PopulateTestConfig(LoadingPredictorConfig* config, bool small_db) { if (small_db) { config->max_urls_to_track = 3; @@ -372,6 +385,21 @@ return os << navigation_id.tab_id << "," << navigation_id.main_frame_url; } +std::ostream& operator<<(std::ostream& os, + const PreconnectPrediction& prediction) { + os << "[" << prediction.host << "," << prediction.is_redirected << "]" + << std::endl; + + os << "Preconnect:" << std::endl; + for (const auto& url : prediction.preconnect_origins) + os << "\t\t" << url << std::endl; + + os << "Preresolve:" << std::endl; + for (const auto& url : prediction.preresolve_hosts) + os << "\t\t" << url << std::endl; + return os; +} + bool operator==(const PrefetchData& lhs, const PrefetchData& rhs) { bool equal = lhs.primary_key() == rhs.primary_key() && lhs.resources_size() == rhs.resources_size(); @@ -460,6 +488,13 @@ lhs.accessed_network() == rhs.accessed_network(); } +bool operator==(const PreconnectPrediction& lhs, + const PreconnectPrediction& rhs) { + return lhs.is_redirected == rhs.is_redirected && lhs.host == rhs.host && + lhs.preconnect_origins == rhs.preconnect_origins && + lhs.preresolve_hosts == rhs.preresolve_hosts; +} + } // namespace predictors namespace precache {
diff --git a/chrome/browser/predictors/loading_test_util.h b/chrome/browser/predictors/loading_test_util.h index 2d6e171..2fe23ac 100644 --- a/chrome/browser/predictors/loading_test_util.h +++ b/chrome/browser/predictors/loading_test_util.h
@@ -104,6 +104,12 @@ const std::string& main_frame_key, std::vector<GURL> subresource_urls); +PreconnectPrediction CreatePreconnectPrediction( + std::string host, + bool is_redirected, + std::vector<GURL> preconnect_urls, + std::vector<GURL> preresolve_urls); + void PopulateTestConfig(LoadingPredictorConfig* config, bool small_db = true); scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders( @@ -184,6 +190,8 @@ std::ostream& operator<<(std::ostream& os, const OriginData& data); std::ostream& operator<<(std::ostream& os, const OriginStat& redirect); +std::ostream& operator<<(std::ostream& os, + const PreconnectPrediction& prediction); bool operator==(const PrefetchData& lhs, const PrefetchData& rhs); bool operator==(const ResourceData& lhs, const ResourceData& rhs); @@ -195,6 +203,8 @@ const ResourcePrefetchPredictor::URLRequestSummary& rhs); bool operator==(const OriginData& lhs, const OriginData& rhs); bool operator==(const OriginStat& lhs, const OriginStat& rhs); +bool operator==(const PreconnectPrediction& lhs, + const PreconnectPrediction& rhs); } // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index 2923f9c..5d3b5114 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -54,6 +54,8 @@ const size_t kMaxManifestByteSize = 16 * 1024; const size_t kNumSampleHosts = 50; const size_t kReportReadinessThreshold = 50; +const float kMinOriginConfidenceToTriggerPreconnect = 0.75; +const float kMinOriginConfidenceToTriggerPreresolve = 0.2; // For reporting events of interest that are not tied to any navigation. enum ReportingEvent { @@ -181,6 +183,11 @@ } // namespace internal +PreconnectPrediction::PreconnectPrediction() = default; +PreconnectPrediction::PreconnectPrediction( + const PreconnectPrediction& prediction) = default; +PreconnectPrediction::~PreconnectPrediction() = default; + //////////////////////////////////////////////////////////////////////////////// // ResourcePrefetchPredictor static functions. @@ -715,6 +722,41 @@ return false; } +bool ResourcePrefetchPredictor::PredictPreconnectOrigins( + const GURL& url, + PreconnectPrediction* prediction) const { + DCHECK(prediction); + DCHECK(prediction->preconnect_origins.empty()); + DCHECK(prediction->preresolve_hosts.empty()); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (initialization_state_ != INITIALIZED) + return false; + + std::string host = url.host(); + std::string redirect_endpoint; + if (!GetRedirectEndpoint(host, *host_redirect_data_, &redirect_endpoint)) + return false; + + OriginData data; + if (!origin_data_->TryGetData(redirect_endpoint, &data)) + return false; + + prediction->host = redirect_endpoint; + prediction->is_redirected = (host != redirect_endpoint); + for (const OriginStat& origin : data.origins()) { + float confidence = static_cast<float>(origin.number_of_hits()) / + (origin.number_of_hits() + origin.number_of_misses()); + if (confidence > kMinOriginConfidenceToTriggerPreconnect) { + prediction->preconnect_origins.emplace_back(origin.origin()); + } else if (confidence > kMinOriginConfidenceToTriggerPreresolve) { + prediction->preresolve_hosts.emplace_back(origin.origin()); + } + } + + return !prediction->preconnect_origins.empty() || + !prediction->preresolve_hosts.empty(); +} + bool ResourcePrefetchPredictor::PopulatePrefetcherRequest( const std::string& main_frame_key, const PrefetchDataMap& resource_data,
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h index fb5c2ba..28df24d 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.h +++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -68,6 +68,17 @@ class ResourcePrefetcherManager; class LoadingStatsCollector; +struct PreconnectPrediction { + PreconnectPrediction(); + PreconnectPrediction(const PreconnectPrediction& other); + ~PreconnectPrediction(); + + bool is_redirected; + std::string host; + std::vector<GURL> preconnect_origins; + std::vector<GURL> preresolve_hosts; +}; + // Contains logic for learning what can be prefetched and for kicking off // speculative prefetching. // - The class is a profile keyed service owned by the profile. @@ -254,6 +265,12 @@ virtual bool GetPrefetchData(const GURL& main_frame_url, Prediction* prediction) const; + // Returns true iff there is OriginData that can be used for a |url| and fills + // |prediction| with origins and hosts that need to be preconnected and + // preresolved respectively. + virtual bool PredictPreconnectOrigins(const GURL& url, + PreconnectPrediction* prediction) const; + private: // 'LoadingPredictorObserver' calls the below functions to inform the // predictor of main frame and resource requests. Should only be called if the @@ -314,6 +331,8 @@ FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetRedirectEndpoint); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetPrefetchData); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, + TestPredictPreconnectOrigins); + FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, TestPrecisionRecallHistograms); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, TestPrefetchingDurationHistogram);
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc index 9c6fa37..1b00760f 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -1632,6 +1632,61 @@ EXPECT_THAT(urls, UnorderedElementsAre(GURL(font_url))); } +TEST_F(ResourcePrefetchPredictorTest, TestPredictPreconnectOrigins) { + const GURL main_frame_url("http://google.com/?query=cats"); + auto prediction = base::MakeUnique<PreconnectPrediction>(); + // No prefetch data. + EXPECT_FALSE( + predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get())); + + const char* cdn_origin = "https://cdn%d.google.com"; + auto gen_origin = [cdn_origin](int n) { + return base::StringPrintf(cdn_origin, n); + }; + + // Add origins associated with the main frame host. + OriginData google = CreateOriginData("google.com"); + InitializeOriginStat(google.add_origins(), gen_origin(1), 10, 0, 0, 1.0, true, + true); // High confidence - preconnect. + InitializeOriginStat(google.add_origins(), gen_origin(2), 10, 5, 0, 2.0, true, + true); // Medium confidence - preresolve. + InitializeOriginStat(google.add_origins(), gen_origin(3), 1, 10, 10, 3.0, + true, true); // Low confidence - ignore. + predictor_->origin_data_->UpdateData(google.host(), google); + + prediction = base::MakeUnique<PreconnectPrediction>(); + EXPECT_TRUE( + predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get())); + EXPECT_EQ(*prediction, CreatePreconnectPrediction("google.com", false, + {GURL(gen_origin(1))}, + {GURL(gen_origin(2))})); + + // Add a redirect. + RedirectData redirect = CreateRedirectData("google.com", 3); + InitializeRedirectStat(redirect.add_redirect_endpoints(), "www.google.com", + 10, 0, 0); + predictor_->host_redirect_data_->UpdateData(redirect.primary_key(), redirect); + + // Prediction failed: no data associated with the redirect endpoint. + prediction = base::MakeUnique<PreconnectPrediction>(); + EXPECT_FALSE( + predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get())); + + // Add a resource associated with the redirect endpoint. + OriginData www_google = CreateOriginData("www.google.com", 4); + InitializeOriginStat(www_google.add_origins(), gen_origin(4), 10, 0, 0, 1.0, + true, + true); // High confidence - preconnect. + predictor_->origin_data_->UpdateData(www_google.host(), www_google); + + prediction = base::MakeUnique<PreconnectPrediction>(); + EXPECT_TRUE( + predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get())); + EXPECT_EQ(*prediction, CreatePreconnectPrediction("www.google.com", true, + {GURL(gen_origin(4))}, + std::vector<GURL>())); +} + TEST_F(ResourcePrefetchPredictorTest, TestRecordFirstContentfulPaint) { auto res1_time = base::TimeTicks::FromInternalValue(1); auto res2_time = base::TimeTicks::FromInternalValue(2);
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc index aad28a88..8bcdac8 100644 --- a/chrome/browser/safe_browsing/download_protection_service.cc +++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -56,11 +56,11 @@ #include "components/prefs/pref_service.h" #include "components/safe_browsing/common/safe_browsing_prefs.h" #include "components/safe_browsing/common/safebrowsing_switches.h" +#include "components/safe_browsing/common/utils.h" #include "components/safe_browsing/csd.pb.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item.h" #include "content/public/browser/page_navigator.h" -#include "crypto/sha2.h" #include "google_apis/google_api_keys.h" #include "net/base/escape.h" #include "net/base/load_flags.h" @@ -107,15 +107,6 @@ WHITELIST_TYPE_MAX); } -} // namespace - -const char DownloadProtectionService::kDownloadRequestUrl[] = - "https://sb-ssl.google.com/safebrowsing/clientreport/download"; - -const void* const DownloadProtectionService::kDownloadPingTokenKey - = &kDownloadPingTokenKey; - -namespace { void RecordFileExtensionType(const std::string& metric_name, const base::FilePath& file) { UMA_HISTOGRAM_SPARSE_SLOWLY( @@ -166,6 +157,12 @@ } // namespace +const char DownloadProtectionService::kDownloadRequestUrl[] = + "https://sb-ssl.google.com/safebrowsing/clientreport/download"; + +const void* const DownloadProtectionService::kDownloadPingTokenKey = + &kDownloadPingTokenKey; + // SafeBrowsing::Client class used to lookup the bad binary URL list. class DownloadUrlSBClient @@ -954,16 +951,7 @@ if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) return url.GetOrigin().spec(); - std::string spec = url.spec(); - if (url.SchemeIs(url::kDataScheme)) { - size_t comma_pos = spec.find(','); - if (comma_pos != std::string::npos && comma_pos != spec.size() - 1) { - std::string hash_value = crypto::SHA256HashString(spec); - spec.erase(comma_pos + 1); - spec += base::HexEncode(hash_value.data(), hash_value.size()); - } - } - return spec; + return ShortURLForReporting(url); } void SendRequest() { @@ -1034,6 +1022,9 @@ !referrer_chain_data->GetReferrerChain()->empty()) { request.mutable_referrer_chain()->Swap( referrer_chain_data->GetReferrerChain()); + if (type_ == ClientDownloadRequest::SAMPLED_UNSUPPORTED_FILE) + SafeBrowsingNavigationObserverManager::SanitizeReferrerChain( + request.mutable_referrer_chain()); } if (archive_is_valid_ != ArchiveValid::UNSET)
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc index 816f7ea..346b630a 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -42,6 +42,7 @@ "navigation_observer_multi_frame_tests.html"; const char kRedirectURL[] = "/safe_browsing/download_protection/navigation_observer/redirect.html"; +// Please update |kShortDataURL| too if you're changing |kDownloadDataURL|. const char kDownloadDataURL[] = "data:application/octet-stream;base64,a2poYWxrc2hkbGtoYXNka2xoYXNsa2RoYWxra" "GtoYWxza2hka2xzamFoZGxramhhc2xka2hhc2xrZGgKYXNrZGpoa2FzZGpoYWtzaGRrYXNoZGt" @@ -49,6 +50,14 @@ "mFoZGtoYXNrZGhhc2tka2hrYXNkCjg3MzQ2ODEyNzQ2OGtqc2hka2FoZHNrZGhraApha3NqZGt" "hc2Roa3NkaGthc2hka2FzaGtkaAohISomXkAqJl4qYWhpZGFzeWRpeWlhc1xcb1wKa2Fqc2Roa" "2FzaGRrYXNoZGsKYWtzamRoc2tkaAplbmQK"; +// Short data url is computed by keeping the prefix of |kDownloadDataURL| up to +// the first ",", and appending the hash (SHA256) of entire |kDownloadDataURL|. +// e.g., +// $echo -n <kDownloadDataURL> | sha256sum | +// awk '{print "data:application/octet-stream;base64,"toupper($1)}' +const char kShortDataURL[] = + "data:application/octet-stream;base64,4A19A03B1EF9D2C3061C5B87BF7D0BE05998D" + "A5F6BA693B6759B47EEA211D246"; const char kIframeDirectDownloadURL[] = "/safe_browsing/download_protection/navigation_observer/iframe.html"; const char kIframeRetargetingURL[] = @@ -1077,6 +1086,7 @@ GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); ClickTestLink("new_tab_download_with_data_url", 2, initial_url); GURL download_url = GURL(kDownloadDataURL); + GURL short_download_url = GURL(kShortDataURL); GURL blank_url = GURL(url::kAboutBlankURL); std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto* nav_list = navigation_event_list(); @@ -1126,7 +1136,7 @@ ReferrerChain referrer_chain; IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); ASSERT_EQ(3, referrer_chain.size()); - VerifyReferrerChainEntry(download_url, // url + VerifyReferrerChainEntry(short_download_url, // url GURL(), // main_frame_url ReferrerChainEntry::EVENT_URL, // type "", // ip_address @@ -1974,4 +1984,38 @@ std::vector<GURL>(), // server redirects referrer_chain.Get(0)); } + +IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, + VerifySanitizeReferrerChain) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + GURL test_server_origin = embedded_test_server()->base_url().GetOrigin(); + ClickTestLink("direct_download", 1, initial_url); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); + auto* nav_list = navigation_event_list(); + ASSERT_TRUE(nav_list); + ASSERT_EQ(2U, nav_list->Size()); + ReferrerChain referrer_chain; + IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain); + SafeBrowsingNavigationObserverManager::SanitizeReferrerChain(&referrer_chain); + ASSERT_EQ(2, referrer_chain.size()); + VerifyReferrerChainEntry(test_server_origin, // url + GURL(), // main_frame_url + ReferrerChainEntry::EVENT_URL, // type + test_server_ip, // ip_address + test_server_origin, // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + std::vector<GURL>(), // server redirects + referrer_chain.Get(0)); + VerifyReferrerChainEntry(test_server_origin, // url + GURL(), // main_frame_url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + std::vector<GURL>(), // server redirects + referrer_chain.Get(1)); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc index 54699090a..dbbbcd4 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/common/utils.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -59,6 +60,10 @@ } } +std::string GetOrigin(const std::string& url) { + return GURL(url).GetOrigin().spec(); +} + } // namespace // The expiration period of a user gesture. Any user gesture that happened 1.0 @@ -219,6 +224,38 @@ ->navigation_observer_manager(); } +// static +void SafeBrowsingNavigationObserverManager::SanitizeReferrerChain( + ReferrerChain* referrer_chain) { + for (int i = 0; i < referrer_chain->size(); i++) { + ReferrerChainEntry* entry = referrer_chain->Mutable(i); + ReferrerChainEntry entry_copy(*entry); + entry->Clear(); + if (entry_copy.has_url()) + entry->set_url(GetOrigin(entry_copy.url())); + if (entry_copy.has_main_frame_url()) + entry->set_main_frame_url(GetOrigin(entry_copy.main_frame_url())); + entry->set_type(entry_copy.type()); + for (int j = 0; j < entry_copy.ip_addresses_size(); j++) + entry->add_ip_addresses(entry_copy.ip_addresses(j)); + if (entry_copy.has_referrer_url()) + entry->set_referrer_url(GetOrigin(entry_copy.referrer_url())); + if (entry_copy.has_referrer_main_frame_url()) + entry->set_referrer_main_frame_url( + GetOrigin(entry_copy.referrer_main_frame_url())); + entry->set_is_retargeting(entry_copy.is_retargeting()); + entry->set_navigation_time_msec(entry_copy.navigation_time_msec()); + for (int j = 0; j < entry_copy.server_redirect_chain_size(); j++) { + ReferrerChainEntry::ServerRedirect* server_redirect_entry = + entry->add_server_redirect_chain(); + if (entry_copy.server_redirect_chain(j).has_url()) { + server_redirect_entry->set_url( + GetOrigin(entry_copy.server_redirect_chain(j).url())); + } + } + } +} + SafeBrowsingNavigationObserverManager::SafeBrowsingNavigationObserverManager() : navigation_event_list_(kNavigationRecordMaxSize) { @@ -486,10 +523,11 @@ std::unique_ptr<ReferrerChainEntry> referrer_chain_entry = base::MakeUnique<ReferrerChainEntry>(); const GURL destination_url = nav_event->GetDestinationUrl(); - referrer_chain_entry->set_url(destination_url.spec()); + referrer_chain_entry->set_url(ShortURLForReporting(destination_url)); if (destination_main_frame_url.is_valid() && destination_url != destination_main_frame_url) - referrer_chain_entry->set_main_frame_url(destination_main_frame_url.spec()); + referrer_chain_entry->set_main_frame_url( + ShortURLForReporting(destination_main_frame_url)); referrer_chain_entry->set_type(type); auto ip_it = host_to_ip_map_.find(destination_url.host()); if (ip_it != host_to_ip_map_.end()) { @@ -500,12 +538,13 @@ // Since we only track navigation to landing referrer, we will not log the // referrer of the landing referrer page. if (type != ReferrerChainEntry::LANDING_REFERRER) { - referrer_chain_entry->set_referrer_url(nav_event->source_url.spec()); + referrer_chain_entry->set_referrer_url( + ShortURLForReporting(nav_event->source_url)); // Only set |referrer_main_frame_url| if it is diff from |referrer_url|. if (nav_event->source_main_frame_url.is_valid() && nav_event->source_url != nav_event->source_main_frame_url) { referrer_chain_entry->set_referrer_main_frame_url( - nav_event->source_main_frame_url.spec()); + ShortURLForReporting(nav_event->source_main_frame_url)); } } referrer_chain_entry->set_is_retargeting(nav_event->source_tab_id != @@ -517,10 +556,11 @@ // url. ReferrerChainEntry::ServerRedirect* server_redirect = referrer_chain_entry->add_server_redirect_chain(); - server_redirect->set_url(nav_event->original_request_url.spec()); + server_redirect->set_url( + ShortURLForReporting(nav_event->original_request_url)); for (const GURL& redirect : nav_event->server_redirect_urls) { server_redirect = referrer_chain_entry->add_server_redirect_chain(); - server_redirect->set_url(redirect.spec()); + server_redirect->set_url(ShortURLForReporting(redirect)); } } referrer_chain->Add()->Swap(referrer_chain_entry.get());
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h index ded29a5..473cb52 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -122,6 +122,9 @@ // initialized. static bool IsEnabledAndReady(Profile* profile); + // Sanitize referrer chain by only keeping origin information of all URLs. + static void SanitizeReferrerChain(ReferrerChain* referrer_chain); + SafeBrowsingNavigationObserverManager(); // Adds |nav_event| to |navigation_event_list_|. Object pointed to by
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index ce52e9bc..bcf223ed 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -3332,6 +3332,10 @@ "app_list/search/app_result.h", "app_list/search/app_search_provider.cc", "app_list/search/app_search_provider.h", + "app_list/search/arc/arc_playstore_search_provider.cc", + "app_list/search/arc/arc_playstore_search_provider.h", + "app_list/search/arc/arc_playstore_search_result.cc", + "app_list/search/arc/arc_playstore_search_result.h", "app_list/search/common/json_response_fetcher.cc", "app_list/search/common/json_response_fetcher.h", "app_list/search/common/url_icon_source.cc", @@ -3413,6 +3417,8 @@ "app_list/arc/arc_package_syncable_service.h", "app_list/arc/arc_package_syncable_service_factory.cc", "app_list/arc/arc_package_syncable_service_factory.h", + "app_list/arc/arc_playstore_app_context_menu.cc", + "app_list/arc/arc_playstore_app_context_menu.h", "app_list/search/arc_app_result.cc", "app_list/search/arc_app_result.h", "ash/launcher/arc_app_deferred_launcher_controller.cc", @@ -3434,7 +3440,10 @@ "views/arc_app_dialog_view.cc", ] } - deps += [ "//ui/app_list" ] + deps += [ + "//ui/app_list", + "//ui/app_list/vector_icons", + ] } else { sources += [ "app_list/app_list_service.h",
diff --git a/chrome/browser/ui/app_list/app_context_menu.h b/chrome/browser/ui/app_list/app_context_menu.h index 24ab832..c6de4ed 100644 --- a/chrome/browser/ui/app_list/app_context_menu.h +++ b/chrome/browser/ui/app_list/app_context_menu.h
@@ -31,6 +31,7 @@ REMOVE_FROM_FOLDER, MENU_NEW_WINDOW, MENU_NEW_INCOGNITO_WINDOW, + INSTALL, // Order matters in USE_LAUNCH_TYPE_* and must match the LaunchType enum. USE_LAUNCH_TYPE_COMMAND_START = 200, USE_LAUNCH_TYPE_PINNED = USE_LAUNCH_TYPE_COMMAND_START,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc index e190e603..4da996d 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -777,9 +777,8 @@ } void ArcAppListPrefs::OnInstanceReady() { - // Init() is also available at version 0. arc::mojom::AppInstance* app_instance = - ARC_GET_INSTANCE_FOR_METHOD(app_instance_holder_, RefreshAppList); + ARC_GET_INSTANCE_FOR_METHOD(app_instance_holder_, Init); // Note, sync_service_ may be nullptr in testing. sync_service_ = arc::ArcPackageSyncableService::Get(profile_); @@ -793,7 +792,6 @@ arc::mojom::AppHostPtr host_proxy; binding_.Bind(mojo::MakeRequest(&host_proxy)); app_instance->Init(std::move(host_proxy)); - app_instance->RefreshAppList(); } void ArcAppListPrefs::OnInstanceClosed() { @@ -1397,11 +1395,6 @@ RemovePackageFromPrefs(prefs_, package_name); } - // TODO(lgcheng@) File http://b/31944261. Remove the flag after Android side - // cleanup. - if (package_list_initial_refreshed_) - return; - package_list_initial_refreshed_ = true; for (auto& observer : observer_list_) observer.OnPackageListInitialRefreshed();
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h index f9efdec..d849fb5c7 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -439,7 +439,7 @@ bool is_initialized_ = false; // True if apps were restored. bool apps_restored_ = false; - // True is ARC package list has been refreshed once. + // True is ARC package list has been successfully refreshed. bool package_list_initial_refreshed_ = false; // Play Store does not have publicly available observers for default app // installations. This timeout is for validating default app availability.
diff --git a/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.cc b/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.cc new file mode 100644 index 0000000..4a92b361 --- /dev/null +++ b/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.cc
@@ -0,0 +1,43 @@ +// Copyright 2017 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 "chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.h" + +#include <string> + +#include "chrome/browser/ui/app_list/app_context_menu_delegate.h" +#include "chrome/grit/generated_resources.h" + +ArcPlayStoreAppContextMenu::ArcPlayStoreAppContextMenu( + app_list::AppContextMenuDelegate* delegate, + Profile* profile, + AppListControllerDelegate* controller) + : app_list::AppContextMenu(delegate, profile, std::string(), controller) {} + +ArcPlayStoreAppContextMenu::~ArcPlayStoreAppContextMenu() = default; + +void ArcPlayStoreAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) { + // App Info item. + menu_model->AddItemWithStringId(INSTALL, IDS_APP_CONTEXT_MENU_INSTALL_ARC); +} + +bool ArcPlayStoreAppContextMenu::IsCommandIdEnabled(int command_id) const { + switch (command_id) { + case INSTALL: + return true; + default: + return app_list::AppContextMenu::IsCommandIdEnabled(command_id); + } +} + +void ArcPlayStoreAppContextMenu::ExecuteCommand(int command_id, + int event_flags) { + switch (command_id) { + case INSTALL: + delegate()->ExecuteLaunchCommand(event_flags); + break; + default: + app_list::AppContextMenu::ExecuteCommand(command_id, event_flags); + } +}
diff --git a/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.h b/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.h new file mode 100644 index 0000000..78ee7899 --- /dev/null +++ b/chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.h
@@ -0,0 +1,35 @@ +// Copyright 2017 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 CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PLAYSTORE_APP_CONTEXT_MENU_H_ +#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PLAYSTORE_APP_CONTEXT_MENU_H_ + +#include "chrome/browser/ui/app_list/app_context_menu.h" + +class AppListControllerDelegate; +class Profile; + +namespace app_list { +class AppContextMenuDelegate; +} + +class ArcPlayStoreAppContextMenu : public app_list::AppContextMenu { + public: + ArcPlayStoreAppContextMenu(app_list::AppContextMenuDelegate* delegate, + Profile* profile, + AppListControllerDelegate* controller); + ~ArcPlayStoreAppContextMenu() override; + + // AppListContextMenu overrides: + void BuildMenu(ui::SimpleMenuModel* menu_model) override; + + // ui::SimpleMenuModel::Delegate overrides: + void ExecuteCommand(int command_id, int event_flags) override; + bool IsCommandIdEnabled(int command_id) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(ArcPlayStoreAppContextMenu); +}; + +#endif // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PLAYSTORE_APP_CONTEXT_MENU_H_
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc new file mode 100644 index 0000000..0c3c0275 --- /dev/null +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
@@ -0,0 +1,58 @@ +// Copyright 2017 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 "chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h" + +#include <utility> + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" +#include "chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/arc_service_manager.h" + +namespace app_list { + +ArcPlayStoreSearchProvider::ArcPlayStoreSearchProvider( + int max_results, + Profile* profile, + AppListControllerDelegate* list_controller) + : max_results_(max_results), + profile_(profile), + list_controller_(list_controller), + weak_ptr_factory_(this) {} + +ArcPlayStoreSearchProvider::~ArcPlayStoreSearchProvider() = default; + +void ArcPlayStoreSearchProvider::Start(bool is_voice_query, + const base::string16& query) { + // TODO(crbug.com/736027): should search for voice? + arc::mojom::AppInstance* app_instance = + arc::ArcServiceManager::Get() + ? ARC_GET_INSTANCE_FOR_METHOD( + arc::ArcServiceManager::Get()->arc_bridge_service()->app(), + GetRecentAndSuggestedAppsFromPlayStore) + : nullptr; + + if (app_instance == nullptr) + return; + + ClearResults(); + app_instance->GetRecentAndSuggestedAppsFromPlayStore( + UTF16ToUTF8(query), max_results_, + base::Bind(&ArcPlayStoreSearchProvider::OnResults, + weak_ptr_factory_.GetWeakPtr())); +} + +void ArcPlayStoreSearchProvider::Stop() {} + +void ArcPlayStoreSearchProvider::OnResults( + std::vector<arc::mojom::AppDiscoveryResultPtr> results) { + for (auto& result : results) { + Add(base::MakeUnique<ArcPlayStoreSearchResult>(std::move(result), profile_, + list_controller_)); + } +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h new file mode 100644 index 0000000..40ca9ee5 --- /dev/null +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h
@@ -0,0 +1,47 @@ +// Copyright 2017 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 CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_PROVIDER_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_PROVIDER_H_ + +#include <memory> +#include <vector> + +#include "components/arc/common/app.mojom.h" +#include "ui/app_list/search_provider.h" + +class Profile; +class AppListControllerDelegate; + +namespace app_list { + +class ArcPlayStoreSearchProvider : public SearchProvider { + public: + ArcPlayStoreSearchProvider(int max_results, + Profile* profile, + AppListControllerDelegate* list_controller); + ~ArcPlayStoreSearchProvider() override; + + protected: + // app_list::SearchProvider overrides: + void Start(bool is_voice_query, const base::string16& query) override; + void Stop() override; + + private: + void OnResults(std::vector<arc::mojom::AppDiscoveryResultPtr> results); + + const int max_results_; + // |profile_| is owned by ProfileInfo. + Profile* const profile_; + // list_controller_ is owned by AppListServiceAsh and lives + // until the service finishes. + AppListControllerDelegate* const list_controller_; + base::WeakPtrFactory<ArcPlayStoreSearchProvider> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcPlayStoreSearchProvider); +}; + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_PROVIDER_H_
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc new file mode 100644 index 0000000..98013dd --- /dev/null +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
@@ -0,0 +1,194 @@ +// Copyright 2017 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 "chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h" + +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/image_decoder.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/arc/arc_playstore_app_context_menu.h" +#include "chrome/grit/component_extension_resources.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/arc_service_manager.h" +#include "components/arc/common/app.mojom.h" +#include "components/crx_file/id_util.h" +#include "content/public/browser/browser_thread.h" +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/vector_icons/vector_icons.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/image/image_skia_rep.h" +#include "ui/gfx/image/image_skia_source.h" +#include "ui/gfx/paint_vector_icon.h" + +using content::BrowserThread; + +namespace { +// The id prefix to identify a Play Store search result. +constexpr char kPlayAppPrefix[] = "play://"; +// Badge icon color, #000 at 54% opacity. +constexpr SkColor kBadgeColor = SkColorSetARGBMacro(0x8A, 0x00, 0x00, 0x00); +} // namespace + +namespace app_list { + +//////////////////////////////////////////////////////////////////////////////// +// IconSource + +class IconSource : public gfx::ImageSkiaSource { + public: + IconSource(const SkBitmap& decoded_bitmap, int resource_size_in_dip); + explicit IconSource(int resource_size_in_dip); + ~IconSource() override = default; + + void SetDecodedImage(const SkBitmap& decoded_bitmap); + + private: + gfx::ImageSkiaRep GetImageForScale(float scale) override; + + const int resource_size_in_dip_; + gfx::ImageSkia decoded_icon_; + + DISALLOW_COPY_AND_ASSIGN(IconSource); +}; + +IconSource::IconSource(int resource_size_in_dip) + : resource_size_in_dip_(resource_size_in_dip) {} + +void IconSource::SetDecodedImage(const SkBitmap& decoded_bitmap) { + decoded_icon_.AddRepresentation(gfx::ImageSkiaRep( + decoded_bitmap, ui::GetScaleForScaleFactor(ui::SCALE_FACTOR_100P))); +} + +gfx::ImageSkiaRep IconSource::GetImageForScale(float scale) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // We use the icon if it was decoded successfully, otherwise use the default + // ARC icon. + const gfx::ImageSkia* icon_to_scale; + if (decoded_icon_.isNull()) { + int resource_id = + scale >= 1.5f ? IDR_ARC_SUPPORT_ICON_96 : IDR_ARC_SUPPORT_ICON_48; + icon_to_scale = + ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); + } else { + icon_to_scale = &decoded_icon_; + } + DCHECK(icon_to_scale); + + gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage( + *icon_to_scale, skia::ImageOperations::RESIZE_BEST, + gfx::Size(resource_size_in_dip_, resource_size_in_dip_)); + return resized_image.GetRepresentation(scale); +} + +//////////////////////////////////////////////////////////////////////////////// +// IconDecodeRequest + +class ArcPlayStoreSearchResult::IconDecodeRequest + : public ImageDecoder::ImageRequest { + public: + explicit IconDecodeRequest(ArcPlayStoreSearchResult* search_result) + : search_result_(search_result) {} + ~IconDecodeRequest() override = default; + + // ImageDecoder::ImageRequest overrides. + void OnImageDecoded(const SkBitmap& bitmap) override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + const gfx::Size resource_size(app_list::kGridIconDimension, + app_list::kGridIconDimension); + IconSource* icon_source = new IconSource(app_list::kGridIconDimension); + icon_source->SetDecodedImage(bitmap); + const gfx::ImageSkia icon = gfx::ImageSkia(icon_source, resource_size); + icon.EnsureRepsForSupportedScales(); + + search_result_->SetIcon(icon); + } + + void OnDecodeImageFailed() override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DLOG(ERROR) << "Failed to decode an app icon image."; + + const gfx::Size resource_size(app_list::kGridIconDimension, + app_list::kGridIconDimension); + IconSource* icon_source = new IconSource(app_list::kGridIconDimension); + const gfx::ImageSkia icon = gfx::ImageSkia(icon_source, resource_size); + icon.EnsureRepsForSupportedScales(); + + search_result_->SetIcon(icon); + } + + private: + // ArcPlayStoreSearchResult owns IconDecodeRequest, so it will outlive this. + ArcPlayStoreSearchResult* const search_result_; + + DISALLOW_COPY_AND_ASSIGN(IconDecodeRequest); +}; + +//////////////////////////////////////////////////////////////////////////////// +// ArcPlayStoreSearchResult + +ArcPlayStoreSearchResult::ArcPlayStoreSearchResult( + arc::mojom::AppDiscoveryResultPtr data, + Profile* profile, + AppListControllerDelegate* list_controller) + : data_(std::move(data)), + profile_(profile), + list_controller_(list_controller) { + set_title(base::UTF8ToUTF16(label().value())); + set_id(kPlayAppPrefix + + crx_file::id_util::GenerateId(install_intent_uri().value())); + set_display_type(DISPLAY_TILE); + SetBadgeIcon(gfx::CreateVectorIcon( + is_instant_app() ? kIcBadgeInstantIcon : kIcBadgePlayIcon, + kAppBadgeIconSize, kBadgeColor)); + SetFormattedPrice(base::UTF8ToUTF16(formatted_price().value())); + SetRating(review_score()); + set_result_type(is_instant_app() ? RESULT_INSTANT_APP : RESULT_PLAYSTORE_APP); + + icon_decode_request_ = base::MakeUnique<IconDecodeRequest>(this); + ImageDecoder::StartWithOptions(icon_decode_request_.get(), icon_png_data(), + ImageDecoder::DEFAULT_CODEC, true, + gfx::Size()); +} + +ArcPlayStoreSearchResult::~ArcPlayStoreSearchResult() = default; + +std::unique_ptr<SearchResult> ArcPlayStoreSearchResult::Duplicate() const { + std::unique_ptr<ArcPlayStoreSearchResult> result = + base::MakeUnique<ArcPlayStoreSearchResult>(data_.Clone(), profile_, + list_controller_); + result->SetIcon(icon()); + return result; +} + +void ArcPlayStoreSearchResult::Open(int event_flags) { + arc::mojom::AppInstance* app_instance = + arc::ArcServiceManager::Get() + ? ARC_GET_INSTANCE_FOR_METHOD( + arc::ArcServiceManager::Get()->arc_bridge_service()->app(), + LaunchIntent) + : nullptr; + if (app_instance == nullptr) + return; + + app_instance->LaunchIntent(install_intent_uri().value(), base::nullopt); +} + +ui::MenuModel* ArcPlayStoreSearchResult::GetContextMenuModel() { + context_menu_ = base::MakeUnique<ArcPlayStoreAppContextMenu>( + this, profile_, list_controller_); + return context_menu_->GetMenuModel(); +} + +void ArcPlayStoreSearchResult::ExecuteLaunchCommand(int event_flags) { + Open(event_flags); +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h new file mode 100644 index 0000000..244efdc --- /dev/null +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h
@@ -0,0 +1,70 @@ +// Copyright 2017 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 CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_RESULT_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_RESULT_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/optional.h" +#include "chrome/browser/ui/app_list/app_context_menu_delegate.h" +#include "components/arc/common/app.mojom.h" +#include "ui/app_list/search_result.h" + +class AppListControllerDelegate; +class ArcPlayStoreAppContextMenu; +class Profile; + +namespace app_list { + +class ArcPlayStoreSearchResult : public SearchResult, + public AppContextMenuDelegate { + public: + ArcPlayStoreSearchResult(arc::mojom::AppDiscoveryResultPtr data, + Profile* profile, + AppListControllerDelegate* list_controller_); + ~ArcPlayStoreSearchResult() override; + + // app_list::SearchResult overrides: + std::unique_ptr<SearchResult> Duplicate() const override; + + // app_list::AppContextMenuDelegate overrides: + ui::MenuModel* GetContextMenuModel() override; + void Open(int event_flags) override; + void ExecuteLaunchCommand(int event_flags) override; + + private: + class IconDecodeRequest; + + const base::Optional<std::string>& install_intent_uri() const { + return data_->install_intent_uri; + } + const base::Optional<std::string>& label() const { return data_->label; } + bool is_instant_app() const { return data_->is_instant_app; } + const base::Optional<std::string>& formatted_price() const { + return data_->formatted_price; + } + float review_score() const { return data_->review_score; } + const std::vector<uint8_t>& icon_png_data() const { + return data_->icon_png_data; + } + + arc::mojom::AppDiscoveryResultPtr data_; + std::unique_ptr<IconDecodeRequest> icon_decode_request_; + + // |profile_| is owned by ProfileInfo. + Profile* const profile_; + // |list_controller_| is owned by AppListServiceAsh and lives + // until the service finishes. + AppListControllerDelegate* const list_controller_; + std::unique_ptr<ArcPlayStoreAppContextMenu> context_menu_; + + DISALLOW_COPY_AND_ASSIGN(ArcPlayStoreSearchResult); +}; + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_PLAYSTORE_SEARCH_RESULT_H_
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc index a0a6a3e5..e1ed3cc6 100644 --- a/chrome/browser/ui/app_list/search/arc_app_result.cc +++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -66,8 +66,10 @@ } ui::MenuModel* ArcAppResult::GetContextMenuModel() { - context_menu_.reset(new ArcAppContextMenu( - this, profile(), app_id(), controller())); + if (!context_menu_) { + context_menu_.reset( + new ArcAppContextMenu(this, profile(), app_id(), controller())); + } return context_menu_->GetMenuModel(); }
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index b0d21a3..dfa37ec6 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -28,6 +28,10 @@ #include "ui/app_list/search/mixer.h" #include "ui/app_list/search_controller.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h" +#endif + namespace app_list { namespace { @@ -38,6 +42,9 @@ constexpr size_t kMaxWebstoreResults = 2; constexpr size_t kMaxSuggestionsResults = 6; constexpr size_t kMaxLauncherSearchResults = 2; +#if defined(OS_CHROMEOS) +constexpr size_t kMaxPlayStoreResults = 2; +#endif // Constants related to the SuggestionsService in AppList field trial. constexpr char kSuggestionsProviderFieldTrialName[] = @@ -113,6 +120,13 @@ base::MakeUnique<LauncherSearchProvider>(profile)); } +#if defined(OS_CHROMEOS) + size_t playstore_api_group_id = + controller->AddGroup(kMaxPlayStoreResults, 1.0); + controller->AddProvider(playstore_api_group_id, + base::MakeUnique<ArcPlayStoreSearchProvider>( + kMaxPlayStoreResults, profile, list_controller)); +#endif return controller; }
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.cc index 7576baa5..50aeec6c 100644 --- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.cc +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h" #include "chrome/grit/generated_resources.h" #include "extensions/browser/api/device_permissions_manager.h" +#include "extensions/browser/api/file_system/saved_file_entry.h" #include "extensions/common/extension.h" #include "extensions/common/permissions/api_permission.h" #include "extensions/common/permissions/permissions_data.h" @@ -296,9 +297,9 @@ apps::SavedFilesService* service = apps::SavedFilesService::Get(profile_); // The SavedFilesService can be null for incognito profiles. if (service) { - std::vector<apps::SavedFileEntry> retained_file_entries = + std::vector<extensions::SavedFileEntry> retained_file_entries = service->GetAllFileEntries(app_->id()); - for (std::vector<apps::SavedFileEntry>::const_iterator it = + for (std::vector<extensions::SavedFileEntry>::const_iterator it = retained_file_entries.begin(); it != retained_file_entries.end(); ++it) { retained_file_paths.push_back(it->path.LossyDisplayName());
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 29840ec..4197368 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -506,6 +506,7 @@ "//third_party/accessibility-audit/axs_testing.js", "//third_party/chaijs/chai.js", "//third_party/mocha/mocha.js", + "//third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js", "//third_party/pyftpdlib/", "//third_party/pywebsocket/", "//third_party/tlslite/",
diff --git a/chrome/test/DEPS b/chrome/test/DEPS index 5123256..6072e6e1 100644 --- a/chrome/test/DEPS +++ b/chrome/test/DEPS
@@ -28,5 +28,4 @@ "+mojo/edk/embedder", "+sandbox/win/tests", "+third_party/ocmock", - "+win8/test", ]
diff --git a/chrome/test/data/webui/polymer_browser_test_base.js b/chrome/test/data/webui/polymer_browser_test_base.js index 150a30b..bbbac975 100644 --- a/chrome/test/data/webui/polymer_browser_test_base.js +++ b/chrome/test/data/webui/polymer_browser_test_base.js
@@ -40,6 +40,8 @@ 'ui/webui/resources/js/promise_resolver.js', 'third_party/mocha/mocha.js', 'chrome/test/data/webui/mocha_adapter.js', + 'third_party/polymer/v1_0/components-chromium/iron-test-helpers/' + + 'mock-interactions.js', ], /** @override */ @@ -76,22 +78,11 @@ } }; - // Import Polymer and iron-test-helpers before running tests. + // Import Polymer before running tests. suiteSetup(function() { - var promises = []; if (!window.Polymer) { - promises.push( - PolymerTest.importHtml('chrome://resources/html/polymer.html')); + return PolymerTest.importHtml('chrome://resources/html/polymer.html'); } - if (typeof MockInteractions != 'object') { - // Avoid importing the HTML file because iron-test-helpers assumes it is - // not being imported separately alongside a vulcanized Polymer. - promises.push( - PolymerTest.loadScript( - 'chrome://resources/polymer/v1_0/iron-test-helpers/' + - 'mock-interactions.js')); - } - return Promise.all(promises); }); },
diff --git a/components/arc/common/app.mojom b/components/arc/common/app.mojom index 6348d525..b1e474b9 100644 --- a/components/arc/common/app.mojom +++ b/components/arc/common/app.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 20 +// Next MinVersion: 21 module arc.mojom; @@ -75,6 +75,19 @@ MANAGE_LINKS = 1, }; +// Describes a Play Store app discovery result. +struct AppDiscoveryResult { + string? launch_intent_uri; + string? install_intent_uri; + string? label; + bool is_instant_app; + bool is_recent; + string? publisher_name; + string? formatted_price; + float review_score; + array<uint8> icon_png_data; +}; + // Next method ID: 18 interface AppHost { // Sends newly added ARC app to Chrome. This message is sent when ARC receives @@ -161,7 +174,7 @@ }; // TODO(lhchavez): Migrate all request/response messages to Mojo. -// Next method ID: 16 +// Next method ID: 17 // Deprecated method ID: 9 interface AppInstance { Init@0(AppHost host_ptr); @@ -233,4 +246,9 @@ // Sends a request to ARC to uninstall the given package. Error (if ever // happens) is ignored, and uninstall option should appear in the UI. [MinVersion=2] UninstallPackage@5(string package_name); + + // Starts a query for Play Store apps. + [MinVersion=20] GetRecentAndSuggestedAppsFromPlayStore@16( + string query, int32 max_results) => + (array<AppDiscoveryResult> results); };
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc index 0b3ecbf..83e4ee8 100644 --- a/components/arc/test/fake_app_instance.cc +++ b/components/arc/test/fake_app_instance.cc
@@ -42,6 +42,12 @@ : app_host_(app_host) {} FakeAppInstance::~FakeAppInstance() {} +void FakeAppInstance::Init(mojom::AppHostPtr host_ptr) { + // ARC app instance calls RefreshAppList after Init() successfully. Call + // RefreshAppList() here to keep the same behavior. + RefreshAppList(); +} + void FakeAppInstance::RefreshAppList() { ++refresh_app_list_count_; } @@ -267,6 +273,13 @@ app_host_->OnPackageAdded(std::move(arcPackageInfo)); } +void FakeAppInstance::GetRecentAndSuggestedAppsFromPlayStore( + const std::string& query, + int32_t max_results, + const GetRecentAndSuggestedAppsFromPlayStoreCallback& callback) { + callback.Run(std::vector<arc::mojom::AppDiscoveryResultPtr>()); +} + void FakeAppInstance::LaunchIntent( const std::string& intent_uri, const base::Optional<gfx::Rect>& dimension_on_screen) {
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h index 52e287a..ce65bce 100644 --- a/components/arc/test/fake_app_instance.h +++ b/components/arc/test/fake_app_instance.h
@@ -79,7 +79,7 @@ ~FakeAppInstance() override; // mojom::AppInstance overrides: - void Init(mojom::AppHostPtr host_ptr) override {} + void Init(mojom::AppHostPtr host_ptr) override; void RefreshAppList() override; void LaunchApp(const std::string& package_name, const std::string& activity, @@ -112,6 +112,10 @@ void SetNotificationsEnabled(const std::string& package_name, bool enabled) override; void InstallPackage(mojom::ArcPackageInfoPtr arcPackageInfo) override; + void GetRecentAndSuggestedAppsFromPlayStore( + const std::string& query, + int32_t max_results, + const GetRecentAndSuggestedAppsFromPlayStoreCallback& callback) override; // Methods to reply messages. void SendRefreshAppList(const std::vector<mojom::AppInfo>& apps);
diff --git a/components/navigation_interception/intercept_navigation_delegate.cc b/components/navigation_interception/intercept_navigation_delegate.cc index b6a3b11..b8cd316 100644 --- a/components/navigation_interception/intercept_navigation_delegate.cc +++ b/components/navigation_interception/intercept_navigation_delegate.cc
@@ -89,7 +89,7 @@ InterceptNavigationDelegate::CreateThrottleFor( content::NavigationHandle* handle) { return base::MakeUnique<InterceptNavigationThrottle>( - handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread)); + handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread), false); } // static
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc index db7a1dd1..a6bbcd0 100644 --- a/components/navigation_interception/intercept_navigation_throttle.cc +++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -12,11 +12,38 @@ namespace navigation_interception { +namespace { + +using ChecksPerformedCallback = base::Callback<void(bool)>; + +// This is used to run |should_ignore_callback| if it can destroy the +// WebContents (and the InterceptNavigationThrottle along). In that case, +// |on_checks_performed_callback| will be a no-op. +void RunCallback( + content::WebContents* web_contents, + const NavigationParams& navigation_params, + InterceptNavigationThrottle::CheckCallback should_ignore_callback, + ChecksPerformedCallback on_checks_performed_callback, + base::WeakPtr<InterceptNavigationThrottle> throttle) { + bool should_ignore_navigation = + should_ignore_callback.Run(web_contents, navigation_params); + + // If the InterceptNavigationThrottle that called RunCallback is still alive + // after |should_ignore_callback| has run, this will run + // InterceptNavigationThrottle::OnAsynchronousChecksPerformed. + on_checks_performed_callback.Run(should_ignore_navigation); +} + +} // namespace + InterceptNavigationThrottle::InterceptNavigationThrottle( content::NavigationHandle* navigation_handle, - CheckCallback should_ignore_callback) + CheckCallback should_ignore_callback, + bool run_callback_synchronously) : content::NavigationThrottle(navigation_handle), - should_ignore_callback_(should_ignore_callback) {} + should_ignore_callback_(should_ignore_callback), + run_callback_synchronously_(run_callback_synchronously), + weak_factory_(this) {} InterceptNavigationThrottle::~InterceptNavigationThrottle() {} @@ -45,11 +72,58 @@ navigation_handle()->GetPageTransition(), is_redirect, navigation_handle()->IsExternalProtocol(), true, navigation_handle()->GetBaseURLForDataURL()); - bool should_ignore_navigation = should_ignore_callback_.Run( - navigation_handle()->GetWebContents(), navigation_params); - return should_ignore_navigation - ? content::NavigationThrottle::CANCEL_AND_IGNORE - : content::NavigationThrottle::PROCEED; + + if (run_callback_synchronously_) { + bool should_ignore_navigation = should_ignore_callback_.Run( + navigation_handle()->GetWebContents(), navigation_params); + return should_ignore_navigation + ? content::NavigationThrottle::CANCEL_AND_IGNORE + : content::NavigationThrottle::PROCEED; + } + + // When the callback can potentially destroy the WebContents, along with the + // NavigationHandle and this InterceptNavigationThrottle, it should be run + // asynchronously. This will ensure that no objects on the stack can be + // deleted, and that the stack does not unwind through them in a deleted + // state. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&InterceptNavigationThrottle::RunCallbackAsynchronously, + weak_factory_.GetWeakPtr(), navigation_params)); + return DEFER; +} + +void InterceptNavigationThrottle::RunCallbackAsynchronously( + const NavigationParams& navigation_params) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // Run the callback in a helper function as it may lead ot the destruction of + // this InterceptNavigationThrottle. + RunCallback( + navigation_handle()->GetWebContents(), navigation_params, + should_ignore_callback_, + base::Bind(&InterceptNavigationThrottle::OnAsynchronousChecksPerformed, + weak_factory_.GetWeakPtr()), + weak_factory_.GetWeakPtr()); + + // DO NOT ADD CODE AFTER HERE: at this point the InterceptNavigationThrottle + // may have been destroyed by the |should_ignore_callback_|. Adding code here + // will cause use-after-free bugs. + // + // Code that needs to act on the result of the |should_ignore_callback_| + // should be put inside OnAsynchronousChecksPerformed. This function will be + // called after |should_ignore_callback_| has run, if this + // InterceptNavigationThrottle is still alive. +} + +void InterceptNavigationThrottle::OnAsynchronousChecksPerformed( + bool should_ignore_navigation) { + if (should_ignore_navigation) { + navigation_handle()->CancelDeferredNavigation( + content::NavigationThrottle::CANCEL_AND_IGNORE); + } else { + navigation_handle()->Resume(); + } } } // namespace navigation_interception
diff --git a/components/navigation_interception/intercept_navigation_throttle.h b/components/navigation_interception/intercept_navigation_throttle.h index 7607fd5f..09158b8 100644 --- a/components/navigation_interception/intercept_navigation_throttle.h +++ b/components/navigation_interception/intercept_navigation_throttle.h
@@ -30,7 +30,8 @@ CheckCallback; InterceptNavigationThrottle(content::NavigationHandle* navigation_handle, - CheckCallback should_ignore_callback); + CheckCallback should_ignore_callback, + bool run_callback_synchronously); ~InterceptNavigationThrottle() override; // content::NavigationThrottle implementation: @@ -41,8 +42,19 @@ private: ThrottleCheckResult CheckIfShouldIgnoreNavigation(bool is_redirect); + // Called to perform the checks asynchronously + void RunCallbackAsynchronously(const NavigationParams& navigation_params); + void OnAsynchronousChecksPerformed(bool should_ignore_navigation); + CheckCallback should_ignore_callback_; + // Whether the callback will be run synchronously or not. If the callback can + // lead to the destruction of the WebContents, this should be false. + // Otherwise this should be true. + const bool run_callback_synchronously_; + + base::WeakPtrFactory<InterceptNavigationThrottle> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(InterceptNavigationThrottle); };
diff --git a/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/components/navigation_interception/intercept_navigation_throttle_unittest.cc index 0b3ed14..a6d27c49 100644 --- a/components/navigation_interception/intercept_navigation_throttle_unittest.cc +++ b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -68,7 +68,8 @@ base::MakeUnique<InterceptNavigationThrottle>( test_handle.get(), base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation, - base::Unretained(mock_callback_receiver_.get())))); + base::Unretained(mock_callback_receiver_.get())), + true)); return test_handle->CallWillStartRequestForTesting( is_post, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false); } @@ -81,7 +82,8 @@ base::MakeUnique<InterceptNavigationThrottle>( test_handle.get(), base::Bind(&MockInterceptCallbackReceiver::ShouldIgnoreNavigation, - base::Unretained(mock_callback_receiver_.get())))); + base::Unretained(mock_callback_receiver_.get())), + true)); test_handle->CallWillStartRequestForTesting( true, content::Referrer(), false, ui::PAGE_TRANSITION_LINK, false); return test_handle->CallWillRedirectRequestForTesting(GURL(kTestUrl), false,
diff --git a/components/offline_pages/core/DEPS b/components/offline_pages/core/DEPS index 5ef8eb9f..5d8bc16 100644 --- a/components/offline_pages/core/DEPS +++ b/components/offline_pages/core/DEPS
@@ -1,8 +1,4 @@ include_rules = [ "+components/keyed_service", - "+components/gcm_driver", - "+components/ntp_snippets", - "+components/version_info", - "+net", "+sql", ]
diff --git a/components/offline_pages/core/background/DEPS b/components/offline_pages/core/background/DEPS index 6fff87d..5f8ec85 100644 --- a/components/offline_pages/core/background/DEPS +++ b/components/offline_pages/core/background/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+sql", + "+net", ]
diff --git a/components/offline_pages/core/prefetch/DEPS b/components/offline_pages/core/prefetch/DEPS index 9a26362..4a85e6c 100644 --- a/components/offline_pages/core/prefetch/DEPS +++ b/components/offline_pages/core/prefetch/DEPS
@@ -1,3 +1,7 @@ include_rules = [ "+google_apis", + "+components/gcm_driver", + "+components/ntp_snippets", + "+components/version_info", + "+net", ]
diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn index 51b0570..eb5b5f9 100644 --- a/components/safe_browsing/common/BUILD.gn +++ b/components/safe_browsing/common/BUILD.gn
@@ -14,10 +14,13 @@ "safebrowsing_switches.cc", "safebrowsing_switches.h", "safebrowsing_types.h", + "utils.cc", + "utils.h", ] deps = [ "//base", + "//crypto:crypto", "//ipc", "//url/ipc:url_ipc", ]
diff --git a/components/safe_browsing/common/DEPS b/components/safe_browsing/common/DEPS index 61eff427..c908d82 100644 --- a/components/safe_browsing/common/DEPS +++ b/components/safe_browsing/common/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/prefs", + "+crypto/sha2.h", "+ipc", "+url" ]
diff --git a/components/safe_browsing/common/utils.cc b/components/safe_browsing/common/utils.cc new file mode 100644 index 0000000..67baa8c1 --- /dev/null +++ b/components/safe_browsing/common/utils.cc
@@ -0,0 +1,25 @@ +// Copyright 2017 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 "components/safe_browsing/common/utils.h" + +#include "base/strings/string_number_conversions.h" +#include "crypto/sha2.h" + +namespace safe_browsing { + +std::string ShortURLForReporting(const GURL& url) { + std::string spec(url.spec()); + if (url.SchemeIs(url::kDataScheme)) { + size_t comma_pos = spec.find(','); + if (comma_pos != std::string::npos && comma_pos != spec.size() - 1) { + std::string hash_value = crypto::SHA256HashString(spec); + spec.erase(comma_pos + 1); + spec += base::HexEncode(hash_value.data(), hash_value.size()); + } + } + return spec; +} + +} // namespace safe_browsing
diff --git a/components/safe_browsing/common/utils.h b/components/safe_browsing/common/utils.h new file mode 100644 index 0000000..fa3b8a7 --- /dev/null +++ b/components/safe_browsing/common/utils.h
@@ -0,0 +1,20 @@ +// Copyrights 2017 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. +// +// Safe Browsing utility functions. + +#ifndef COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_ +#define COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_ + +#include "url/gurl.h" + +namespace safe_browsing { + +// Shorten URL by replacing its contents with its SHA256 hash if it has data +// scheme. +std::string ShortURLForReporting(const GURL& url); + +} // namespace safe_browsing + +#endif // COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
diff --git a/components/safe_browsing/csd.proto b/components/safe_browsing/csd.proto index 132372dc..0e3a5aa 100644 --- a/components/safe_browsing/csd.proto +++ b/components/safe_browsing/csd.proto
@@ -509,6 +509,8 @@ [deprecated = true]; } +// Please update SafeBrowsingNavigationObserverManager::SanitizeReferrerChain() +// if you're adding more fields to this message. message ReferrerChainEntry { enum URLType { // URL of safe browsing events that are at the end of the referrer chain.
diff --git a/content/browser/DEPS b/content/browser/DEPS index ed5f31a5..da28d41 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -41,7 +41,6 @@ "+ui/aura_extra", "+ui/vector_icons", "+ui/webui", - "+win8/util", # In general, //content shouldn't depend on //device. # This is the an exception.
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 298b011..df73588 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1405,10 +1405,13 @@ RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html")); } +// Disabled because it is flaky in several platforms +/* IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityModalDialogInIframeOpened) { RunHtmlTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html")); } +*/ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityModalDialogStack) {
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index c130d36..95bc35f 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -262,7 +262,8 @@ const CommonNavigationParams& common_params, const BeginNavigationParams& begin_params, int current_history_list_offset, - int current_history_list_length) { + int current_history_list_length, + bool override_user_agent) { // Only normal navigations to a different document or reloads are expected. // - Renderer-initiated fragment-navigations never take place in the browser, // even with PlzNavigate. @@ -274,12 +275,10 @@ common_params.navigation_type == FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT); - // TODO(clamy): See how we should handle override of the user agent when the - // navigation may start in a renderer and commit in another one. // TODO(clamy): See if the navigation start time should be measured in the // renderer and sent to the browser instead of being measured here. RequestNavigationParams request_params( - false, // is_overriding_user_agent + override_user_agent, std::vector<GURL>(), // redirects common_params.url, common_params.method, false, // can_load_local_resources @@ -358,13 +357,14 @@ common_params_.method == "POST"); // Add necessary headers that may not be present in the BeginNavigationParams. - std::string user_agent_override; - if (entry) { + if (entry) nav_entry_id_ = entry->GetUniqueID(); - if (entry->GetIsOverridingUserAgent()) { - user_agent_override = - frame_tree_node_->navigator()->GetDelegate()->GetUserAgentOverride(); - } + + std::string user_agent_override; + if (request_params.is_overriding_user_agent || + (entry && entry->GetIsOverridingUserAgent())) { + user_agent_override = + frame_tree_node_->navigator()->GetDelegate()->GetUserAgentOverride(); } net::HttpRequestHeaders headers;
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 73856c4..a4b2e01 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -98,7 +98,8 @@ const CommonNavigationParams& common_params, const BeginNavigationParams& begin_params, int current_history_list_offset, - int current_history_list_length); + int current_history_list_length, + bool override_user_agent); ~NavigationRequest() override;
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index f21afa5..9f9285ee 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -1022,11 +1022,14 @@ navigation_data_.reset(); } NavigationEntryImpl* pending_entry = controller_->GetPendingEntry(); + NavigationEntryImpl* current_entry = controller_->GetLastCommittedEntry(); + bool override_user_agent = + current_entry ? current_entry->GetIsOverridingUserAgent() : false; frame_tree_node->CreatedNavigationRequest( NavigationRequest::CreateRendererInitiated( frame_tree_node, pending_entry, common_params, begin_params, controller_->GetLastCommittedEntryIndex(), - controller_->GetEntryCount())); + controller_->GetEntryCount(), override_user_agent)); NavigationRequest* navigation_request = frame_tree_node->navigation_request(); // For main frames, NavigationHandle will be created after the call to
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc index 10fc3ff..178797d1 100644 --- a/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/legacy_input_router_impl_unittest.cc
@@ -149,31 +149,55 @@ } #endif // defined(USE_AURA) +enum WheelScrollingMode { + kWheelScrollingModeNone, + kWheelScrollLatching, + kAsyncWheelEvents, +}; + } // namespace class LegacyInputRouterImplTest : public testing::Test { public: - LegacyInputRouterImplTest(bool raf_aligned_touch = true, - bool wheel_scroll_latching = true) - : scoped_task_environment_( + LegacyInputRouterImplTest( + bool raf_aligned_touch = true, + WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching) + : wheel_scroll_latching_enabled_(wheel_scrolling_mode != + kWheelScrollingModeNone), + scoped_task_environment_( base::test::ScopedTaskEnvironment::MainThreadType::UI) { - if (raf_aligned_touch && wheel_scroll_latching) { + if (raf_aligned_touch && wheel_scrolling_mode == kAsyncWheelEvents) { + feature_list_.InitWithFeatures({features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {}); + } else if (raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollLatching) { feature_list_.InitWithFeatures( {features::kRafAlignedTouchInputEvents, features::kTouchpadAndWheelScrollLatching}, - {}); - } else if (raf_aligned_touch && !wheel_scroll_latching) { - feature_list_.InitWithFeatures( - {features::kRafAlignedTouchInputEvents}, - {features::kTouchpadAndWheelScrollLatching}); - } else if (!raf_aligned_touch && wheel_scroll_latching) { + {features::kAsyncWheelEvents}); + } else if (raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollingModeNone) { + feature_list_.InitWithFeatures({features::kRafAlignedTouchInputEvents}, + {features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); + } else if (!raf_aligned_touch && + wheel_scrolling_mode == kAsyncWheelEvents) { + feature_list_.InitWithFeatures({features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {features::kRafAlignedTouchInputEvents}); + } else if (!raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollLatching) { feature_list_.InitWithFeatures( {features::kTouchpadAndWheelScrollLatching}, - {features::kRafAlignedTouchInputEvents}); - } else { // !raf_aligned_touch && !wheel_scroll_latching - feature_list_.InitWithFeatures( - {}, {features::kRafAlignedTouchInputEvents, - features::kTouchpadAndWheelScrollLatching}); + {features::kRafAlignedTouchInputEvents, features::kAsyncWheelEvents}); + } else { // !raf_aligned_touch && wheel_scroll_latching == + // kWheelScrollingModeNone. + feature_list_.InitWithFeatures({}, + {features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); } } @@ -248,6 +272,21 @@ input_router_->SendWheelEvent(MouseWheelEventWithLatencyInfo(wheel_event)); } + void SimulateWheelEventPossiblyIncludingPhase( + bool ignore_phase, + float x, + float y, + float dX, + float dY, + int modifiers, + bool precise, + WebMouseWheelEvent::Phase phase) { + if (ignore_phase) + SimulateWheelEvent(x, y, dX, dY, modifiers, precise); + else + SimulateWheelEventWithPhase(x, y, dX, dY, modifiers, precise, phase); + } + void SimulateMouseEvent(WebInputEvent::Type type, int x, int y) { input_router_->SendMouseEvent(MouseEventWithLatencyInfo( SyntheticWebMouseEventBuilder::Build(type, x, y, 0))); @@ -379,91 +418,16 @@ base::RunLoop().Run(); } - void UnhandledWheelEvent(bool wheel_scroll_latching_enabled) { - // Simulate wheel events. - if (wheel_scroll_latching_enabled) { - SimulateWheelEventWithPhase( - 0, 0, 0, -5, 0, false, - WebMouseWheelEvent::kPhaseBegan); // sent directly - SimulateWheelEventWithPhase( - 0, 0, 0, -10, 0, false, - WebMouseWheelEvent::kPhaseChanged); // enqueued - } else { - SimulateWheelEvent(0, 0, 0, -5, 0, false); // sent directly - SimulateWheelEvent(0, 0, 0, -10, 0, false); // enqueued - } + void UnhandledWheelEvent(); - // Check that only the first event was sent. - EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - - // Indicate that the wheel event was unhandled. - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - - // Check that the ack for the MouseWheel and ScrollBegin - // were processed. - EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); - - // There should be a ScrollBegin and ScrollUpdate, MouseWheel sent. - EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); - - EXPECT_EQ(ack_handler_->acked_wheel_event().delta_y, -5); - SendInputEventACK(WebInputEvent::kGestureScrollUpdate, - INPUT_EVENT_ACK_STATE_CONSUMED); - - if (wheel_scroll_latching_enabled) { - // Check that the ack for ScrollUpdate were processed. - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); - } else { - // The GestureScrollUpdate ACK releases the GestureScrollEnd. - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - - // Check that the ack for the ScrollUpdate and ScrollEnd - // were processed. - EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); - } - - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - - if (wheel_scroll_latching_enabled) { - // There should be a ScrollUpdate sent. - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); - } else { - // There should be a ScrollBegin and ScrollUpdate sent. - EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); - EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); - } - - // Check that the correct unhandled wheel event was received. - EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, - ack_handler_->acked_wheel_event_state()); - EXPECT_EQ(ack_handler_->acked_wheel_event().delta_y, -10); - - SendInputEventACK(WebInputEvent::kGestureScrollUpdate, - INPUT_EVENT_ACK_STATE_CONSUMED); - - if (wheel_scroll_latching_enabled) { - // Check that the ack for ScrollUpdate were processed. - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); - } else { - // The GestureScrollUpdate ACK releases the GestureScrollEnd. - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - - // Check that the ack for the ScrollUpdate and ScrollEnd - // were processed. - EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); - } - } + void OverscrollDispatch(); InputRouter::Config config_; std::unique_ptr<MockRenderProcessHost> process_; std::unique_ptr<MockInputRouterClient> client_; std::unique_ptr<MockInputAckHandler> ack_handler_; std::unique_ptr<LegacyInputRouterImpl> input_router_; + bool wheel_scroll_latching_enabled_; private: base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -477,14 +441,21 @@ : public LegacyInputRouterImplTest { public: LegacyInputRouterImplRafAlignedTouchDisabledTest() - : LegacyInputRouterImplTest(false, false) {} + : LegacyInputRouterImplTest(false, kWheelScrollingModeNone) {} }; class LegacyInputRouterImplWheelScrollLatchingDisabledTest : public LegacyInputRouterImplTest { public: LegacyInputRouterImplWheelScrollLatchingDisabledTest() - : LegacyInputRouterImplTest(true, false) {} + : LegacyInputRouterImplTest(true, kWheelScrollingModeNone) {} +}; + +class LegacyInputRouterImplAsyncWheelEventEnabledTest + : public LegacyInputRouterImplTest { + public: + LegacyInputRouterImplAsyncWheelEventEnabledTest() + : LegacyInputRouterImplTest(true, kAsyncWheelEvents) {} }; TEST_F(LegacyInputRouterImplTest, CoalescesRangeSelection) { @@ -578,8 +549,8 @@ new InputMsg_SelectRange(0, gfx::Point(7, 8), gfx::Point(9, 10)))); EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); - // Ack the messages and verify that they're not coalesced and that they're in - // correct order. + // Ack the messages and verify that they're not coalesced and that they're + // in correct order. // Ack the first message. { @@ -658,8 +629,8 @@ input_router_->OnMessageReceived(*response); } - // Verify that the three MoveRangeSelectionExtent messages are coalesced into - // one message. + // Verify that the three MoveRangeSelectionExtent messages are coalesced + // into one message. ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>( process_->sink().GetMessageAt(0), gfx::Point(9, 10)); EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); @@ -774,7 +745,7 @@ EXPECT_TRUE(ack_handler_->unexpected_event_ack_called()); } -// Tests ported from RenderWidgetHostTest -------------------------------------- +// Tests ported from RenderWidgetHostTest ------------------------------------- TEST_F(LegacyInputRouterImplTest, HandleKeyEventsWeSent) { // Simulate a keyboard event. @@ -806,11 +777,21 @@ TEST_F(LegacyInputRouterImplTest, CoalescesWheelEvents) { // Simulate wheel events. - SimulateWheelEvent(0, 0, 0, -5, 0, false); // sent directly - SimulateWheelEvent(0, 0, 0, -10, 0, false); // enqueued - SimulateWheelEvent(0, 0, 8, -6, 0, false); // coalesced into previous event - SimulateWheelEvent(0, 0, 9, -7, 1, false); // enqueued, different modifiers - SimulateWheelEvent(0, 0, 0, -10, 0, false); // enqueued, different modifiers + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, 0, 0, 0, -5, 0, false, + WebMouseWheelEvent::kPhaseBegan); // sent directly + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, 0, 0, 0, -10, 0, false, + WebMouseWheelEvent::kPhaseChanged); // enqueued + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, 0, 0, 8, -6, 0, false, + WebMouseWheelEvent::kPhaseChanged); // coalesced into previous event + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, 0, 0, 9, -7, 1, false, + WebMouseWheelEvent::kPhaseChanged); // enqueued, different modifiers + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, 0, 0, 0, -10, 0, false, + WebMouseWheelEvent::kPhaseChanged); // enqueued, different modifiers // Explicitly verify that PhaseEnd isn't coalesced to avoid bugs like // https://crbug.com/154740. SimulateWheelEventWithPhase(WebMouseWheelEvent::kPhaseEnded); // enqueued @@ -960,8 +941,8 @@ EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); } -// Tests that the touch-queue is emptied after a page stops listening for touch -// events and the outstanding ack is received. +// Tests that the touch-queue is emptied after a page stops listening for +// touch events and the outstanding ack is received. TEST_F(LegacyInputRouterImplTest, TouchEventQueueFlush) { OnHasTouchEventHandlers(true); EXPECT_TRUE(client_->has_touch_handler()); @@ -1089,12 +1070,131 @@ } #endif // defined(USE_AURA) +void LegacyInputRouterImplTest::UnhandledWheelEvent() { + // Simulate wheel events. + SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 0, + 0, 0, -5, 0, false, + WebMouseWheelEvent::kPhaseBegan); + SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 0, + 0, 0, -10, 0, false, + WebMouseWheelEvent::kPhaseChanged); + + // Check that only the first event was sent. + EXPECT_TRUE( + process_->sink().GetUniqueMessageMatching(InputMsg_HandleInputEvent::ID)); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + + // Indicate that the wheel event was unhandled. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + // Check that the ack for the MouseWheel and ScrollBegin + // were processed. + EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); + + // There should be a ScrollBegin and ScrollUpdate, MouseWheel sent. + EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); + + EXPECT_EQ(ack_handler_->acked_wheel_event().delta_y, -5); + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + + if (wheel_scroll_latching_enabled_) { + // Check that the ack for ScrollUpdate were processed. + EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + } else { + // The GestureScrollUpdate ACK releases the GestureScrollEnd. + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + + // Check that the ack for the ScrollUpdate and ScrollEnd + // were processed. + EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); + } + + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + if (wheel_scroll_latching_enabled_) { + // There should be a ScrollUpdate sent. + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + } else { + // There should be a ScrollBegin and ScrollUpdate sent. + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); + } + + // Check that the correct unhandled wheel event was received. + EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, + ack_handler_->acked_wheel_event_state()); + EXPECT_EQ(ack_handler_->acked_wheel_event().delta_y, -10); + + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + + if (wheel_scroll_latching_enabled_) { + // Check that the ack for ScrollUpdate were processed. + EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + } else { + // The GestureScrollUpdate ACK releases the GestureScrollEnd. + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + + // Check that the ack for the ScrollUpdate and ScrollEnd + // were processed. + EXPECT_EQ(2U, ack_handler_->GetAndResetAckCount()); + } +} + TEST_F(LegacyInputRouterImplTest, UnhandledWheelEvent) { - UnhandledWheelEvent(true); + UnhandledWheelEvent(); } TEST_F(LegacyInputRouterImplWheelScrollLatchingDisabledTest, UnhandledWheelEvent) { - UnhandledWheelEvent(false); + UnhandledWheelEvent(); +} +TEST_F(LegacyInputRouterImplAsyncWheelEventEnabledTest, UnhandledWheelEvent) { + // Simulate wheel events. + SimulateWheelEventWithPhase(0, 0, 0, -5, 0, false, + WebMouseWheelEvent::kPhaseBegan); + SimulateWheelEventWithPhase(0, 0, 0, -10, 0, false, + WebMouseWheelEvent::kPhaseChanged); + + // Check that only the first event was sent. + EXPECT_TRUE( + process_->sink().GetUniqueMessageMatching(InputMsg_HandleInputEvent::ID)); + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + + // Indicate that the wheel event was unhandled. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + + // Check that the ack for the first MouseWheel, ScrollBegin, and the second + // MouseWheel were processed. + EXPECT_EQ(3U, ack_handler_->GetAndResetAckCount()); + + // There should be a ScrollBegin and ScrollUpdate, MouseWheel sent. + EXPECT_EQ(3U, GetSentMessageCountAndResetSink()); + + // The last acked wheel event should be the second one since the input router + // has alread sent the immediate ack for the second wheel event. + EXPECT_EQ(ack_handler_->acked_wheel_event().delta_y, -10); + EXPECT_EQ(INPUT_EVENT_ACK_STATE_IGNORED, + ack_handler_->acked_wheel_event_state()); + + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + + // Check that the ack for the first ScrollUpdate were processed. + EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + + // There should be a second ScrollUpdate sent. + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + + // Check that the ack for ScrollUpdate were processed. + EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); } TEST_F(LegacyInputRouterImplTest, TouchTypesIgnoringAck) { @@ -1892,7 +1992,7 @@ // Test proper routing of overscroll notifications received either from // event acks or from |DidOverscroll| IPC messages. -TEST_F(LegacyInputRouterImplTest, OverscrollDispatch) { +void LegacyInputRouterImplTest::OverscrollDispatch() { DidOverscrollParams overscroll; overscroll.accumulated_overscroll = gfx::Vector2dF(-14, 14); overscroll.latest_overscroll_delta = gfx::Vector2dF(-7, 0); @@ -1912,7 +2012,9 @@ wheel_overscroll.latest_overscroll_delta = gfx::Vector2dF(3, 0); wheel_overscroll.current_fling_velocity = gfx::Vector2dF(1, 0); - SimulateWheelEvent(0, 0, 3, 0, 0, false); + SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 0, + 0, 3, 0, 0, false, + WebMouseWheelEvent::kPhaseBegan); InputEventAck ack(InputEventAckSource::COMPOSITOR_THREAD, WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -1927,6 +2029,16 @@ EXPECT_EQ(wheel_overscroll.current_fling_velocity, client_overscroll.current_fling_velocity); } +TEST_F(LegacyInputRouterImplTest, OverscrollDispatch) { + OverscrollDispatch(); +} +TEST_F(LegacyInputRouterImplWheelScrollLatchingDisabledTest, + OverscrollDispatch) { + OverscrollDispatch(); +} +TEST_F(LegacyInputRouterImplAsyncWheelEventEnabledTest, OverscrollDispatch) { + OverscrollDispatch(); +} // Tests that touch event stream validation passes when events are filtered // out. See crbug.com/581231 for details. @@ -2024,7 +2136,8 @@ TEST_F(LegacyInputRouterImplScaleEventTest, ScaleMouseWheelEventTest) { ASSERT_EQ(0u, process_->sink().message_count()); - SimulateWheelEvent(5, 5, 10, 10, 0, false); + SimulateWheelEventWithPhase(5, 5, 10, 10, 0, false, + WebMouseWheelEvent::kPhaseBegan); ASSERT_EQ(1u, process_->sink().message_count()); const WebMouseWheelEvent* sent_event =
diff --git a/content/browser/renderer_host/input/mouse_latency_browsertest.cc b/content/browser/renderer_host/input/mouse_latency_browsertest.cc index 69fcb2d..b9c0e4bf 100644 --- a/content/browser/renderer_host/input/mouse_latency_browsertest.cc +++ b/content/browser/renderer_host/input/mouse_latency_browsertest.cc
@@ -145,7 +145,8 @@ // MouseDown events in the case where no swap is generated. // Disabled on Android because we don't support synthetic mouse input on // Android (crbug.com/723618). -#if defined(OS_ANDROID) +// Test is flaky on Linux (crbug.com/736836). +#if defined (OS_ANDROID) || defined(OS_LINUX) #define MAYBE_MouseDownAndUpRecordedWithoutSwap \ DISABLED_MouseDownAndUpRecordedWithoutSwap #else
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc index 2652afa0..9b850fd 100644 --- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc +++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -7,6 +7,8 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" +#include "content/common/input/input_event_dispatch_type.h" +#include "content/public/common/content_features.h" #include "ui/events/base_event_utils.h" #include "ui/events/blink/web_input_event_traits.h" @@ -40,6 +42,9 @@ needs_scroll_begin_(true), needs_scroll_end_(false), enable_scroll_latching_(enable_scroll_latching), + enable_async_wheel_events_( + base::FeatureList::IsEnabled(features::kAsyncWheelEvents)), + send_wheel_events_async_(false), scrolling_device_(blink::kWebGestureDeviceUninitialized) { DCHECK(client); } @@ -176,6 +181,7 @@ if (enable_scroll_latching_) { if (event_sent_for_gesture_ack_->event.phase == blink::WebMouseWheelEvent::kPhaseBegan) { + send_wheel_events_async_ = true; SendScrollBegin(scroll_update, false); } @@ -267,6 +273,20 @@ event_sent_for_gesture_ack_ = std::move(wheel_queue_.front()); wheel_queue_.pop_front(); + if (enable_async_wheel_events_) { + DCHECK(event_sent_for_gesture_ack_->event.phase != + blink::WebMouseWheelEvent::kPhaseNone || + event_sent_for_gesture_ack_->event.momentum_phase != + blink::WebMouseWheelEvent::kPhaseNone); + if (event_sent_for_gesture_ack_->event.phase == + blink::WebMouseWheelEvent::kPhaseBegan) { + send_wheel_events_async_ = false; + } else if (send_wheel_events_async_) { + event_sent_for_gesture_ack_->event.dispatch_type = + WebInputEvent::kEventNonBlocking; + } + } + client_->SendMouseWheelEventImmediately(*event_sent_for_gesture_ack_); }
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/content/browser/renderer_host/input/mouse_wheel_event_queue.h index d4e9c7e..b0389f95 100644 --- a/content/browser/renderer_host/input/mouse_wheel_event_queue.h +++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -90,9 +90,17 @@ // GSB has been sent in the past. bool needs_scroll_end_; - // True if the touchpad and wheel scroll latching is enabled. + // True if the touchpad and wheel scroll latching flag is enabled. bool enable_scroll_latching_; + // True if the async wheel events flag is enabled. + bool enable_async_wheel_events_; + + // True if the ack for the first wheel event in a scroll sequence is not + // consumed. This lets us to send the rest of the wheel events in the sequence + // as non-blocking. + bool send_wheel_events_async_; + blink::WebGestureDevice scrolling_device_; DISALLOW_COPY_AND_ASSIGN(MouseWheelEventQueue);
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc index 56a5d43..c65b4dc 100644 --- a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -13,10 +13,12 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/renderer_host/input/timeout_monitor.h" #include "content/common/input/synthetic_web_input_event_builders.h" +#include "content/public/common/content_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" #include "ui/events/base_event_utils.h" @@ -135,19 +137,43 @@ #define EXPECT_MOUSE_WHEEL(event) \ EXPECT_EQ(WebInputEvent::kMouseWheel, event->GetType()); +enum WheelScrollingMode { + kWheelScrollingModeNone, + kWheelScrollLatching, + kAsyncWheelEvents, +}; + } // namespace -class MouseWheelEventQueueTest : public testing::TestWithParam<bool>, - public MouseWheelEventQueueClient { +class MouseWheelEventQueueTest + : public testing::TestWithParam<WheelScrollingMode>, + public MouseWheelEventQueueClient { public: MouseWheelEventQueueTest() : scoped_task_environment_( base::test::ScopedTaskEnvironment::MainThreadType::UI), acked_event_count_(0), last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN) { - scroll_latching_enabled_ = GetParam(); + scroll_latching_enabled_ = GetParam() != kWheelScrollingModeNone; + switch (GetParam()) { + case kWheelScrollingModeNone: + feature_list_.InitWithFeatures( + {}, {features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); + break; + case kWheelScrollLatching: + feature_list_.InitWithFeatures( + {features::kTouchpadAndWheelScrollLatching}, + {features::kAsyncWheelEvents}); + break; + case kAsyncWheelEvents: + feature_list_.InitWithFeatures( + {features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {}); + } + queue_.reset(new MouseWheelEventQueue(this, scroll_latching_enabled_)); - scroll_end_timeout_ms_ = scroll_latching_enabled_ ? 100 : 0; } ~MouseWheelEventQueueTest() override {} @@ -177,10 +203,6 @@ last_acked_event_state_ = ack_result; } - base::TimeDelta DefaultScrollEndTimeoutDelay() { - return base::TimeDelta::FromMilliseconds(scroll_end_timeout_ms_); - } - bool scroll_latching_enabled() { return scroll_latching_enabled_; } protected: @@ -507,21 +529,27 @@ size_t acked_event_count_; InputEventAckState last_acked_event_state_; WebMouseWheelEvent last_acked_event_; - int64_t scroll_end_timeout_ms_; bool scroll_latching_enabled_; + + private: + base::test::ScopedFeatureList feature_list_; }; // Tests that mouse wheel events are queued properly. TEST_P(MouseWheelEventQueueTest, Basic) { - SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, - kWheelScrollGlobalY, 1, 1, 0, false); + SendMouseWheelPossiblyIncludingPhase( + !scroll_latching_enabled_, kWheelScrollX, kWheelScrollY, + kWheelScrollGlobalX, kWheelScrollGlobalY, 1, 1, 0, false, + WebMouseWheelEvent::kPhaseBegan, WebMouseWheelEvent::kPhaseNone); EXPECT_EQ(0U, queued_event_count()); EXPECT_TRUE(event_in_flight()); EXPECT_EQ(1U, GetAndResetSentEventCount()); // The second mouse wheel should not be sent since one is already in queue. - SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX, - kWheelScrollGlobalY, 5, 5, 0, false); + SendMouseWheelPossiblyIncludingPhase( + !scroll_latching_enabled_, kWheelScrollX, kWheelScrollY, + kWheelScrollGlobalX, kWheelScrollGlobalY, 5, 5, 0, false, + WebMouseWheelEvent::kPhaseChanged, WebMouseWheelEvent::kPhaseNone); EXPECT_EQ(1U, queued_event_count()); EXPECT_TRUE(event_in_flight()); EXPECT_EQ(0U, GetAndResetSentEventCount()); @@ -784,6 +812,8 @@ INSTANTIATE_TEST_CASE_P(MouseWheelEventQueueTests, MouseWheelEventQueueTest, - testing::Bool()); + testing::Values(kWheelScrollingModeNone, + kWheelScrollLatching, + kAsyncWheelEvents)); } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index c88f7d6..d537fb1 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -790,26 +790,21 @@ return; } - // We use GestureTapDown to detect the start of a gesture sequence since there - // is no WebGestureEvent equivalent for ET_GESTURE_BEGIN. Note that this - // means the GestureFlingCancel that always comes between ET_GESTURE_BEGIN and - // GestureTapDown is sent to the previous target, in case it is still in a - // fling. - if (event->GetType() == blink::WebInputEvent::kGestureTapDown) { - bool no_target = touchscreen_gesture_target_queue_.empty(); - // This UMA metric is temporary, and will be removed once it has fulfilled - // it's purpose, namely telling us when the incidents of empty - // gesture-queues has dropped to zero. https://crbug.com/642008 - UMA_HISTOGRAM_BOOLEAN("Event.FrameEventRouting.NoGestureTarget", no_target); - if (no_target) { - LOG(ERROR) << "Gesture sequence start detected with no target available."; - // Ignore this gesture sequence as no target is available. - // TODO(wjmaclean): this only happens on Windows, and should not happen. - // https://crbug.com/595422 - touchscreen_gesture_target_.target = nullptr; - return; - } - + // On Android it is possible for touchscreen gesture events to arrive that + // are not associated with touch events, because non-synthetic events can be + // created by ContentView. In that case the target queue will be empty. + if (touchscreen_gesture_target_queue_.empty()) { + gfx::Point transformed_point; + gfx::Point original_point(event->x, event->y); + touchscreen_gesture_target_.target = + FindEventTarget(root_view, original_point, &transformed_point); + touchscreen_gesture_target_.delta = transformed_point - original_point; + } else if (event->GetType() == blink::WebInputEvent::kGestureTapDown) { + // We use GestureTapDown to detect the start of a gesture sequence since + // there is no WebGestureEvent equivalent for ET_GESTURE_BEGIN. Note that + // this means the GestureFlingCancel that always comes between + // ET_GESTURE_BEGIN and GestureTapDown is sent to the previous target, in + // case it is still in a fling. touchscreen_gesture_target_ = touchscreen_gesture_target_queue_.front(); touchscreen_gesture_target_queue_.pop_front();
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index d3a9b51d..9584fe7 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -512,15 +512,44 @@ render_view_host_delegate_view_; }; +enum WheelScrollingMode { + kWheelScrollingModeNone, + kWheelScrollLatching, + kAsyncWheelEvents, +}; + // RenderWidgetHostTest -------------------------------------------------------- class RenderWidgetHostTest : public testing::Test { public: - RenderWidgetHostTest() + RenderWidgetHostTest( + WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching) : process_(NULL), handle_key_press_event_(false), handle_mouse_event_(false), - simulated_event_time_delta_seconds_(0) { + simulated_event_time_delta_seconds_(0), + wheel_scroll_latching_enabled_(wheel_scrolling_mode != + kWheelScrollingModeNone) { + switch (wheel_scrolling_mode) { + case kWheelScrollingModeNone: + feature_list_.InitWithFeatures( + {features::kRafAlignedTouchInputEvents}, + {features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); + break; + case kWheelScrollLatching: + feature_list_.InitWithFeatures( + {features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching}, + {features::kAsyncWheelEvents}); + break; + case kAsyncWheelEvents: + feature_list_.InitWithFeatures( + {features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {}); + } last_simulated_event_time_seconds_ = ui::EventTimeStampToSeconds(ui::EventTimeForNow()); } @@ -538,9 +567,6 @@ void SetUp() override { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitch(switches::kValidateInputEventStream); - feature_list_.InitFromCommandLine( - features::kRafAlignedTouchInputEvents.name, ""); - browser_context_.reset(new TestBrowserContext()); delegate_.reset(new MockRenderWidgetHostDelegate()); process_ = new RenderWidgetHostProcess(browser_context_.get()); @@ -659,6 +685,19 @@ 0, 0, dX, dY, modifiers, precise)); } + void SimulateWheelEventPossiblyIncludingPhase( + float dX, + float dY, + int modifiers, + bool precise, + WebMouseWheelEvent::Phase phase) { + WebMouseWheelEvent wheel_event = SyntheticWebMouseWheelEventBuilder::Build( + 0, 0, dX, dY, modifiers, precise); + if (wheel_scroll_latching_enabled_) + wheel_event.phase = phase; + host_->ForwardWheelEvent(wheel_event); + } + void SimulateWheelEventWithLatencyInfo(float dX, float dY, int modifiers, @@ -670,6 +709,20 @@ ui_latency); } + void SimulateWheelEventWithLatencyInfoAndPossiblyPhase( + float dX, + float dY, + int modifiers, + bool precise, + const ui::LatencyInfo& ui_latency, + WebMouseWheelEvent::Phase phase) { + WebMouseWheelEvent wheel_event = SyntheticWebMouseWheelEventBuilder::Build( + 0, 0, dX, dY, modifiers, precise); + if (wheel_scroll_latching_enabled_) + wheel_event.phase = phase; + host_->ForwardWheelEventWithLatencyInfo(wheel_event, ui_latency); + } + void SimulateMouseMove(int x, int y, int modifiers) { SimulateMouseEvent(WebInputEvent::kMouseMove, x, y, modifiers, false); } @@ -735,6 +788,10 @@ return reinterpret_cast<const WebInputEvent*>(data); } + void UnhandledWheelEvent(); + void HandleWheelEvent(); + void InputEventRWHLatencyComponent(); + std::unique_ptr<TestBrowserContext> browser_context_; RenderWidgetHostProcess* process_; // Deleted automatically by the widget. std::unique_ptr<MockRenderWidgetHostDelegate> delegate_; @@ -748,6 +805,7 @@ IPC::TestSink* sink_; std::unique_ptr<FakeRendererCompositorFrameSink> renderer_compositor_frame_sink_; + bool wheel_scroll_latching_enabled_; private: SyntheticWebTouchEvent touch_event_; @@ -759,6 +817,20 @@ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostTest); }; +class RenderWidgetHostWheelScrollLatchingDisabledTest + : public RenderWidgetHostTest { + public: + RenderWidgetHostWheelScrollLatchingDisabledTest() + : RenderWidgetHostTest(kWheelScrollingModeNone) {} +}; + +class RenderWidgetHostAsyncWheelEventsEnabledTest + : public RenderWidgetHostTest { + public: + RenderWidgetHostAsyncWheelEventsEnabledTest() + : RenderWidgetHostTest(kAsyncWheelEvents) {} +}; + #if GTEST_HAS_PARAM_TEST // RenderWidgetHostWithSourceTest ---------------------------------------------- @@ -1153,12 +1225,13 @@ EXPECT_EQ(WebInputEvent::kKeyUp, delegate_->unhandled_keyboard_event_type()); } -TEST_F(RenderWidgetHostTest, UnhandledWheelEvent) { - SimulateWheelEvent(-5, 0, 0, true); +void RenderWidgetHostTest::UnhandledWheelEvent() { + SimulateWheelEventPossiblyIncludingPhase(-5, 0, 0, true, + WebMouseWheelEvent::kPhaseBegan); // Make sure we sent the input event to the renderer. - EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - InputMsg_HandleInputEvent::ID)); + EXPECT_TRUE( + process_->sink().GetUniqueMessageMatching(InputMsg_HandleInputEvent::ID)); process_->sink().ClearMessages(); // Send the simulated response from the renderer back. @@ -1168,16 +1241,26 @@ EXPECT_EQ(1, view_->unhandled_wheel_event_count()); EXPECT_EQ(-5, view_->unhandled_wheel_event().delta_x); } +TEST_F(RenderWidgetHostTest, UnhandledWheelEvent) { + UnhandledWheelEvent(); +} +TEST_F(RenderWidgetHostWheelScrollLatchingDisabledTest, UnhandledWheelEvent) { + UnhandledWheelEvent(); +} +TEST_F(RenderWidgetHostAsyncWheelEventsEnabledTest, UnhandledWheelEvent) { + UnhandledWheelEvent(); +} -TEST_F(RenderWidgetHostTest, HandleWheelEvent) { +void RenderWidgetHostTest::HandleWheelEvent() { // Indicate that we're going to handle this wheel event delegate_->set_handle_wheel_event(true); - SimulateWheelEvent(-5, 0, 0, true); + SimulateWheelEventPossiblyIncludingPhase(-5, 0, 0, true, + WebMouseWheelEvent::kPhaseBegan); // Make sure we sent the input event to the renderer. - EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( - InputMsg_HandleInputEvent::ID)); + EXPECT_TRUE( + process_->sink().GetUniqueMessageMatching(InputMsg_HandleInputEvent::ID)); process_->sink().ClearMessages(); // Send the simulated response from the renderer back. @@ -1190,6 +1273,15 @@ // and that it suppressed the unhandled wheel event handler. EXPECT_EQ(0, view_->unhandled_wheel_event_count()); } +TEST_F(RenderWidgetHostTest, HandleWheelEvent) { + HandleWheelEvent(); +} +TEST_F(RenderWidgetHostWheelScrollLatchingDisabledTest, HandleWheelEvent) { + HandleWheelEvent(); +} +TEST_F(RenderWidgetHostAsyncWheelEventsEnabledTest, HandleWheelEvent) { + HandleWheelEvent(); +} TEST_F(RenderWidgetHostTest, UnhandledGestureEvent) { SimulateGestureEvent(WebInputEvent::kGestureTwoFingerTap, @@ -1793,18 +1885,20 @@ // or ForwardXXXEventWithLatencyInfo(), LatencyInfo component // ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT will always present in the // event's LatencyInfo. -TEST_F(RenderWidgetHostTest, InputEventRWHLatencyComponent) { +void RenderWidgetHostTest::InputEventRWHLatencyComponent() { host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); process_->sink().ClearMessages(); // Tests RWHI::ForwardWheelEvent(). - SimulateWheelEvent(-5, 0, 0, true); + SimulateWheelEventPossiblyIncludingPhase(-5, 0, 0, true, + WebMouseWheelEvent::kPhaseBegan); CheckLatencyInfoComponentInMessage(process_, GetLatencyComponentId(), WebInputEvent::kMouseWheel); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); // Tests RWHI::ForwardWheelEventWithLatencyInfo(). - SimulateWheelEventWithLatencyInfo(-5, 0, 0, true, ui::LatencyInfo()); + SimulateWheelEventWithLatencyInfoAndPossiblyPhase( + -5, 0, 0, true, ui::LatencyInfo(), WebMouseWheelEvent::kPhaseChanged); CheckLatencyInfoComponentInMessage(process_, GetLatencyComponentId(), WebInputEvent::kMouseWheel); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); @@ -1847,6 +1941,17 @@ CheckLatencyInfoComponentInMessage(process_, GetLatencyComponentId(), WebInputEvent::kTouchStart); } +TEST_F(RenderWidgetHostTest, InputEventRWHLatencyComponent) { + InputEventRWHLatencyComponent(); +} +TEST_F(RenderWidgetHostWheelScrollLatchingDisabledTest, + InputEventRWHLatencyComponent) { + InputEventRWHLatencyComponent(); +} +TEST_F(RenderWidgetHostAsyncWheelEventsEnabledTest, + InputEventRWHLatencyComponent) { + InputEventRWHLatencyComponent(); +} TEST_F(RenderWidgetHostTest, RendererExitedResetsInputRouter) { // RendererExited will delete the view.
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 82872c6..77970a32 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1015,9 +1015,14 @@ bool causes_scrolling = false; ui::LatencyInfo latency_info(ui::SourceEventType::TOUCH); latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); - host_->ForwardTouchEventWithLatencyInfo( - ui::CreateWebTouchEventFromMotionEvent(*cancel_event, causes_scrolling), - latency_info); + blink::WebTouchEvent web_event = + ui::CreateWebTouchEventFromMotionEvent(*cancel_event, causes_scrolling); + if (host_->delegate()->GetInputEventRouter()) { + host_->delegate()->GetInputEventRouter()->RouteTouchEvent( + this, &web_event, latency_info); + } else { + host_->ForwardTouchEventWithLatencyInfo(web_event, latency_info); + } } }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index f915f1d6..ff342a07 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -578,6 +578,12 @@ return reinterpret_cast<const WebInputEvent*>(data); } +enum WheelScrollingMode { + kWheelScrollingModeNone, + kWheelScrollLatching, + kAsyncWheelEvents, +}; + } // namespace class RenderWidgetHostViewAuraTest : public testing::Test { @@ -745,24 +751,41 @@ "", features::kTouchpadAndWheelScrollLatching.name); } - void SetFeatureList(bool raf_aligned_touch, bool wheel_scroll_latching) { - if (raf_aligned_touch && wheel_scroll_latching) { + void SetFeatureList( + bool raf_aligned_touch, + WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching) { + if (raf_aligned_touch && wheel_scrolling_mode == kAsyncWheelEvents) { + feature_list_.InitWithFeatures({features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {}); + } else if (raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollLatching) { feature_list_.InitWithFeatures( {features::kRafAlignedTouchInputEvents, features::kTouchpadAndWheelScrollLatching}, - {}); - } else if (raf_aligned_touch && !wheel_scroll_latching) { - feature_list_.InitWithFeatures( - {features::kRafAlignedTouchInputEvents}, - {features::kTouchpadAndWheelScrollLatching}); - } else if (!raf_aligned_touch && wheel_scroll_latching) { + {features::kAsyncWheelEvents}); + } else if (raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollingModeNone) { + feature_list_.InitWithFeatures({features::kRafAlignedTouchInputEvents}, + {features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); + } else if (!raf_aligned_touch && + wheel_scrolling_mode == kAsyncWheelEvents) { + feature_list_.InitWithFeatures({features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}, + {features::kRafAlignedTouchInputEvents}); + } else if (!raf_aligned_touch && + wheel_scrolling_mode == kWheelScrollLatching) { feature_list_.InitWithFeatures( {features::kTouchpadAndWheelScrollLatching}, - {features::kRafAlignedTouchInputEvents}); - } else { // !raf_aligned_touch && !wheel_scroll_latching - feature_list_.InitWithFeatures( - {}, {features::kRafAlignedTouchInputEvents, - features::kTouchpadAndWheelScrollLatching}); + {features::kRafAlignedTouchInputEvents, features::kAsyncWheelEvents}); + } else { // !raf_aligned_touch && wheel_scroll_latching == + // kWheelScrollingModeNone. + feature_list_.InitWithFeatures({}, + {features::kRafAlignedTouchInputEvents, + features::kTouchpadAndWheelScrollLatching, + features::kAsyncWheelEvents}); } } @@ -908,8 +931,10 @@ : public RenderWidgetHostViewAuraTest { public: RenderWidgetHostViewAuraOverscrollTest( - bool wheel_scroll_latching_enabled = true) - : wheel_scroll_latching_enabled_(wheel_scroll_latching_enabled) {} + WheelScrollingMode wheel_scrolling_mode = kWheelScrollLatching) + : wheel_scroll_latching_enabled_(wheel_scrolling_mode != + kWheelScrollingModeNone), + wheel_scrolling_mode_(wheel_scrolling_mode) {} // We explicitly invoke SetUp to allow gesture debounce customization. void SetUp() override {} @@ -922,7 +947,7 @@ void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); } void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) { - SetFeatureList(true, wheel_scroll_latching_enabled_); + SetFeatureList(true, wheel_scrolling_mode_); ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms( debounce_interval_in_ms); @@ -1128,13 +1153,29 @@ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); } - void ExpectGestureScrollEventsAfterMouseWheelACK(bool is_first_ack, - bool enqueued_mouse_wheel) { + void ExpectGestureScrollEventsAfterMouseWheelACK( + bool is_first_ack, + size_t enqueued_wheel_event_count) { InputMsg_HandleInputEvent::Param params; const blink::WebInputEvent* event; size_t expected_message_count; if (is_first_ack) { - expected_message_count = enqueued_mouse_wheel ? 3 : 2; + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + // If the ack for the first sent event is not consumed, + // MouseWheelEventQueue(MWEQ) sends the rest of the wheel events in the + // current scrolling sequence as non-blocking events. Since MWEQ + // receives the ack for non-blocking events asynchronously, it sends the + // next queued wheel event immediately and this continues till the queue + // is empty. + expected_message_count = enqueued_wheel_event_count + 2; + } else { + // Since the MWEQ must wait for ack of the sent event before sending the + // next queued event, when wheel events are blocking only one queued + // event will be sent regardless of the number of the queued wheel + // events. + expected_message_count = enqueued_wheel_event_count ? 3 : 2; + } + EXPECT_EQ(expected_message_count, sink_->message_count()); // The first message is GestureScrollBegin. @@ -1149,15 +1190,15 @@ EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, event->GetType()); } - if (enqueued_mouse_wheel) { - // The last message is the queued MouseWheel. - if (InputMsg_HandleInputEvent::Read(sink_->GetMessageAt(2), ¶ms)) { + for (size_t i = 2; i < expected_message_count; i++) { + // The last messages are the queued MouseWheel event(s). + if (InputMsg_HandleInputEvent::Read(sink_->GetMessageAt(i), ¶ms)) { event = std::get<0>(params); EXPECT_EQ(WebInputEvent::kMouseWheel, event->GetType()); } } } else { // !is_first_ack - expected_message_count = enqueued_mouse_wheel ? 2 : 1; + expected_message_count = enqueued_wheel_event_count ? 2 : 1; size_t scroll_update_index = 0; if (!wheel_scroll_latching_enabled_) { @@ -1178,7 +1219,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, event->GetType()); } - if (enqueued_mouse_wheel) { + if (enqueued_wheel_event_count) { // The last message is the queued MouseWheel. if (InputMsg_HandleInputEvent::Read( sink_->GetMessageAt(expected_message_count - 1), ¶ms)) { @@ -1190,6 +1231,45 @@ EXPECT_EQ(expected_message_count, GetSentMessageCountAndResetSink()); } + void ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK( + bool wheel_was_queued) { + size_t gesture_scroll_update_index; + InputMsg_HandleInputEvent::Param params; + if (wheel_was_queued) { + // The queued wheel event is already sent. + gesture_scroll_update_index = 0; + } else { + // The first sent must be the wheel event and the second one must be + // GestureScrollUpdate since the ack for the wheel event is non-blocking. + if (InputMsg_HandleInputEvent::Read(sink_->GetMessageAt(0), ¶ms)) { + EXPECT_EQ(WebInputEvent::kMouseWheel, (std::get<0>(params))->GetType()); + } + gesture_scroll_update_index = 1; + } + if (InputMsg_HandleInputEvent::Read( + sink_->GetMessageAt(gesture_scroll_update_index), ¶ms)) { + EXPECT_EQ(WebInputEvent::kGestureScrollUpdate, + (std::get<0>(params))->GetType()); + } + EXPECT_EQ(gesture_scroll_update_index + 1, + GetSentMessageCountAndResetSink()); + } + + void ExpectGestureScrollEndAfterNonBlockingMouseWheelACK() { + InputMsg_HandleInputEvent::Param params; + // The first sent must be the wheel event and the second one must be + // GestureScrollEnd since the ack for the wheel event is non-blocking. + if (InputMsg_HandleInputEvent::Read(sink_->GetMessageAt(0), ¶ms)) { + EXPECT_EQ(WebInputEvent::kMouseWheel, (std::get<0>(params))->GetType()); + } + + if (InputMsg_HandleInputEvent::Read(sink_->GetMessageAt(1), ¶ms)) { + EXPECT_EQ(WebInputEvent::kGestureScrollEnd, + (std::get<0>(params))->GetType()); + } + EXPECT_EQ(2U, GetSentMessageCountAndResetSink()); + } + void WheelNotPreciseScrollEvent(); void WheelScrollOverscrollToggle(); void OverscrollMouseMoveCompletion(); @@ -1198,6 +1278,7 @@ void ScrollEventsOverscrollWithFling(); void OverscrollDirectionChangeMouseWheel(); void OverscrollStateResetsAfterScroll(); + void ScrollDeltasResetOnEnd(); void ScrollEventsOverscrollWithZeroFling(); SyntheticWebTouchEvent touch_event_; @@ -1205,6 +1286,7 @@ std::unique_ptr<TestOverscrollDelegate> overscroll_delegate_; bool wheel_scroll_latching_enabled_; + WheelScrollingMode wheel_scrolling_mode_; private: DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraOverscrollTest); @@ -1214,7 +1296,14 @@ : public RenderWidgetHostViewAuraOverscrollTest { public: RenderWidgetHostViewAuraOverscrollWithoutWheelScrollLatchingTest() - : RenderWidgetHostViewAuraOverscrollTest(false) {} + : RenderWidgetHostViewAuraOverscrollTest(kWheelScrollingModeNone) {} +}; + +class RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest + : public RenderWidgetHostViewAuraOverscrollTest { + public: + RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest() + : RenderWidgetHostViewAuraOverscrollTest(kAsyncWheelEvents) {} }; class RenderWidgetHostViewAuraShutdownTest @@ -3722,28 +3811,36 @@ // Receive ACK the first wheel event as not processed. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 1); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + ExpectGestureScrollEndForWheelScrolling(false); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - if (wheel_scroll_latching_enabled_) { - SimulateWheelEventWithPhase(0, 0, 0, false, - WebMouseWheelEvent::kPhaseEnded); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); + ExpectGestureScrollEndAfterNonBlockingMouseWheelACK(); + } else if (wheel_scroll_latching_enabled_) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(true); + } else { + ExpectGestureScrollEndForWheelScrolling(true); } - ExpectGestureScrollEndForWheelScrolling(true); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); @@ -3755,6 +3852,10 @@ WheelNotPreciseScrollEvent) { WheelNotPreciseScrollEvent(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + WheelNotPreciseScrollEvent) { + WheelNotPreciseScrollEvent(); +} void RenderWidgetHostViewAuraOverscrollTest::WheelScrollEventOverscrolls() { SetUpOverscrollEnvironment(); @@ -3784,25 +3885,28 @@ // Receive ACK the first wheel event as not processed. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 2); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); - - // Receive ACK for the second (coalesced) event as not processed. This will - // start a back navigation. However, this will also cause the queued next - // event to be sent to the renderer. But since overscroll navigation has - // started, that event will also be included in the overscroll computation - // instead of being sent to the renderer. So the result will be an overscroll - // back navigation, and no ScrollUpdate event will be sent to the renderer. - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, true); - + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + ExpectGestureScrollEndForWheelScrolling(false); + // Receive ACK for the second (coalesced) event as not processed. This will + // start a back navigation. However, this will also cause the queued next + // event to be sent to the renderer. But since overscroll navigation has + // started, that event will also be included in the overscroll computation + // instead of being sent to the renderer. So the result will be an + // overscroll back navigation, and no ScrollUpdate event will be sent to the + // renderer. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 1); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); ExpectGestureScrollEndForWheelScrolling(false); @@ -3836,6 +3940,10 @@ WheelScrollEventOverscrolls) { WheelScrollEventOverscrolls(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + WheelScrollEventOverscrolls) { + WheelScrollEventOverscrolls(); +} // Tests that if some scroll events are consumed towards the start, then // subsequent scrolls do not horizontal overscroll. @@ -3869,42 +3977,54 @@ // Receive ACK the first wheel event as processed. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); - - SendInputEventACK(WebInputEvent::kGestureScrollUpdate, - INPUT_EVENT_ACK_STATE_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 2); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); - // Receive ACK for the second (coalesced) event as not processed. This should - // not initiate overscroll, since the beginning of the scroll has been - // consumed. The queued event with different modifiers should be sent to the - // renderer. - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + if (wheel_scrolling_mode_ != kAsyncWheelEvents) { + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(false); + // Receive ACK for the second (coalesced) event as not processed. This + // should not initiate overscroll, since the beginning of the scroll has + // been consumed. The queued event with different modifiers should be sent + // to the renderer. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 1); + } EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); - ExpectGestureScrollEventsAfterMouseWheelACK(false, true); + + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + // The first and second GSU events are coalesced. This is the ack for the + // coalesced event. Since it is the first GSU, the ack should be consumed. + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_CONSUMED); + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + SendInputEventACK(WebInputEvent::kGestureScrollUpdate, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(false); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); - - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); - - SendInputEventACK(WebInputEvent::kGestureScrollUpdate, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - if (wheel_scroll_latching_enabled_) { + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); + ExpectGestureScrollEndAfterNonBlockingMouseWheelACK(); + } else if (wheel_scroll_latching_enabled_) { SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(true); + } else { + ExpectGestureScrollEndForWheelScrolling(true); } - - ExpectGestureScrollEndForWheelScrolling(true); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); } TEST_F(RenderWidgetHostViewAuraOverscrollTest, @@ -3915,6 +4035,10 @@ WheelScrollConsumedDoNotHorizOverscroll) { WheelScrollConsumedDoNotHorizOverscroll(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + WheelScrollConsumedDoNotHorizOverscroll) { + WheelScrollConsumedDoNotHorizOverscroll(); +} // Tests that wheel-scrolling correctly turns overscroll on and off. void RenderWidgetHostViewAuraOverscrollTest::WheelScrollOverscrollToggle() { @@ -3928,7 +4052,7 @@ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, false); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 0); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -3941,10 +4065,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 10, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -3957,10 +4085,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 40, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -3993,10 +4125,14 @@ 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4010,20 +4146,29 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, -55, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - if (wheel_scroll_latching_enabled_) { + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); + ExpectGestureScrollEndAfterNonBlockingMouseWheelACK(); + } else if (wheel_scroll_latching_enabled_) { SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(true); + } else { + ExpectGestureScrollEndForWheelScrolling(true); } - ExpectGestureScrollEndForWheelScrolling(true); EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); EXPECT_EQ(OVERSCROLL_WEST, overscroll_delegate()->current_mode()); @@ -4038,6 +4183,10 @@ WheelScrollOverscrollToggle) { WheelScrollOverscrollToggle(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + WheelScrollOverscrollToggle) { + WheelScrollOverscrollToggle(); +} void RenderWidgetHostViewAuraOverscrollTest::ScrollEventsOverscrollWithFling() { SetUpOverscrollEnvironment(); @@ -4050,7 +4199,7 @@ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, false); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 0); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4063,9 +4212,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 20, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, sink_->message_count()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); @@ -4076,11 +4230,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 30, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); - + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); ExpectGestureScrollEndForWheelScrolling(false); @@ -4112,6 +4269,10 @@ ScrollEventsOverscrollWithFling) { ScrollEventsOverscrollWithFling(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + ScrollEventsOverscrollWithFling) { + ScrollEventsOverscrollWithFling(); +} // Same as ScrollEventsOverscrollWithFling, but with zero velocity. Checks that // the zero-velocity fling does not reach the renderer. @@ -4127,7 +4288,7 @@ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, false); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 0); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4140,10 +4301,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 20, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4156,10 +4321,14 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 30, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4192,6 +4361,10 @@ ScrollEventsOverscrollWithZeroFling) { ScrollEventsOverscrollWithZeroFling(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + ScrollEventsOverscrollWithZeroFling) { + ScrollEventsOverscrollWithZeroFling(); +} // Tests that a fling in the opposite direction of the overscroll cancels the // overscroll nav instead of completing it. @@ -4649,7 +4822,7 @@ EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, false); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 0); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4665,10 +4838,15 @@ SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, -260, 0, 0, true, WebMouseWheelEvent::kPhaseChanged); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(false); + } else { + EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } + EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, @@ -4683,8 +4861,10 @@ 0, 0, true, WebMouseWheelEvent::kPhaseChanged); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + if (wheel_scrolling_mode_ != kAsyncWheelEvents) { + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + } // wheel event ack generates gesture scroll update; which gets consumed // solely by the overflow controller. @@ -4706,6 +4886,10 @@ OverscrollDirectionChangeMouseWheel) { OverscrollDirectionChangeMouseWheel(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + OverscrollDirectionChangeMouseWheel) { + OverscrollDirectionChangeMouseWheel(); +} void RenderWidgetHostViewAuraOverscrollTest::OverscrollMouseMoveCompletion() { SetUpOverscrollEnvironment(); @@ -4732,20 +4916,24 @@ // Receive ACK the first wheel event as not processed. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 1); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); EXPECT_EQ(OVERSCROLL_NONE, overscroll_delegate()->current_mode()); - // Receive ACK for the second (coalesced) event as not processed. This will - // start an overcroll gesture. - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + ExpectGestureScrollEndForWheelScrolling(false); + // Receive ACK for the second (coalesced) event as not processed. This will + // start an overcroll gesture. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -4812,6 +5000,10 @@ OverscrollMouseMoveCompletion) { OverscrollMouseMoveCompletion(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + OverscrollMouseMoveCompletion) { + OverscrollMouseMoveCompletion(); +} // Tests that if a page scrolled, then the overscroll controller's states are // reset after the end of the scroll. @@ -4837,32 +5029,41 @@ // The first wheel event is consumed. Dispatches the queued wheel event. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 1); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); EXPECT_TRUE(ScrollStateIsContentScrolling()); - // The second wheel event is consumed. - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + ExpectGestureScrollEndForWheelScrolling(false); + // The second wheel event is consumed. + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_CONSUMED); - if (wheel_scroll_latching_enabled_) { + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); + ExpectGestureScrollEndAfterNonBlockingMouseWheelACK(); + } else if (wheel_scroll_latching_enabled_) { SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(true); + } else { + ExpectGestureScrollEndForWheelScrolling(true); } - ExpectGestureScrollEndForWheelScrolling(true); EXPECT_TRUE(ScrollStateIsContentScrolling()); - // Touchpad scroll can end with a zero-velocity fling. But it is not - // dispatched, but it should still reset the overscroll controller state. + // Touchpad scroll can end with a zero-velocity fling which is not dispatched, + // but it should still reset the overscroll controller state. SimulateGestureEvent(WebInputEvent::kGestureScrollBegin, blink::kWebGestureDeviceTouchscreen); SimulateGestureFlingStartEvent(0.f, 0.f, blink::kWebGestureDeviceTouchpad); @@ -4896,28 +5097,37 @@ // yet, since enough hasn't been scrolled. SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(true, true); + ExpectGestureScrollEventsAfterMouseWheelACK(true, 1); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEndForWheelScrolling(false); + EXPECT_TRUE(ScrollStateIsUnknown()); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - ExpectGestureScrollEventsAfterMouseWheelACK(false, false); + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + ExpectGestureScrollUpdateAfterNonBlockingMouseWheelACK(true); + } else { + ExpectGestureScrollEndForWheelScrolling(false); + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEventsAfterMouseWheelACK(false, 0); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - if (wheel_scroll_latching_enabled_) { + if (wheel_scrolling_mode_ == kAsyncWheelEvents) { + SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); + ExpectGestureScrollEndAfterNonBlockingMouseWheelACK(); + } else if (wheel_scroll_latching_enabled_) { SimulateWheelEventWithPhase(0, 0, 0, true, WebMouseWheelEvent::kPhaseEnded); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + ExpectGestureScrollEndForWheelScrolling(true); + } else { + ExpectGestureScrollEndForWheelScrolling(true); } - - ExpectGestureScrollEndForWheelScrolling(true); EXPECT_EQ(OVERSCROLL_WEST, overscroll_mode()); EXPECT_TRUE(ScrollStateIsOverscrolling()); @@ -4940,6 +5150,10 @@ OverscrollStateResetsAfterScroll) { OverscrollStateResetsAfterScroll(); } +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + OverscrollStateResetsAfterScroll) { + OverscrollStateResetsAfterScroll(); +} TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollResetsOnBlur) { SetUpOverscrollEnvironment(); @@ -5185,10 +5399,12 @@ // Tests that the scroll deltas stored within the overscroll controller get // reset at the end of the overscroll gesture even if the overscroll threshold // isn't surpassed and the overscroll mode stays OVERSCROLL_NONE. -TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) { +void RenderWidgetHostViewAuraOverscrollTest::ScrollDeltasResetOnEnd() { SetUpOverscrollEnvironment(); // Wheel event scroll ending with mouse move. - SimulateWheelEvent(-30, -10, 0, true); // sent directly + SimulateWheelEventPossiblyIncludingPhase( + !wheel_scroll_latching_enabled_, -30, -10, 0, true, + WebMouseWheelEvent::kPhaseBegan); // sent directly SendInputEventACK(WebInputEvent::kMouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); SendInputEventACK(WebInputEvent::kGestureScrollUpdate, @@ -5215,14 +5431,22 @@ EXPECT_EQ(0.f, overscroll_delta_y()); // Wheel event scroll ending with a fling. - SimulateWheelEvent(5, 0, 0, true); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 5, + 0, 0, true, + WebMouseWheelEvent::kPhaseChanged); + if (wheel_scrolling_mode_ != kAsyncWheelEvents) { + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - SimulateWheelEvent(10, -5, 0, true); - SendInputEventACK(WebInputEvent::kMouseWheel, - INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + SimulateWheelEventPossiblyIncludingPhase(!wheel_scroll_latching_enabled_, 10, + -5, 0, true, + WebMouseWheelEvent::kPhaseChanged); + if (wheel_scrolling_mode_ != kAsyncWheelEvents) { + SendInputEventACK(WebInputEvent::kMouseWheel, + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + } SendInputEventACK(WebInputEvent::kGestureScrollUpdate, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); @@ -5234,6 +5458,17 @@ EXPECT_EQ(0.f, overscroll_delta_x()); EXPECT_EQ(0.f, overscroll_delta_y()); } +TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) { + ScrollDeltasResetOnEnd(); +} +TEST_F(RenderWidgetHostViewAuraOverscrollWithoutWheelScrollLatchingTest, + ScrollDeltasResetOnEnd) { + ScrollDeltasResetOnEnd(); +} +TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, + ScrollDeltasResetOnEnd) { + ScrollDeltasResetOnEnd(); +} TEST_F(RenderWidgetHostViewAuraTest, ForwardMouseEvent) { aura::Window* root = parent_view_->GetNativeView()->GetRootWindow();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 617f484..52ddbab 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -988,6 +988,8 @@ } if (browser_plugin_embedder_) browser_plugin_embedder_->CancelGuestDialogs(); + if (delegate_) + delegate_->HideValidationMessage(this); } void WebContentsImpl::ClosePage() { @@ -4694,9 +4696,6 @@ // Cancel any visible dialogs so they are not left dangling over the sad tab. CancelActiveAndPendingDialogs(); - if (delegate_) - delegate_->HideValidationMessage(this); - audio_stream_monitor_.RenderProcessGone(rvh->GetProcess()->GetID()); // Reset the loading progress. TODO(avi): What does it mean to have a
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index 2f161b01..fea1eb6 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1467,4 +1467,78 @@ wc->SetJavaScriptDialogManagerForTesting(nullptr); } +class FormBubbleDelegate : public WebContentsDelegate { + public: + FormBubbleDelegate() = default; + + void WaitUntilShown() { + while (!is_visible_) { + message_loop_runner_ = new MessageLoopRunner; + message_loop_runner_->Run(); + } + } + + void WaitUntilHidden() { + while (is_visible_) { + message_loop_runner_ = new MessageLoopRunner; + message_loop_runner_->Run(); + } + } + + private: + void ShowValidationMessage(WebContents* web_contents, + const gfx::Rect& anchor_in_root_view, + const base::string16& main_text, + const base::string16& sub_text) override { + is_visible_ = true; + if (message_loop_runner_) + message_loop_runner_->Quit(); + } + + void HideValidationMessage(WebContents* web_contents) override { + is_visible_ = false; + if (message_loop_runner_) + message_loop_runner_->Quit(); + } + + bool is_visible_ = false; + scoped_refptr<MessageLoopRunner> message_loop_runner_; +}; + +IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, + NavigationHidesFormValidationBubble) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); + + // Start listening for requests to show or hide the form validation bubble. + WebContentsImpl* web_contents = + static_cast<WebContentsImpl*>(shell()->web_contents()); + FormBubbleDelegate bubble_delegate; + web_contents->SetDelegate(&bubble_delegate); + + // Trigger a form validation bubble and verify that the bubble is shown. + std::string script = R"( + var input_field = document.createElement('input'); + input_field.required = true; + var form = document.createElement('form'); + form.appendChild(input_field); + document.body.appendChild(form); + + setTimeout(function() { + input_field.setCustomValidity('Custom validity message'); + input_field.reportValidity(); + }, + 0); + )"; + ASSERT_TRUE(ExecuteScript(web_contents, script)); + bubble_delegate.WaitUntilShown(); + + // Navigate to another page and verify that the form validation bubble is + // hidden. + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("b.com", "/title2.html"))); + bubble_delegate.WaitUntilHidden(); +} + } // namespace content
diff --git a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc index 3d815a27..071bf9ca 100644 --- a/content/browser/webrtc/webrtc_media_recorder_browsertest.cc +++ b/content/browser/webrtc/webrtc_media_recorder_browsertest.cc
@@ -154,8 +154,16 @@ kMediaRecorderHtmlFile); } +// Flaky on Linux Tsan (crbug.com/736268) +#if defined(THREAD_SANITIZER) +#define MAYBE_IllegalStartWhilePausedThrowsDOMError \ + DISABLED_IllegalStartWhilePausedThrowsDOMError +#else +#define MAYBE_IllegalStartWhilePausedThrowsDOMError \ + IllegalStartWhilePausedThrowsDOMError +#endif IN_PROC_BROWSER_TEST_F(WebRtcMediaRecorderTest, - IllegalStartWhilePausedThrowsDOMError) { + MAYBE_IllegalStartWhilePausedThrowsDOMError) { MakeTypicalCall("testIllegalStartInPausedStateThrowsDOMError();", kMediaRecorderHtmlFile); }
diff --git a/content/common/site_isolation_policy.cc b/content/common/site_isolation_policy.cc index 7fa66c2..3fc8ba5f 100644 --- a/content/common/site_isolation_policy.cc +++ b/content/common/site_isolation_policy.cc
@@ -6,7 +6,6 @@ #include "base/command_line.h" #include "base/feature_list.h" -#include "content/public/common/content_client.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" @@ -14,17 +13,7 @@ // static bool SiteIsolationPolicy::AreCrossProcessFramesPossible() { -// Before turning this on for Android, input event routing needs to be -// completed there, and perf regressions in https://crbug.com/690229 need to be -// investigated. -#if defined(OS_ANDROID) - return UseDedicatedProcessesForAllSites() || - IsTopDocumentIsolationEnabled() || AreIsolatedOriginsEnabled() || - GetContentClient()->IsSupplementarySiteIsolationModeEnabled() || - base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames); -#else return true; -#endif } // static
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index ba68c9030..dee3dde 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -21,6 +21,10 @@ const base::Feature kAsmJsToWebAssembly{"AsmJsToWebAssembly", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables async wheel events. +const base::Feature kAsyncWheelEvents{"AsyncWheelEvents", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Block subresource requests whose URLs contain embedded credentials (e.g. // `https://user:pass@example.com/resource`). const base::Feature kBlockCredentialedSubresources{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index e06b6dc..b7ba58be 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -19,6 +19,7 @@ CONTENT_EXPORT extern const base::Feature kAllowContentInitiatedDataUrlNavigations; CONTENT_EXPORT extern const base::Feature kAsmJsToWebAssembly; +CONTENT_EXPORT extern const base::Feature kAsyncWheelEvents; CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources; CONTENT_EXPORT extern const base::Feature kBrotliEncoding; CONTENT_EXPORT extern const base::Feature kBrowserSideNavigation;
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc index 1afd649..21792a5 100644 --- a/content/renderer/media/rtc_peer_connection_handler.cc +++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1105,6 +1105,8 @@ dependency_factory_(dependency_factory), track_adapter_map_( new WebRtcMediaStreamTrackAdapterMap(dependency_factory_)), + stream_adapter_map_(new WebRtcMediaStreamAdapterMap(dependency_factory_, + track_adapter_map_)), weak_factory_(this) { CHECK(client_); GetPeerConnectionHandlers()->insert(this); @@ -1524,8 +1526,8 @@ const blink::WebMediaConstraints& options) { DCHECK(thread_checker_.CalledOnValidThread()); TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::addStream"); - for (const auto& adapter : local_streams_) { - if (adapter->IsEqual(stream)) { + for (const auto& adapter_ref : local_streams_) { + if (adapter_ref->adapter().IsEqual(stream)) { DVLOG(1) << "RTCPeerConnectionHandler::addStream called with the same " << "stream twice. id=" << stream.Id().Utf8(); return false; @@ -1539,11 +1541,11 @@ PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter(); - local_streams_.push_back(base::MakeUnique<WebRtcMediaStreamAdapter>( - dependency_factory_, track_adapter_map_, stream)); + local_streams_.push_back( + stream_adapter_map_->GetOrCreateLocalStreamAdapter(stream)); webrtc::MediaStreamInterface* webrtc_stream = - local_streams_.back()->webrtc_media_stream(); + local_streams_.back()->adapter().webrtc_media_stream(); track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM, webrtc_stream); @@ -1567,8 +1569,8 @@ scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream; for (auto adapter_it = local_streams_.begin(); adapter_it != local_streams_.end(); ++adapter_it) { - if ((*adapter_it)->IsEqual(stream)) { - webrtc_stream = (*adapter_it)->webrtc_media_stream(); + if ((*adapter_it)->adapter().IsEqual(stream)) { + webrtc_stream = (*adapter_it)->adapter().webrtc_media_stream(); local_streams_.erase(adapter_it); break; } @@ -1759,9 +1761,9 @@ // Find the WebRtc track referenced by the blink track's ID. webrtc::AudioTrackInterface* webrtc_track = nullptr; - for (const auto& adapter : local_streams_) { - webrtc_track = - adapter->webrtc_media_stream()->FindAudioTrack(track.Id().Utf8()); + for (const auto& adapter_ref : local_streams_) { + webrtc_track = adapter_ref->adapter().webrtc_media_stream()->FindAudioTrack( + track.Id().Utf8()); if (webrtc_track) break; }
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h index 77de858f..89bcb95 100644 --- a/content/renderer/media/rtc_peer_connection_handler.h +++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -21,6 +21,7 @@ #include "base/threading/thread_checker.h" #include "content/common/content_export.h" #include "content/renderer/media/webrtc/media_stream_track_metrics.h" +#include "content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h" #include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h" #include "ipc/ipc_platform_file.h" #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" @@ -43,7 +44,6 @@ class PeerConnectionTracker; class RemoteMediaStreamImpl; class RtcDataChannelHandler; -class WebRtcMediaStreamAdapter; // Mockable wrapper for blink::WebRTCStatsResponse class CONTENT_EXPORT LocalRTCStatsResponse @@ -262,12 +262,23 @@ // needs to reference it, and automatically disposed when there are no longer // any components referencing it. scoped_refptr<WebRtcMediaStreamTrackAdapterMap> track_adapter_map_; + // Map and owners of stream adapters. Every stream that is in use by the peer + // connection has an associated blink and webrtc layer representation of it. + // The map keeps track of the relationship between |blink::WebMediaStream|s + // and |webrtc::MediaStreamInterface|s. Stream adapters are created on the fly + // when a component (such as |local_streams_| or a sender) needs to reference + // it, and automatically disposed when there are no longer any components + // referencing it. + // TODO(hbos): Update and use the map for the |remote_streams_| case too. + // crbug.com/705901 + scoped_refptr<WebRtcMediaStreamAdapterMap> stream_adapter_map_; // Local stream adapters. Every stream that is in use by the peer connection // has an associated blink and webrtc layer representation of it. This vector // keeps track of the relationship between |blink::WebMediaStream|s and // |webrtc::MediaStreamInterface|s. Streams are added and removed from the // peer connection using |AddStream| and |RemoveStream|. - std::vector<std::unique_ptr<WebRtcMediaStreamAdapter>> local_streams_; + std::vector<std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>> + local_streams_; base::WeakPtr<PeerConnectionTracker> peer_connection_tracker_;
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py index 5c1c8ba..1f10d559 100755 --- a/content/test/gpu/generate_buildbot_json.py +++ b/content/test/gpu/generate_buildbot_json.py
@@ -1584,7 +1584,6 @@ 'tester_configs': [ { 'predicate': Predicates.DEFAULT_PLUS_V8, - 'disabled_instrumentation_types': ['tsan'], }, ], 'disabled_tester_configs': [
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 01cf24a..3d62527 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -68,6 +68,18 @@ self.Fail('conformance2/textures/misc/tex-base-level-bug.html', ['win', 'd3d11'], bug=705865) + # Failing intermittently with out-of-memory crashes on some Windows bots. + self.Flaky('deqp/functional/gles3/texturefiltering/3d_formats_05.html', + ['win'], bug=735527) + self.Flaky('deqp/functional/gles3/texturefiltering/3d_formats_06.html', + ['win'], bug=735527) + self.Flaky('deqp/functional/gles3/texturefiltering/3d_formats_07.html', + ['win'], bug=735527) + self.Flaky('deqp/functional/gles3/texturefiltering/3d_sizes_02.html', + ['win'], bug=735527) + self.Flaky('deqp/functional/gles3/texturefiltering/3d_sizes_03.html', + ['win'], bug=735527) + # Win / NVidia self.Flaky('deqp/functional/gles3/fbomultisample*', ['win', 'nvidia', 'd3d11'], bug=631317)
diff --git a/docs/fuchsia_build_instructions.md b/docs/fuchsia_build_instructions.md new file mode 100644 index 0000000..5a5f317c --- /dev/null +++ b/docs/fuchsia_build_instructions.md
@@ -0,0 +1,116 @@ +# Checking out and building on Fuchsia + +***Note that the Fuchsia port is in the early stages, and things are likely to +frequently be broken. Try #cr-fuchsia on Freenode if something seems awry.*** + +There are instructions for other platforms linked from the +[get the code](get_the_code.md) page. + +## System requirements + +* A 64-bit Intel machine with at least 8GB of RAM. More than 16GB is highly + recommended. +* At least 100GB of free disk space. +* You must have Git and Python installed already. + +Most development is done on Ubuntu. + +## Install `depot_tools` + +Clone the `depot_tools` repository: + +```shell +$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +``` + +Add `depot_tools` to the end of your PATH (you will probably want to put this +in your `~/.bashrc` or `~/.zshrc`). Assuming you cloned `depot_tools` to +`/path/to/depot_tools`: + +```shell +$ export PATH="$PATH:/path/to/depot_tools" +``` + +## Get the code + +Create a `chromium` directory for the checkout and change to it (you can call +this whatever you like and put it wherever you like, as long as the full path +has no spaces): + +```shell +$ mkdir ~/chromium && cd ~/chromium +``` + +Run the `fetch` tool from depot_tools to check out the code and its +dependencies. + +```shell +$ fetch --nohooks chromium +``` + +If you don't want the full repo history, you can save a lot of time by +adding the `--no-history` flag to `fetch`. + +Expect the command to take 30 minutes on even a fast connection, and many +hours on slower ones. + +If you've already installed the build dependencies on the machine (from another +checkout, for example), you can omit the `--nohooks` flag and `fetch` +will automatically execute `gclient runhooks` at the end. + +When `fetch` completes, it will have created a hidden `.gclient` file and a +directory called `src` in the working directory. The remaining instructions +assume you have switched to the `src` directory: + +```shell +$ cd src +``` + +### Configure for building on Fuchsia + +Edit `.gclient` to include (this is a list, so it could also include `android`, +etc. if necessary.) + +``` +target_os = ['fuchsia'] +``` + +You will then need to re-run `gclient runhooks`. This makes sure the Fuchsia SDK +is available in third\_party and keeps it up to date. + + +## Setting up the build + +Chromium uses [Ninja](https://ninja-build.org) as its main build tool along +with a tool called [GN](../tools/gn/docs/quick_start.md) to generate `.ninja` +files. You can create any number of *build directories* with different +configurations. To create a build directory, run: + +```shell +$ gn gen out/fuch --args="is_debug=false dcheck_always_on=true is_component_build=false target_os=\"fuchsia\"" +``` + +## Build + +Currently, not all targets build on Fuchsia. You can build base\_unittests, for +example: + +```shell +$ ninja -C out/fuch base_unittests +``` + +## Run + +Once it is built, you can run by: + +```shell +$ out/fuch/bin/run_base_unittests +``` + +This packages the built binary and test data into a disk image, and runs a QEMU +instance from the Fuchsia SDK, outputting to the console. + +Common gtest arguments such as `--gtest_filter=...` are supported by the run +script. + +The run script also symbolizes backtraces.
diff --git a/docs/memory/README.md b/docs/memory/README.md index 2cf5c2dc..ad99948 100644 --- a/docs/memory/README.md +++ b/docs/memory/README.md
@@ -60,15 +60,15 @@ | Topic | Description | |-------|-------------| -| [Key Concepts in Chrome Memory](/memory/key_concepts.md) | Primer for memory terminology in Chrome. | -| [memory-infra](/memory-infra/README.md) | The primary tool used for inspecting allocations. | +| [Key Concepts in Chrome Memory](/docs/memory/key_concepts.md) | Primer for memory terminology in Chrome. | +| [memory-infra](/docs/memory-infra/README.md) | The primary tool used for inspecting allocations. | ## What are people actively working on? | Project | Description | |---------|-------------| | [Memory Coordinator](https://docs.google.com/document/d/1dkUXXmpJk7xBUeQM-olBpTHJ2MXamDgY_kjNrl9JXMs/edit#heading=h.swke19b7apg5) (including [Purge+Throttle/Suspend](https://docs.google.com/document/d/1EgLimgxWK5DGhptnNVbEGSvVn6Q609ZJaBkLjEPRJvI/edit)) | Centralized policy and coordination of all memory components in Chrome | -| [Memory-Infra](/memory-infra/README.md) | Tooling and infrastructure for Memory | +| [Memory-Infra](/docs/memory-infra/README.md) | Tooling and infrastructure for Memory | | [System health benchmarks](https://docs.google.com/document/d/1pEeCnkbtrbsK3uuPA-ftbg4kzM4Bk7a2A9rhRYklmF8/edit?usp=sharing) | Automated tests based on telemetry |
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn index 22db2bf..700a17c0 100644 --- a/extensions/browser/api/BUILD.gn +++ b/extensions/browser/api/BUILD.gn
@@ -57,6 +57,7 @@ "//extensions/browser/api/dns", "//extensions/browser/api/document_scan", "//extensions/browser/api/file_handlers", + "//extensions/browser/api/file_system", "//extensions/browser/api/hid", "//extensions/browser/api/idle", "//extensions/browser/api/management",
diff --git a/extensions/browser/api/file_system/BUILD.gn b/extensions/browser/api/file_system/BUILD.gn new file mode 100644 index 0000000..0e5fa0b --- /dev/null +++ b/extensions/browser/api/file_system/BUILD.gn
@@ -0,0 +1,20 @@ +# Copyright 2017 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. + +import("//extensions/features/features.gni") + +assert(enable_extensions, + "Cannot depend on extensions because enable_extensions=false.") + +source_set("file_system") { + sources = [ + "saved_file_entry.cc", + "saved_file_entry.h", + "saved_files_service_interface.h", + ] + + deps = [ + "//base:base", + ] +}
diff --git a/extensions/browser/api/file_system/saved_file_entry.cc b/extensions/browser/api/file_system/saved_file_entry.cc new file mode 100644 index 0000000..77a6530 --- /dev/null +++ b/extensions/browser/api/file_system/saved_file_entry.cc
@@ -0,0 +1,20 @@ +// Copyright 2017 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 "extensions/browser/api/file_system/saved_file_entry.h" + +namespace extensions { + +SavedFileEntry::SavedFileEntry() : is_directory(false), sequence_number(0) {} + +SavedFileEntry::SavedFileEntry(const std::string& id, + const base::FilePath& path, + bool is_directory, + int sequence_number) + : id(id), + path(path), + is_directory(is_directory), + sequence_number(sequence_number) {} + +} // namespace extensions
diff --git a/extensions/browser/api/file_system/saved_file_entry.h b/extensions/browser/api/file_system/saved_file_entry.h new file mode 100644 index 0000000..ad8bc92 --- /dev/null +++ b/extensions/browser/api/file_system/saved_file_entry.h
@@ -0,0 +1,40 @@ +// Copyright 2017 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 EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILE_ENTRY_H_ +#define EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILE_ENTRY_H_ + +#include <string> + +#include "base/files/file_path.h" + +namespace extensions { + +// Represents a file entry that a user has given an app permission to +// access. Must be serializable for persisting to disk. +struct SavedFileEntry { + SavedFileEntry(); + + SavedFileEntry(const std::string& id, + const base::FilePath& path, + bool is_directory, + int sequence_number); + + // The opaque id of this file entry. + std::string id; + + // The path to a file entry that the app had permission to access. + base::FilePath path; + + // Whether or not the entry refers to a directory. + bool is_directory; + + // The sequence number in the LRU of the file entry. The value 0 indicates + // that the entry is not in the LRU. + int sequence_number; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILE_ENTRY_H_
diff --git a/extensions/browser/api/file_system/saved_files_service_interface.h b/extensions/browser/api/file_system/saved_files_service_interface.h new file mode 100644 index 0000000..9b075c4 --- /dev/null +++ b/extensions/browser/api/file_system/saved_files_service_interface.h
@@ -0,0 +1,49 @@ +// Copyright 2017 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 EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILES_SERVICE_INTERFACE_H_ +#define EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILES_SERVICE_INTERFACE_H_ + +#include <string> + +#include "base/files/file_path.h" + +namespace extensions { + +struct SavedFileEntry; + +// Provides an LRU of saved file entries that persist across app reloads. +class SavedFilesServiceInterface { + public: + virtual ~SavedFilesServiceInterface() {} + + // Registers a file entry with the saved files service, making it eligible to + // be put into the queue. File entries that are in the retained files queue at + // object construction are automatically registered. + virtual void RegisterFileEntry(const std::string& extension_id, + const std::string& id, + const base::FilePath& file_path, + bool is_directory) = 0; + + // If the file with |id| is not in the queue of files to be retained + // permanently, adds the file to the back of the queue, evicting the least + // recently used entry at the front of the queue if it is full. If it is + // already present, moves it to the back of the queue. The |id| must have been + // registered. + virtual void EnqueueFileEntry(const std::string& extension_id, + const std::string& id) = 0; + + // Returns whether the file entry with the given |id| has been registered. + virtual bool IsRegistered(const std::string& extension_id, + const std::string& id) = 0; + + // Gets a borrowed pointer to the file entry with the specified |id|. Returns + // nullptr if the file entry has not been registered. + virtual const SavedFileEntry* GetFileEntry(const std::string& extension_id, + const std::string& id) = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_FILE_SYSTEM_SAVED_FILES_SERVICE_INTERFACE_H_
diff --git a/gin/public/v8_platform.h b/gin/public/v8_platform.h index 896a21e..9bcc57894 100644 --- a/gin/public/v8_platform.h +++ b/gin/public/v8_platform.h
@@ -54,6 +54,7 @@ void AddTraceStateObserver(v8::Platform::TraceStateObserver*) override; void RemoveTraceStateObserver(v8::Platform::TraceStateObserver*) override; StackTracePrinter GetStackTracePrinter() override; + v8::TracingController* GetTracingController() override; private: friend struct base::LazyInstanceTraitsBase<V8Platform>; @@ -61,6 +62,9 @@ V8Platform(); ~V8Platform() override; + class TracingControllerImpl; + std::unique_ptr<TracingControllerImpl> tracing_controller_; + DISALLOW_COPY_AND_ASSIGN(V8Platform); };
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc index 1bfa2f6..fd0ef94 100644 --- a/gin/v8_platform.cc +++ b/gin/v8_platform.cc
@@ -54,12 +54,144 @@ trace.Print(); } +class ConvertableToTraceFormatWrapper final + : public base::trace_event::ConvertableToTraceFormat { + public: + explicit ConvertableToTraceFormatWrapper( + std::unique_ptr<v8::ConvertableToTraceFormat>& inner) + : inner_(std::move(inner)) {} + ~ConvertableToTraceFormatWrapper() override = default; + void AppendAsTraceFormat(std::string* out) const final { + inner_->AppendAsTraceFormat(out); + } + + private: + std::unique_ptr<v8::ConvertableToTraceFormat> inner_; + + DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormatWrapper); +}; + +class EnabledStateObserverImpl final + : public base::trace_event::TraceLog::EnabledStateObserver { + public: + EnabledStateObserverImpl() = default; + + void OnTraceLogEnabled() final { + base::AutoLock lock(mutex_); + for (auto* o : observers_) { + o->OnTraceEnabled(); + } + } + + void OnTraceLogDisabled() final { + base::AutoLock lock(mutex_); + for (auto* o : observers_) { + o->OnTraceDisabled(); + } + } + + void AddObserver(v8::TracingController::TraceStateObserver* observer) { + { + base::AutoLock lock(mutex_); + DCHECK(!observers_.count(observer)); + if (observers_.empty()) { + base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver( + this); + } + observers_.insert(observer); + } + // Fire the observer if recording is already in progress. + if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) + observer->OnTraceEnabled(); + } + + void RemoveObserver(v8::TracingController::TraceStateObserver* observer) { + base::AutoLock lock(mutex_); + DCHECK(observers_.count(observer) == 1); + observers_.erase(observer); + if (observers_.empty()) { + base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver( + this); + } + } + + private: + base::Lock mutex_; + std::unordered_set<v8::TracingController::TraceStateObserver*> observers_; + + DISALLOW_COPY_AND_ASSIGN(EnabledStateObserverImpl); +}; + +base::LazyInstance<EnabledStateObserverImpl>::Leaky g_trace_state_dispatcher = + LAZY_INSTANCE_INITIALIZER; + } // namespace +class V8Platform::TracingControllerImpl : public v8::TracingController { + public: + TracingControllerImpl() = default; + ~TracingControllerImpl() override = default; + + // TracingController implementation. + const uint8_t* GetCategoryGroupEnabled(const char* name) override { + return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name); + } + uint64_t AddTraceEvent( + char phase, + const uint8_t* category_enabled_flag, + const char* name, + const char* scope, + uint64_t id, + uint64_t bind_id, + int32_t num_args, + const char** arg_names, + const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, + unsigned int flags) override { + std::unique_ptr<base::trace_event::ConvertableToTraceFormat> + convertables[2]; + if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) { + convertables[0].reset( + new ConvertableToTraceFormatWrapper(arg_convertables[0])); + } + if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) { + convertables[1].reset( + new ConvertableToTraceFormatWrapper(arg_convertables[1])); + } + DCHECK_LE(num_args, 2); + base::trace_event::TraceEventHandle handle = + TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID( + phase, category_enabled_flag, name, scope, id, bind_id, num_args, + arg_names, arg_types, (const long long unsigned int*)arg_values, + convertables, flags); + uint64_t result; + memcpy(&result, &handle, sizeof(result)); + return result; + } + void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, + const char* name, + uint64_t handle) override { + base::trace_event::TraceEventHandle traceEventHandle; + memcpy(&traceEventHandle, &handle, sizeof(handle)); + TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name, + traceEventHandle); + } + void AddTraceStateObserver(TraceStateObserver* observer) override { + g_trace_state_dispatcher.Get().AddObserver(observer); + } + void RemoveTraceStateObserver(TraceStateObserver* observer) override { + g_trace_state_dispatcher.Get().RemoveObserver(observer); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl); +}; + // static V8Platform* V8Platform::Get() { return g_v8_platform.Pointer(); } -V8Platform::V8Platform() {} +V8Platform::V8Platform() : tracing_controller_(new TracingControllerImpl) {} V8Platform::~V8Platform() {} @@ -125,8 +257,12 @@ static_cast<double>(base::Time::kMicrosecondsPerSecond); } +v8::TracingController* V8Platform::GetTracingController() { + return tracing_controller_.get(); +} + const uint8_t* V8Platform::GetCategoryGroupEnabled(const char* name) { - return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name); + return tracing_controller_->GetCategoryGroupEnabled(name); } const char* V8Platform::GetCategoryGroupName( @@ -135,27 +271,6 @@ category_enabled_flag); } -namespace { - -class ConvertableToTraceFormatWrapper - : public base::trace_event::ConvertableToTraceFormat { - public: - explicit ConvertableToTraceFormatWrapper( - std::unique_ptr<v8::ConvertableToTraceFormat>& inner) - : inner_(std::move(inner)) {} - ~ConvertableToTraceFormatWrapper() override = default; - void AppendAsTraceFormat(std::string* out) const final { - inner_->AppendAsTraceFormat(out); - } - - private: - std::unique_ptr<v8::ConvertableToTraceFormat> inner_; - - DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormatWrapper); -}; - -} // namespace - uint64_t V8Platform::AddTraceEvent( char phase, const uint8_t* category_enabled_flag, @@ -169,101 +284,26 @@ const uint64_t* arg_values, std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables, unsigned int flags) { - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> convertables[2]; - if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertables[0].reset( - new ConvertableToTraceFormatWrapper(arg_convertables[0])); - } - if (num_args > 1 && arg_types[1] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertables[1].reset( - new ConvertableToTraceFormatWrapper(arg_convertables[1])); - } - DCHECK_LE(num_args, 2); - base::trace_event::TraceEventHandle handle = - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID( - phase, category_enabled_flag, name, scope, id, bind_id, num_args, - arg_names, arg_types, (const long long unsigned int*)arg_values, - convertables, flags); - uint64_t result; - memcpy(&result, &handle, sizeof(result)); - return result; + return tracing_controller_->AddTraceEvent( + phase, category_enabled_flag, name, scope, id, bind_id, num_args, + arg_names, arg_types, arg_values, arg_convertables, flags); } void V8Platform::UpdateTraceEventDuration(const uint8_t* category_enabled_flag, const char* name, uint64_t handle) { - base::trace_event::TraceEventHandle traceEventHandle; - memcpy(&traceEventHandle, &handle, sizeof(handle)); - TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name, - traceEventHandle); + tracing_controller_->UpdateTraceEventDuration(category_enabled_flag, name, + handle); } -namespace { - -class EnabledStateObserverImpl final - : public base::trace_event::TraceLog::EnabledStateObserver { - public: - EnabledStateObserverImpl() = default; - - void OnTraceLogEnabled() final { - base::AutoLock lock(mutex_); - for (auto* o : observers_) { - o->OnTraceEnabled(); - } - } - - void OnTraceLogDisabled() final { - base::AutoLock lock(mutex_); - for (auto* o : observers_) { - o->OnTraceDisabled(); - } - } - - void AddObserver(v8::Platform::TraceStateObserver* observer) { - { - base::AutoLock lock(mutex_); - DCHECK(!observers_.count(observer)); - if (observers_.empty()) { - base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver( - this); - } - observers_.insert(observer); - } - // Fire the observer if recording is already in progress. - if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) - observer->OnTraceEnabled(); - } - - void RemoveObserver(v8::Platform::TraceStateObserver* observer) { - base::AutoLock lock(mutex_); - DCHECK(observers_.count(observer) == 1); - observers_.erase(observer); - if (observers_.empty()) { - base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver( - this); - } - } - - private: - base::Lock mutex_; - std::unordered_set<v8::Platform::TraceStateObserver*> observers_; - - DISALLOW_COPY_AND_ASSIGN(EnabledStateObserverImpl); -}; - -base::LazyInstance<EnabledStateObserverImpl>::Leaky g_trace_state_dispatcher = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - void V8Platform::AddTraceStateObserver( v8::Platform::TraceStateObserver* observer) { - g_trace_state_dispatcher.Get().AddObserver(observer); + tracing_controller_->AddTraceStateObserver(observer); } void V8Platform::RemoveTraceStateObserver( v8::Platform::TraceStateObserver* observer) { - g_trace_state_dispatcher.Get().RemoveObserver(observer); + tracing_controller_->RemoveTraceStateObserver(observer); } v8::Platform::StackTracePrinter V8Platform::GetStackTracePrinter() {
diff --git a/net/spdy/core/spdy_framer.cc b/net/spdy/core/spdy_framer.cc index 47482b2..fc131bb 100644 --- a/net/spdy/core/spdy_framer.cc +++ b/net/spdy/core/spdy_framer.cc
@@ -72,10 +72,6 @@ // Used to indicate no flags in a HTTP2 flags field. const uint8_t kNoFlags = 0; -// Wire sizes of priority payloads. -const size_t kPriorityDependencyPayloadSize = 4; -const size_t kPriorityWeightPayloadSize = 1; - // Wire size of pad length field. const size_t kPadLengthFieldSize = 1; @@ -215,82 +211,55 @@ } size_t SpdyFramer::GetDataFrameMinimumSize() const { - return kDataFrameMinimumSize; + return size_utils::GetDataFrameMinimumSize(); } -// Size, in bytes, of the control frame header. size_t SpdyFramer::GetFrameHeaderSize() const { - return kFrameHeaderSize; + return size_utils::GetFrameHeaderSize(); } size_t SpdyFramer::GetRstStreamSize() const { - // Size, in bytes, of a RST_STREAM frame. - // Calculated as: - // frame prefix + 4 (status code) - return GetFrameHeaderSize() + 4; + return size_utils::GetRstStreamSize(); } size_t SpdyFramer::GetSettingsMinimumSize() const { - // Size, in bytes, of a SETTINGS frame not including the IDs and values - // from the variable-length value block. - return GetFrameHeaderSize(); + return size_utils::GetSettingsMinimumSize(); } size_t SpdyFramer::GetPingSize() const { - // Size, in bytes, of this PING frame. - // Calculated as: - // control frame header + 8 (id) - return GetFrameHeaderSize() + 8; + return size_utils::GetPingSize(); } size_t SpdyFramer::GetGoAwayMinimumSize() const { - // Size, in bytes, of this GOAWAY frame. Calculated as: - // Control frame header + last stream id (4 bytes) + error code (4 bytes). - return GetFrameHeaderSize() + 8; + return size_utils::GetGoAwayMinimumSize(); } size_t SpdyFramer::GetHeadersMinimumSize() const { - // Size, in bytes, of a HEADERS frame not including the variable-length - // header block. - return GetFrameHeaderSize(); + return size_utils::GetFrameHeaderSize(); } size_t SpdyFramer::GetWindowUpdateSize() const { - // Size, in bytes, of a WINDOW_UPDATE frame. - // Calculated as: - // frame prefix + 4 (delta) - return GetFrameHeaderSize() + 4; + return size_utils::GetWindowUpdateSize(); } size_t SpdyFramer::GetPushPromiseMinimumSize() const { - // Size, in bytes, of a PUSH_PROMISE frame, sans the embedded header block. - // Calculated as frame prefix + 4 (promised stream id) - return GetFrameHeaderSize() + 4; + return size_utils::GetPushPromiseMinimumSize(); } size_t SpdyFramer::GetContinuationMinimumSize() const { - // Size, in bytes, of a CONTINUATION frame not including the variable-length - // headers fragments. - return GetFrameHeaderSize(); + return size_utils::GetContinuationMinimumSize(); } size_t SpdyFramer::GetAltSvcMinimumSize() const { - // Size, in bytes, of an ALTSVC frame not including the Field-Value and - // (optional) Origin fields, both of which can vary in length. Note that - // this gives a lower bound on the frame size rather than a true minimum; - // the actual frame should always be larger than this. - // Calculated as frame prefix + 2 (origin_len). - return GetFrameHeaderSize() + 2; + return size_utils::GetAltSvcMinimumSize(); } size_t SpdyFramer::GetPrioritySize() const { - // Size, in bytes, of a PRIORITY frame. - return GetFrameHeaderSize() + kPriorityDependencyPayloadSize + - kPriorityWeightPayloadSize; + return size_utils::GetPrioritySize(); } size_t SpdyFramer::GetFrameMinimumSize() const { - return GetFrameHeaderSize(); + return size_utils::GetFrameMinimumSize(); } size_t SpdyFramer::GetFrameMaximumSize() const {
diff --git a/net/spdy/core/spdy_protocol.cc b/net/spdy/core/spdy_protocol.cc index 89b9c9541..c95fc0f 100644 --- a/net/spdy/core/spdy_protocol.cc +++ b/net/spdy/core/spdy_protocol.cc
@@ -13,6 +13,89 @@ const char* const kHttp2ConnectionHeaderPrefix = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; +namespace size_utils { + +size_t GetDataFrameMinimumSize() { + return kDataFrameMinimumSize; +} + +// Size, in bytes, of the control frame header. +size_t GetFrameHeaderSize() { + return kFrameHeaderSize; +} + +size_t GetRstStreamSize() { + // Size, in bytes, of a RST_STREAM frame. + // Calculated as: + // frame prefix + 4 (status code) + return GetFrameHeaderSize() + 4; +} + +size_t GetSettingsMinimumSize() { + // Size, in bytes, of a SETTINGS frame not including the IDs and values + // from the variable-length value block. + return GetFrameHeaderSize(); +} + +size_t GetPingSize() { + // Size, in bytes, of this PING frame. + // Calculated as: + // control frame header + 8 (id) + return GetFrameHeaderSize() + 8; +} + +size_t GetGoAwayMinimumSize() { + // Size, in bytes, of this GOAWAY frame. Calculated as: + // Control frame header + last stream id (4 bytes) + error code (4 bytes). + return GetFrameHeaderSize() + 8; +} + +size_t GetHeadersMinimumSize() { + // Size, in bytes, of a HEADERS frame not including the variable-length + // header block. + return GetFrameHeaderSize(); +} + +size_t GetWindowUpdateSize() { + // Size, in bytes, of a WINDOW_UPDATE frame. + // Calculated as: + // frame prefix + 4 (delta) + return GetFrameHeaderSize() + 4; +} + +size_t GetPushPromiseMinimumSize() { + // Size, in bytes, of a PUSH_PROMISE frame, sans the embedded header block. + // Calculated as frame prefix + 4 (promised stream id) + return GetFrameHeaderSize() + 4; +} + +size_t GetContinuationMinimumSize() { + // Size, in bytes, of a CONTINUATION frame not including the variable-length + // headers fragments. + return GetFrameHeaderSize(); +} + +size_t GetAltSvcMinimumSize() { + // Size, in bytes, of an ALTSVC frame not including the Field-Value and + // (optional) Origin fields, both of which can vary in length. Note that + // this gives a lower bound on the frame size rather than a true minimum; + // the actual frame should always be larger than this. + // Calculated as frame prefix + 2 (origin_len). + return GetFrameHeaderSize() + 2; +} + +size_t GetPrioritySize() { + // Size, in bytes, of a PRIORITY frame. + return GetFrameHeaderSize() + kPriorityDependencyPayloadSize + + kPriorityWeightPayloadSize; +} + +size_t GetFrameMinimumSize() { + return GetFrameHeaderSize(); +} + +} // namespace size_utils + std::ostream& operator<<(std::ostream& out, SpdySettingsIds id) { return out << static_cast<uint16_t>(id); } @@ -208,6 +291,10 @@ const char* const kHttp2Npn = "h2"; +int SpdyFrameIR::flow_control_window_consumed() const { + return 0; +} + SpdyFrameWithHeaderBlockIR::SpdyFrameWithHeaderBlockIR( SpdyStreamId stream_id, SpdyHeaderBlock header_block) @@ -252,6 +339,10 @@ return SpdyFrameType::DATA; } +int SpdyDataIR::flow_control_window_consumed() const { + return padded() ? 1 + padding_payload_len() + data_len() : data_len(); +} + SpdyRstStreamIR::SpdyRstStreamIR(SpdyStreamId stream_id, SpdyErrorCode error_code) : SpdyFrameIR(stream_id) { @@ -389,4 +480,12 @@ return static_cast<SpdyFrameType>(type()); } +int SpdyUnknownIR::flow_control_window_consumed() const { + if (frame_type() == SpdyFrameType::DATA) { + return payload_.size(); + } else { + return 0; + } +} + } // namespace net
diff --git a/net/spdy/core/spdy_protocol.h b/net/spdy/core/spdy_protocol.h index d40f6fb..12fe4151 100644 --- a/net/spdy/core/spdy_protocol.h +++ b/net/spdy/core/spdy_protocol.h
@@ -277,6 +277,31 @@ // The NPN string for HTTP2, "h2". extern const char* const kHttp2Npn; +// Wire sizes of priority payloads. +const size_t kPriorityDependencyPayloadSize = 4; +const size_t kPriorityWeightPayloadSize = 1; + +namespace size_utils { + +// Returns the (minimum) size of frames (sans variable-length portions). +size_t GetDataFrameMinimumSize(); +size_t GetFrameHeaderSize(); +size_t GetRstStreamSize(); +size_t GetSettingsMinimumSize(); +size_t GetPingSize(); +size_t GetGoAwayMinimumSize(); +size_t GetHeadersMinimumSize(); +size_t GetWindowUpdateSize(); +size_t GetPushPromiseMinimumSize(); +size_t GetContinuationMinimumSize(); +size_t GetAltSvcMinimumSize(); +size_t GetPrioritySize(); + +// Returns the minimum size a frame can be (data or control). +size_t GetFrameMinimumSize(); + +} // namespace size_utils + // Variant type (i.e. tagged union) that is either a SPDY 3.x priority value, // or else an HTTP/2 stream dependency tuple {parent stream ID, weight, // exclusive bit}. Templated to allow for use by QUIC code; SPDY and HTTP/2 @@ -384,6 +409,10 @@ virtual SpdyFrameType frame_type() const = 0; SpdyStreamId stream_id() const { return stream_id_; } + // Returns the number of bytes of flow control window that would be consumed + // by this frame if written to the wire. + virtual int flow_control_window_consumed() const; + protected: SpdyFrameIR() : stream_id_(0) {} explicit SpdyFrameIR(SpdyStreamId stream_id) : stream_id_(stream_id) {} @@ -499,6 +528,8 @@ SpdyFrameType frame_type() const override; + int flow_control_window_consumed() const override; + private: // Used to store data that this SpdyDataIR should own. std::unique_ptr<SpdyString> data_store_; @@ -812,6 +843,8 @@ SpdyFrameType frame_type() const override; + int flow_control_window_consumed() const override; + private: uint8_t type_; uint8_t flags_;
diff --git a/net/spdy/core/spdy_protocol_test.cc b/net/spdy/core/spdy_protocol_test.cc index cc222605..e5a71fe 100644 --- a/net/spdy/core/spdy_protocol_test.cc +++ b/net/spdy/core/spdy_protocol_test.cc
@@ -230,11 +230,13 @@ SpdyDataIR d2(/* stream_id = */ 2, s2); EXPECT_EQ(SpdyStringPiece(d2.data(), d2.data_len()), s2); EXPECT_NE(SpdyStringPiece(d1.data(), d1.data_len()), s2); + EXPECT_EQ((int)d1.data_len(), d1.flow_control_window_consumed()); // Confirm copies a const string. const SpdyString foo = "foo"; SpdyDataIR d3(/* stream_id = */ 3, foo); EXPECT_EQ(foo, d3.data()); + EXPECT_EQ((int)d3.data_len(), d3.flow_control_window_consumed()); // Confirm copies a non-const string. SpdyString bar = "bar"; @@ -252,6 +254,10 @@ // Confirms makes a copy of string literal. SpdyDataIR d7(/* stream_id = */ 7, "something else"); EXPECT_EQ(SpdyStringPiece(d7.data(), d7.data_len()), "something else"); + + SpdyDataIR d8(/* stream_id = */ 8, "shawarma"); + d8.set_padding_len(20); + EXPECT_EQ(28, d8.flow_control_window_consumed()); } } // namespace test
diff --git a/printing/DEPS b/printing/DEPS index 038006b3..8cfa7a2 100644 --- a/printing/DEPS +++ b/printing/DEPS
@@ -9,5 +9,4 @@ "+ui/base/resource", "+ui/base/text", "+ui/gfx", - "+win8/util", ]
diff --git a/remoting/client/input/keyboard_input_strategy.h b/remoting/client/input/keyboard_input_strategy.h index 9f18dc6..389d87f 100644 --- a/remoting/client/input/keyboard_input_strategy.h +++ b/remoting/client/input/keyboard_input_strategy.h
@@ -23,8 +23,8 @@ // Handle a text event. virtual void HandleTextEvent(const std::string& text, uint8_t modifiers) = 0; - // Handle delete event. - virtual void HandleDeleteEvent(uint8_t modifiers) = 0; + // Handle keys event as keycodes. + virtual void HandleKeysEvent(std::queue<KeyEvent> keys) = 0; }; } // namespace remoting
diff --git a/remoting/client/input/keyboard_interpreter.cc b/remoting/client/input/keyboard_interpreter.cc index 725956a..55b28e4 100644 --- a/remoting/client/input/keyboard_interpreter.cc +++ b/remoting/client/input/keyboard_interpreter.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "remoting/client/input/text_keyboard_input_strategy.h" +#include "ui/events/keycodes/dom/dom_code.h" namespace remoting { @@ -22,7 +23,43 @@ } void KeyboardInterpreter::HandleDeleteEvent(uint8_t modifiers) { - input_strategy_->HandleDeleteEvent(modifiers); + std::queue<KeyEvent> keys; + // TODO(nicholss): Handle modifers. + // Key press. + keys.push({static_cast<uint32_t>(ui::DomCode::BACKSPACE), true}); + + // Key release. + keys.push({static_cast<uint32_t>(ui::DomCode::BACKSPACE), false}); + + input_strategy_->HandleKeysEvent(keys); +} + +void KeyboardInterpreter::HandleCtrlAltDeleteEvent() { + std::queue<KeyEvent> keys; + + // Key press. + keys.push({static_cast<uint32_t>(ui::DomCode::CONTROL_LEFT), true}); + keys.push({static_cast<uint32_t>(ui::DomCode::ALT_LEFT), true}); + keys.push({static_cast<uint32_t>(ui::DomCode::DEL), true}); + + // Key release. + keys.push({static_cast<uint32_t>(ui::DomCode::DEL), false}); + keys.push({static_cast<uint32_t>(ui::DomCode::ALT_LEFT), false}); + keys.push({static_cast<uint32_t>(ui::DomCode::CONTROL_LEFT), false}); + + input_strategy_->HandleKeysEvent(keys); +} + +void KeyboardInterpreter::HandlePrintScreenEvent() { + std::queue<KeyEvent> keys; + + // Key press. + keys.push({static_cast<uint32_t>(ui::DomCode::PRINT_SCREEN), true}); + + // Key release. + keys.push({static_cast<uint32_t>(ui::DomCode::PRINT_SCREEN), false}); + + input_strategy_->HandleKeysEvent(keys); } } // namespace remoting
diff --git a/remoting/client/input/keyboard_interpreter.h b/remoting/client/input/keyboard_interpreter.h index 3780397..300b43ad 100644 --- a/remoting/client/input/keyboard_interpreter.h +++ b/remoting/client/input/keyboard_interpreter.h
@@ -26,6 +26,12 @@ void HandleTextEvent(const std::string& text, uint8_t modifiers); // Delegates to |KeyboardInputStrategy| to covert and send the delete. void HandleDeleteEvent(uint8_t modifiers); + // Assembles CTRL+ALT+DEL key event and then delegates to + // |KeyboardInputStrategy| send the keys. + void HandleCtrlAltDeleteEvent(); + // Assembles PRINT_SCREEN key event and then delegates to + // |KeyboardInputStrategy| send the keys. + void HandlePrintScreenEvent(); private: std::unique_ptr<KeyboardInputStrategy> input_strategy_;
diff --git a/remoting/client/input/text_keyboard_input_strategy.cc b/remoting/client/input/text_keyboard_input_strategy.cc index c1b11c59..e4d2061 100644 --- a/remoting/client/input/text_keyboard_input_strategy.cc +++ b/remoting/client/input/text_keyboard_input_strategy.cc
@@ -24,8 +24,7 @@ input_injector_->SendTextEvent(text); } -void TextKeyboardInputStrategy::HandleDeleteEvent(uint8_t modifiers) { - std::queue<KeyEvent> keys = ConvertDeleteEvent(modifiers); +void TextKeyboardInputStrategy::HandleKeysEvent(std::queue<KeyEvent> keys) { while (!keys.empty()) { KeyEvent key = keys.front(); input_injector_->SendKeyEvent(0, key.keycode, key.keydown); @@ -33,17 +32,4 @@ } } -std::queue<KeyEvent> TextKeyboardInputStrategy::ConvertDeleteEvent( - uint8_t modifiers) { - std::queue<KeyEvent> keys; - // TODO(nicholss): Handle modifers. - // Key press. - keys.push({static_cast<uint32_t>(ui::DomCode::BACKSPACE), true}); - - // Key release. - keys.push({static_cast<uint32_t>(ui::DomCode::BACKSPACE), false}); - - return keys; -} - } // namespace remoting
diff --git a/remoting/client/input/text_keyboard_input_strategy.h b/remoting/client/input/text_keyboard_input_strategy.h index 4772449..0c6ca1fa 100644 --- a/remoting/client/input/text_keyboard_input_strategy.h +++ b/remoting/client/input/text_keyboard_input_strategy.h
@@ -21,7 +21,7 @@ // KeyboardInputStrategy overrides. void HandleTextEvent(const std::string& text, uint8_t modifiers) override; - void HandleDeleteEvent(uint8_t modifiers) override; + void HandleKeysEvent(std::queue<KeyEvent> keys) override; private: std::queue<KeyEvent> ConvertDeleteEvent(uint8_t modifiers);
diff --git a/remoting/ios/app/app_delegate.h b/remoting/ios/app/app_delegate.h index 9235202..68320f30 100644 --- a/remoting/ios/app/app_delegate.h +++ b/remoting/ios/app/app_delegate.h
@@ -17,6 +17,17 @@ @property(strong, nonatomic) UIWindow* window; @property(class, strong, nonatomic, readonly) AppDelegate* instance; +// This will push the FAQ view controller onto the provided nav controller. +- (void)navigateToFAQs:(UINavigationController*)navigationController; + +// This will push the Help Center view controller onto the provided nav +// controller. +- (void)navigateToHelpCenter:(UINavigationController*)navigationController; + +// This will push the Send Feedback view controller onto the provided nav +// controller. +- (void)navigateToSendFeedback:(UINavigationController*)navigationController; + @end #endif // REMOTING_IOS_APP_APP_DELEGATE_H_
diff --git a/remoting/ios/app/app_delegate.mm b/remoting/ios/app/app_delegate.mm index 9a9abec..4b137f1 100644 --- a/remoting/ios/app/app_delegate.mm +++ b/remoting/ios/app/app_delegate.mm
@@ -8,6 +8,8 @@ #import "remoting/ios/app/app_delegate.h" +#import <WebKit/WebKit.h> + #include "base/logging.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -21,6 +23,13 @@ } @end +// TODO(nicholss): These urls should come from a global config. +static NSString* const kHelpCenterUrl = + @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS"; +// TODO(nicholss): There is no FAQ page at the moment. +static NSString* const kFAQsUrl = + @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS"; + @implementation AppDelegate @synthesize window = _window; @@ -82,7 +91,9 @@ #pragma mark - Properties + (AppDelegate*)instance { - return (AppDelegate*)UIApplication.sharedApplication.delegate; + id<UIApplicationDelegate> delegate = UIApplication.sharedApplication.delegate; + DCHECK([delegate isKindOfClass:AppDelegate.class]); + return (AppDelegate*)delegate; } #pragma mark - Private @@ -98,4 +109,42 @@ [self.window makeKeyAndVisible]; } +#pragma mark - AppDelegate + +- (void)navigateToFAQs:(UINavigationController*)navigationController { + [self navigateToUrl:kFAQsUrl + title:@"FAQs" + navigationController:navigationController]; +} + +- (void)navigateToHelpCenter:(UINavigationController*)navigationController { + [self navigateToUrl:kHelpCenterUrl + title:@"Help Center" + navigationController:navigationController]; +} + +- (void)navigateToSendFeedback:(UINavigationController*)navigationController { + UIViewController* feedbackController = [[UIViewController alloc] init]; + feedbackController.title = @"Feedback"; + [navigationController pushViewController:feedbackController animated:YES]; +} + +#pragma mark - Private + +- (void)navigateToUrl:(NSString*)url + title:(NSString*)title + navigationController:(UINavigationController*)navigationController { + UIViewController* viewController = [[UIViewController alloc] init]; + viewController.title = title; + + NSURLRequest* request = + [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; + WKWebView* webView = + [[WKWebView alloc] initWithFrame:viewController.view.frame + configuration:[[WKWebViewConfiguration alloc] init]]; + [viewController.view addSubview:webView]; + [navigationController pushViewController:viewController animated:YES]; + [webView loadRequest:request]; +} + @end
diff --git a/remoting/ios/app/host_view_controller.mm b/remoting/ios/app/host_view_controller.mm index b761e2d..6bf3993 100644 --- a/remoting/ios/app/host_view_controller.mm +++ b/remoting/ios/app/host_view_controller.mm
@@ -28,7 +28,8 @@ static const CGFloat kKeyboardAnimationTime = 0.3; @interface HostViewController ()<ClientKeyboardDelegate, - ClientGesturesDelegate> { + ClientGesturesDelegate, + RemotingSettingsViewControllerDelegate> { RemotingClient* _client; MDCActionImageView* _actionImageView; MDCFloatingButton* _floatingButton; @@ -226,6 +227,40 @@ [self hideKeyboard]; } +#pragma mark - RemotingSettingsViewControllerDelegate + +- (void)setShrinkToFit:(BOOL)shrinkToFit { + // TODO(nicholss): I don't think this option makes sense for mobile. + NSLog(@"TODO: shrinkToFit %d", shrinkToFit); +} + +- (void)setResizeToFit:(BOOL)resizeToFit { + // TODO(nicholss): I don't think this option makes sense for phones. Maybe + // for an iPad. Maybe we add a native screen size mimimum before enabling + // this option? Ask Jon. + NSLog(@"TODO: resizeToFit %d", resizeToFit); +} + +- (void)useDirectInputMode { + // TODO(nicholss): Store this as a preference. + _client.gestureInterpreter->SetInputMode( + remoting::GestureInterpreter::DIRECT_INPUT_MODE); +} + +- (void)useTrackpadInputMode { + // TODO(nicholss): Store this as a preference. + _client.gestureInterpreter->SetInputMode( + remoting::GestureInterpreter::TRACKPAD_INPUT_MODE); +} + +- (void)sendCtrAltDel { + _client.keyboardInterpreter->HandleCtrlAltDeleteEvent(); +} + +- (void)sendPrintScreen { + _client.keyboardInterpreter->HandlePrintScreenEvent(); +} + #pragma mark - Private - (void)didTap:(id)sender { @@ -241,6 +276,7 @@ if ([self isKeyboardActive]) { void (^hideKeyboardHandler)(UIAlertAction*) = ^(UIAlertAction*) { [self hideKeyboard]; + [_actionImageView setActive:NO animated:YES]; }; [alert addAction:[UIAlertAction actionWithTitle:@"Hide Keyboard" style:UIAlertActionStyleDefault @@ -248,6 +284,7 @@ } else { void (^showKeyboardHandler)(UIAlertAction*) = ^(UIAlertAction*) { [self showKeyboard]; + [_actionImageView setActive:NO animated:YES]; }; [alert addAction:[UIAlertAction actionWithTitle:@"Show Keyboard" style:UIAlertActionStyleDefault @@ -265,6 +302,7 @@ currentInputMode == remoting::GestureInterpreter::DIRECT_INPUT_MODE ? remoting::GestureInterpreter::TRACKPAD_INPUT_MODE : remoting::GestureInterpreter::DIRECT_INPUT_MODE); + [_actionImageView setActive:NO animated:YES]; }; [alert addAction:[UIAlertAction actionWithTitle:switchInputModeTitle style:UIAlertActionStyleDefault @@ -273,6 +311,7 @@ void (^disconnectHandler)(UIAlertAction*) = ^(UIAlertAction*) { [_client disconnectFromHost]; [self.navigationController popViewControllerAnimated:YES]; + [_actionImageView setActive:NO animated:YES]; }; [alert addAction:[UIAlertAction actionWithTitle:@"Disconnect" style:UIAlertActionStyleDefault @@ -282,9 +321,12 @@ void (^settingsHandler)(UIAlertAction*) = ^(UIAlertAction*) { RemotingSettingsViewController* settingsViewController = [[RemotingSettingsViewController alloc] init]; - [weakSelf presentViewController:settingsViewController - animated:YES - completion:nil]; + settingsViewController.delegate = weakSelf; + settingsViewController.inputMode = currentInputMode; + UINavigationController* navController = [[UINavigationController alloc] + initWithRootViewController:settingsViewController]; + [weakSelf presentViewController:navController animated:YES completion:nil]; + [_actionImageView setActive:NO animated:YES]; }; [alert addAction:[UIAlertAction actionWithTitle:@"Settings" style:UIAlertActionStyleDefault
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.h b/remoting/ios/app/settings/remoting_settings_view_controller.h index 8a8957e8..c675336 100644 --- a/remoting/ios/app/settings/remoting_settings_view_controller.h +++ b/remoting/ios/app/settings/remoting_settings_view_controller.h
@@ -7,7 +7,36 @@ #import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h" +#include "remoting/client/gesture_interpreter.h" + +@protocol RemotingSettingsViewControllerDelegate<NSObject> + +@optional // Applies to all methods. + +// Sets the setting to shrink the display of the host to the client window. +- (void)setShrinkToFit:(BOOL)shrinkToFit; +// Sets the setting to resize the host to fix the client window. +- (void)setResizeToFit:(BOOL)resizeToFit; +// Use the direct input mode for the current connection. +- (void)useDirectInputMode; +// Use the trackpad input mode for the current connection. +- (void)useTrackpadInputMode; +// Sends the key combo ctrl + alt + del to the host. +- (void)sendCtrAltDel; +// Sends the key Print Screen to the host. +- (void)sendPrintScreen; + +@end + +// |RemotingSettingsViewController| is intended to be reinitialized before it +// is displayed. It only synchronizes to the delegate. +// TODO(nicholss): Perhaps we should remove the internal settings storage and +// get the state from the delegate directly. It will remove the sync issue. @interface RemotingSettingsViewController : MDCCollectionViewController + +@property(weak, nonatomic) id<RemotingSettingsViewControllerDelegate> delegate; +@property(nonatomic) remoting::GestureInterpreter::InputMode inputMode; + @end #endif // REMOTING_IOS_APP_REMOTING_SETTINGS_SETTINGS_VIEW_CONTROLLER_H_
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.mm b/remoting/ios/app/settings/remoting_settings_view_controller.mm index 664b1e4..923847a 100644 --- a/remoting/ios/app/settings/remoting_settings_view_controller.mm +++ b/remoting/ios/app/settings/remoting_settings_view_controller.mm
@@ -10,6 +10,7 @@ #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" +#import "remoting/ios/app/app_delegate.h" #import "remoting/ios/app/remoting_theme.h" #import "remoting/ios/app/settings/setting_option.h" @@ -26,6 +27,9 @@ @implementation RemotingSettingsViewController +@synthesize delegate = _delegate; +@synthesize inputMode = _inputMode; + - (id)init { self = [super init]; if (self) { @@ -73,70 +77,15 @@ _sections = @[ @"Display options", @"Mouse options", @"Keyboard controls", @"Support" ]; - - _content = [NSMutableArray array]; - - SettingOption* shrinkOption = [[SettingOption alloc] init]; - shrinkOption.title = @"Shrink to fit"; - // TODO(nicholss): I think this text changes based on value. Confirm. - shrinkOption.subtext = @"Don't change resolution to match window"; - shrinkOption.style = OptionCheckbox; - shrinkOption.checked = NO; - - SettingOption* resizeOption = [[SettingOption alloc] init]; - resizeOption.title = @"Resize to fit"; - // TODO(nicholss): I think this text changes based on value. Confirm. - resizeOption.subtext = @"Update remote resolution to match window"; - resizeOption.style = OptionCheckbox; - resizeOption.checked = YES; - - [_content addObject:@[ shrinkOption, resizeOption ]]; - - SettingOption* directMode = [[SettingOption alloc] init]; - directMode.title = @"Touch mode"; - // TODO(nicholss): I think this text changes based on value. Confirm. - directMode.subtext = @"Screen acts like a touch screen"; - directMode.style = OptionSelector; - directMode.checked = YES; - - SettingOption* trackpadMode = [[SettingOption alloc] init]; - trackpadMode.title = @"Trackpad mode"; - // TODO(nicholss): I think this text changes based on value. Confirm. - trackpadMode.subtext = @"Screen acts like a trackpad"; - trackpadMode.style = OptionSelector; - trackpadMode.checked = NO; - - [_content addObject:@[ directMode, trackpadMode ]]; - - SettingOption* ctrlAltDelOption = [[SettingOption alloc] init]; - ctrlAltDelOption.title = @"Press \"Ctrl+Alt+Del\""; - ctrlAltDelOption.style = FlatButton; - - SettingOption* printScreenOption = [[SettingOption alloc] init]; - printScreenOption.title = @"Press \"Print Screen\""; - printScreenOption.style = FlatButton; - - [_content addObject:@[ ctrlAltDelOption, printScreenOption ]]; - - SettingOption* helpCenterOption = [[SettingOption alloc] init]; - helpCenterOption.title = @"Help center"; - helpCenterOption.style = FlatButton; - - SettingOption* faqsOption = [[SettingOption alloc] init]; - faqsOption.title = @"FAQs"; - faqsOption.style = FlatButton; - - SettingOption* sendFeedbackOption = [[SettingOption alloc] init]; - sendFeedbackOption.title = @"Send feedback"; - sendFeedbackOption.style = FlatButton; - - [_content addObject:@[ helpCenterOption, faqsOption, sendFeedbackOption ]]; - - DCHECK_EQ(_content.count, _sections.count); - self.styler.cellStyle = MDCCollectionViewCellStyleCard; } +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.navigationController setNavigationBarHidden:YES animated:animated]; + [self loadContent]; +} + #pragma mark - UICollectionViewDataSource - (NSInteger)numberOfSectionsInCollectionView: @@ -208,10 +157,34 @@ didSelectItemAtIndexPath:(NSIndexPath*)indexPath { [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; - MDCCollectionViewTextCell* cell = (MDCCollectionViewTextCell*)[collectionView - cellForItemAtIndexPath:indexPath]; + SettingOption* setting = _content[indexPath.section][indexPath.item]; - NSLog(@"Tapped: %@", cell); + NSMutableArray* updatedIndexPaths = [NSMutableArray arrayWithCapacity:1]; + int i = 0; + switch (setting.style) { + case OptionCheckbox: + setting.checked = !setting.checked; + [updatedIndexPaths + addObject:[NSIndexPath indexPathForItem:indexPath.item + inSection:indexPath.section]]; + break; + case OptionSelector: + for (SettingOption* s in _content[indexPath.section]) { + s.checked = NO; + [updatedIndexPaths + addObject:[NSIndexPath indexPathForItem:i + inSection:indexPath.section]]; + i++; + } + setting.checked = YES; + break; + case FlatButton: + break; + } + [self.collectionView reloadItemsAtIndexPaths:updatedIndexPaths]; + if (setting.action) { + setting.action(); + } } - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView @@ -245,4 +218,115 @@ [self dismissViewControllerAnimated:YES completion:nil]; } +- (void)loadContent { + _content = [NSMutableArray array]; + + __weak RemotingSettingsViewController* weakSelf = self; + + SettingOption* shrinkOption = [[SettingOption alloc] init]; + shrinkOption.title = @"Shrink to fit"; + // TODO(nicholss): I think this text changes based on value. Confirm. + shrinkOption.subtext = @"Don't change resolution to match window"; + shrinkOption.style = OptionCheckbox; + shrinkOption.checked = NO; + __weak SettingOption* weakShrinkOption = shrinkOption; + shrinkOption.action = ^{ + if ([weakSelf.delegate respondsToSelector:@selector(setShrinkToFit:)]) { + [weakSelf.delegate setShrinkToFit:weakShrinkOption.checked]; + } + }; + + SettingOption* resizeOption = [[SettingOption alloc] init]; + resizeOption.title = @"Resize to fit"; + // TODO(nicholss): I think this text changes based on value. Confirm. + resizeOption.subtext = @"Update remote resolution to match window"; + resizeOption.style = OptionCheckbox; + resizeOption.checked = YES; + __weak SettingOption* weakResizeOption = resizeOption; + resizeOption.action = ^{ + if ([weakSelf.delegate respondsToSelector:@selector(setResizeToFit:)]) { + [weakSelf.delegate setResizeToFit:weakResizeOption.checked]; + } + }; + + [_content addObject:@[ shrinkOption, resizeOption ]]; + + SettingOption* directMode = [[SettingOption alloc] init]; + directMode.title = @"Touch mode"; + // TODO(nicholss): I think this text changes based on value. Confirm. + directMode.subtext = @"Screen acts like a touch screen"; + directMode.style = OptionSelector; + directMode.checked = + self.inputMode == remoting::GestureInterpreter::DIRECT_INPUT_MODE; + directMode.action = ^{ + if ([weakSelf.delegate respondsToSelector:@selector(useDirectInputMode)]) { + [weakSelf.delegate useDirectInputMode]; + } + }; + + SettingOption* trackpadMode = [[SettingOption alloc] init]; + trackpadMode.title = @"Trackpad mode"; + // TODO(nicholss): I think this text changes based on value. Confirm. + trackpadMode.subtext = @"Screen acts like a trackpad"; + trackpadMode.style = OptionSelector; + trackpadMode.checked = + self.inputMode == remoting::GestureInterpreter::TRACKPAD_INPUT_MODE; + trackpadMode.action = ^{ + if ([weakSelf.delegate + respondsToSelector:@selector(useTrackpadInputMode)]) { + [weakSelf.delegate useTrackpadInputMode]; + } + }; + + [_content addObject:@[ directMode, trackpadMode ]]; + + SettingOption* ctrlAltDelOption = [[SettingOption alloc] init]; + ctrlAltDelOption.title = @"Press \"Ctrl+Alt+Del\""; + ctrlAltDelOption.style = FlatButton; + ctrlAltDelOption.action = ^{ + if ([weakSelf.delegate respondsToSelector:@selector(sendCtrAltDel)]) { + [weakSelf.delegate sendCtrAltDel]; + } + }; + + SettingOption* printScreenOption = [[SettingOption alloc] init]; + printScreenOption.title = @"Press \"Print Screen\""; + printScreenOption.style = FlatButton; + printScreenOption.action = ^{ + if ([weakSelf.delegate respondsToSelector:@selector(sendPrintScreen)]) { + [weakSelf.delegate sendPrintScreen]; + } + }; + + [_content addObject:@[ ctrlAltDelOption, printScreenOption ]]; + + SettingOption* helpCenterOption = [[SettingOption alloc] init]; + helpCenterOption.title = @"Help center"; + helpCenterOption.style = FlatButton; + helpCenterOption.action = ^{ + [AppDelegate.instance navigateToHelpCenter:weakSelf.navigationController]; + [weakSelf.navigationController setNavigationBarHidden:NO animated:YES]; + }; + + SettingOption* faqsOption = [[SettingOption alloc] init]; + faqsOption.title = @"FAQs"; + faqsOption.style = FlatButton; + faqsOption.action = ^{ + [AppDelegate.instance navigateToFAQs:weakSelf.navigationController]; + [weakSelf.navigationController setNavigationBarHidden:NO animated:YES]; + }; + + SettingOption* sendFeedbackOption = [[SettingOption alloc] init]; + sendFeedbackOption.title = @"Send feedback"; + sendFeedbackOption.style = FlatButton; + sendFeedbackOption.action = ^{ + [AppDelegate.instance navigateToSendFeedback:self.navigationController]; + [weakSelf.navigationController setNavigationBarHidden:NO animated:YES]; + }; + + [_content addObject:@[ helpCenterOption, faqsOption, sendFeedbackOption ]]; + + DCHECK_EQ(_content.count, _sections.count); +} + @end
diff --git a/testing/android/empty_apk/AndroidManifest.xml b/testing/android/empty_apk/AndroidManifest.xml new file mode 100644 index 0000000..610dcdd --- /dev/null +++ b/testing/android/empty_apk/AndroidManifest.xml
@@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 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. --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="{{package}}"> +</manifest>
diff --git a/testing/android/empty_apk/empty_apk.gni b/testing/android/empty_apk/empty_apk.gni new file mode 100644 index 0000000..7d6ca46f --- /dev/null +++ b/testing/android/empty_apk/empty_apk.gni
@@ -0,0 +1,22 @@ +# Copyright 2017 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. + +import("//build/config/android/rules.gni") + +template("empty_apk") { + manifest_target_name = "${target_name}__manifest" + manifest_path = "${target_gen_dir}/${target_name}/AndroidManifest.xml" + + jinja_template(manifest_target_name) { + input = "//testing/android/empty_apk/AndroidManifest.xml" + output = manifest_path + variables = [ "package=${invoker.package_name}" ] + } + + android_apk(target_name) { + forward_variables_from(invoker, "*") + android_manifest = manifest_path + android_manifest_dep = ":$manifest_target_name" + } +}
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 80ed296..389aee0a 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3434,6 +3434,30 @@ } ] } + }, + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "context_lost_tests", + "override_compile_targets": [ + "telemetry_gpu_integration_test" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Ubuntu" + } + ] + } } ] },
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter index e698354c..34a7b6eb 100644 --- a/testing/buildbot/filters/ash_unittests_mash.filter +++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -1,4 +1,14 @@ # Failures and crashes +-AppListPresenterDelegateTest.AppListViewDragHandler +-AppListPresenterDelegateTest.AppListViewDragHandlerMaximizeModeFromAllApps +-AppListPresenterDelegateTest.AppListViewDragHandlerMaximizeModeFromSearch +-AppListPresenterDelegateTest.BottomShelfAlignmentTextStateTransitions +-AppListPresenterDelegateTest.HalfToFullscreenWhenMaximizeModeIsActive +-AppListPresenterDelegateTest.MaximizeModeTextStateTransitions +-AppListPresenterDelegateTest.PeekingToFullscreenWhenMaximizeModeIsActive +-AppListPresenterDelegateTest.SideShelfAlignmentTextStateTransitions +-AppListPresenterDelegateTest.TapAndClickOutsideClosesPeekingAppList +-AppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList -NativeCursorManagerAshTest.FractionalScale -NativeCursorManagerAshTest.LockCursor -NativeCursorManagerAshTest.SetCursor
diff --git a/testing/buildbot/filters/ash_unittests_mus.filter b/testing/buildbot/filters/ash_unittests_mus.filter index 1ca5b15..df4e4ca 100644 --- a/testing/buildbot/filters/ash_unittests_mus.filter +++ b/testing/buildbot/filters/ash_unittests_mus.filter
@@ -1,3 +1,14 @@ +# TODO: fix these. http://crbug.com/726838 +-AppListPresenterDelegateTest.BottomShelfAlignmentTextStateTransitions +-AppListPresenterDelegateTest.MaximizeModeTextStateTransitions +-AppListPresenterDelegateTest.PeekingToFullscreenWhenMaximizeModeIsActive +-AppListPresenterDelegateTest.HalfToFullscreenWhenMaximizeModeIsActive +-AppListPresenterDelegateTest.AppListViewDragHandler +-AppListPresenterDelegateTest.AppListViewDragHandlerMaximizeModeFromAllApps +-AppListPresenterDelegateTest.AppListViewDragHandlerMaximizeModeFromSearch +-AppListPresenterDelegateTest.TapAndClickOutsideClosesPeekingAppList +-AppListPresenterDelegateTest.TapAndClickOutsideClosesHalfAppList + # TODO: fix these. They fail because wm::CursorManager isn't created. # http://crbug.com/734806. # The following fail as they use wm::CursorManager:
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter index 60b106ce..53c56d99 100644 --- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -85,6 +85,8 @@ -PaymentAppBrowserTest.PaymentAppInvocation -PaymentAppBrowserTest.PaymentAppOpenWindowFailed -PlzNavigateNavigationHandleImplBrowserTest.ErrorPageNetworkError +-PowerMonitorTest.TestRendererProcess +-PowerMonitorTest.TestUtilityProcess -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeNavigateBackThenForward -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeOff -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeOn
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index feab373e..9d9370e 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1551,6 +1551,24 @@ ] } ], + "NTPCaptureThumbnailOnLoadFinished": [ + { + "platforms": [ + "chromeos", + "linux", + "mac", + "win" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "CaptureThumbnailOnLoadFinished" + ] + } + ] + } + ], "NTPFaviconsFromNewServer": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service index 3544d15..d8f3e0d1 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -21,6 +21,8 @@ Bug(none) bluetooth/characteristic/readValue/gen-gatt-op-garbage-collection-ran-during-error.html [ Timeout ] Bug(none) bluetooth/characteristic/readValue/read-succeeds.html [ Timeout ] Bug(none) bluetooth/characteristic/readValue/read-updates-value.html [ Timeout ] +Bug(none) bluetooth/characteristic/writeValue/write-succeeds.html [ Timeout ] +Bug(none) bluetooth/descriptor/readValue/read-succeeds.html [ Timeout ] Bug(none) bluetooth/idl/idl-BluetoothDevice.html [ Timeout ] Bug(none) bluetooth/requestDevice [ Timeout ] Bug(none) bluetooth/server/connect/connection-succeeds.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations index 3a330c7..1688d3a0 100644 --- a/third_party/WebKit/LayoutTests/MSANExpectations +++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -39,6 +39,7 @@ crbug.com/671556 [ Linux ] virtual/mojo-loading/http/tests/security/xssAuditor/report-script-tag-replace-state.html [ Timeout Pass ] crbug.com/671556 [ Linux ] virtual/mojo-loading/http/tests/security/xssAuditor/report-script-tag.html [ Timeout Pass ] +crbug.com/736802 [ Linux ] virtual/mojo-loading/http/tests/fetch/serviceworker-proxied/thorough/cors-preflight2-other-https.html [ Crash ] crbug.com/736370 [ Linux ] external/wpt/editing/run/removeformat.html [ Timeout ] crbug.com/736554 [ Linux ] external/wpt/IndexedDB/nested-cloning-large-multiple.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 008cc444..45d72c89 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1251,6 +1251,8 @@ crbug.com/658305 css3/filters/effect-reference-zoom-hw.html [ Failure Pass ] crbug.com/658305 css3/filters/filter-effect-removed.html [ Failure Pass ] +crbug.com/736429 webaudio/internals/audiosource-premature-gc.html [ Timeout Pass ] + crbug.com/267206 [ Mac ] fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] crbug.com/267206 [ Mac ] virtual/scroll_customization/fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] @@ -2003,6 +2005,10 @@ crbug.com/736056 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href-errors-misc.html [ Pass Timeout ] crbug.com/736056 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href.html [ Pass Timeout ] +# rebaseline-cl does not handle ref-tests yet... +crbug.com/736811 fast/css/text-overflow-ellipsis-multiple-shadows.html [ Pass Failure ] +crbug.com/736811 external/wpt/css/selectors4/focus-within-004.html [ Pass Failure ] + # Failures in non-wpt tests from: # https://chromium-review.googlesource.com/c/543695/ # Possibly became flaky after a change in testharness.js.
diff --git a/third_party/WebKit/PerformanceTests/DOM/page-up-with-many-lines.html b/third_party/WebKit/PerformanceTests/Editing/page-up-with-many-lines.html similarity index 100% rename from third_party/WebKit/PerformanceTests/DOM/page-up-with-many-lines.html rename to third_party/WebKit/PerformanceTests/Editing/page-up-with-many-lines.html
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.cpp b/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.cpp index 442f1d9..60cb109 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ToV8ForCore.cpp
@@ -8,12 +8,16 @@ #include "core/events/EventTarget.h" #include "core/frame/DOMWindow.h" #include "core/frame/Frame.h" +#include "platform/bindings/RuntimeCallStats.h" namespace blink { v8::Local<v8::Value> ToV8(DOMWindow* window, v8::Local<v8::Object> creation_context, v8::Isolate* isolate) { + RUNTIME_CALL_TIMER_SCOPE(isolate, + RuntimeCallStats::CounterId::kToV8DOMWindow); + // Notice that we explicitly ignore creationContext because the DOMWindow // has its own creationContext.
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.cpp b/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.cpp index 649da0e..04a9fd7 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.cpp
@@ -56,6 +56,7 @@ #include "core/workers/WorkerGlobalScope.h" #include "core/workers/WorkletGlobalScope.h" #include "core/xml/XPathNSResolver.h" +#include "platform/bindings/RuntimeCallStats.h" #include "platform/bindings/V8BindingMacros.h" #include "platform/bindings/V8ObjectConstructor.h" #include "platform/instrumentation/tracing/TracedValue.h" @@ -716,6 +717,8 @@ ExecutionContext* ToExecutionContext(v8::Local<v8::Context> context) { if (context.IsEmpty()) return 0; + RUNTIME_CALL_TIMER_SCOPE(context->GetIsolate(), + RuntimeCallStats::CounterId::kToExecutionContext); v8::Local<v8::Object> global = context->Global(); v8::Local<v8::Object> window_wrapper = V8Window::findInstanceInPrototypeChain(global, context->GetIsolate());
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl index 391c465..7edf163 100644 --- a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl +++ b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
@@ -3,9 +3,8 @@ {##############################################################################} {% macro runtime_timer_scope(counter) %} {% if counter -%} -RuntimeCallStats* runtime_call_stats = RuntimeCallStats::From(info.GetIsolate()); -RuntimeCallTimerScope timer_scope(runtime_call_stats, - RuntimeCallStats::CounterId::{{counter}}); +RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), + RuntimeCallStats::CounterId::{{counter}}); {%- endif %} {% endmacro %}
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp index 35c98a3c..0c81ec1 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -3776,9 +3776,8 @@ } static void RuntimeCallStatsCounterAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { - RuntimeCallStats* runtime_call_stats = RuntimeCallStats::From(info.GetIsolate()); - RuntimeCallTimerScope timer_scope(runtime_call_stats, - RuntimeCallStats::CounterId::kRuntimeCallStatsCounterAttribute_Getter); + RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), + RuntimeCallStats::CounterId::kRuntimeCallStatsCounterAttribute_Getter); v8::Local<v8::Object> holder = info.Holder(); @@ -3788,9 +3787,8 @@ } static void RuntimeCallStatsCounterAttributeAttributeSetter(v8::Local<v8::Value> v8Value, const v8::FunctionCallbackInfo<v8::Value>& info) { - RuntimeCallStats* runtime_call_stats = RuntimeCallStats::From(info.GetIsolate()); - RuntimeCallTimerScope timer_scope(runtime_call_stats, - RuntimeCallStats::CounterId::kRuntimeCallStatsCounterAttribute_Setter); + RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), + RuntimeCallStats::CounterId::kRuntimeCallStatsCounterAttribute_Setter); v8::Isolate* isolate = info.GetIsolate(); ALLOW_UNUSED_LOCAL(isolate); @@ -3810,9 +3808,8 @@ } static void RuntimeCallStatsCounterReadOnlyAttributeAttributeGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { - RuntimeCallStats* runtime_call_stats = RuntimeCallStats::From(info.GetIsolate()); - RuntimeCallTimerScope timer_scope(runtime_call_stats, - RuntimeCallStats::CounterId::kRuntimeCallStatsCounterReadOnlyAttribute_Getter); + RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), + RuntimeCallStats::CounterId::kRuntimeCallStatsCounterReadOnlyAttribute_Getter); v8::Local<v8::Object> holder = info.Holder(); @@ -9251,9 +9248,8 @@ } static void RuntimeCallStatsCounterMethodMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { - RuntimeCallStats* runtime_call_stats = RuntimeCallStats::From(info.GetIsolate()); - RuntimeCallTimerScope timer_scope(runtime_call_stats, - RuntimeCallStats::CounterId::kRuntimeCallStatsCounterMethod); + RUNTIME_CALL_TIMER_SCOPE(info.GetIsolate(), + RuntimeCallStats::CounterId::kRuntimeCallStatsCounterMethod); TestObject* impl = V8TestObject::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 5f661d84..eae9de11 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2119,9 +2119,8 @@ void Document::UpdateStyle() { DCHECK(!View()->ShouldThrottleRendering()); TRACE_EVENT_BEGIN0("blink,blink_style", "Document::updateStyle"); - RuntimeCallTimerScope scope( - RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()), - RuntimeCallStats::CounterId::kUpdateStyle); + RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(), + RuntimeCallStats::CounterId::kUpdateStyle); double start_time = MonotonicallyIncreasingTime(); unsigned initial_element_count = GetStyleEngine().StyleForElementCount(); @@ -3251,8 +3250,6 @@ return; if (load_event_progress_ <= kUnloadEventInProgress) { - if (GetPage()) - GetPage()->WillUnloadDocument(*this); Element* current_focused_element = FocusedElement(); if (isHTMLInputElement(current_focused_element)) toHTMLInputElement(*current_focused_element).EndEditing();
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp index 6ebc468..e36b1953 100644 --- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -294,11 +294,9 @@ MockValidationMessageClient() { Reset(); } void Reset() { show_validation_message_was_called = false; - will_unload_document_was_called = false; document_detached_was_called = false; } bool show_validation_message_was_called; - bool will_unload_document_was_called; bool document_detached_was_called; // ValidationMessageClient functions. @@ -313,9 +311,6 @@ bool IsValidationMessageVisible(const Element& anchor) override { return true; } - void WillUnloadDocument(const Document&) override { - will_unload_document_was_called = true; - } void DocumentDetached(const Document&) override { document_detached_was_called = true; } @@ -826,7 +821,6 @@ // prepareForCommit() unloads the document, and shutdown. GetDocument().GetFrame()->PrepareForCommit(); - EXPECT_TRUE(mock_client->will_unload_document_was_called); EXPECT_TRUE(mock_client->document_detached_was_called); // Unload handler tried to show a validation message, but it should fail. EXPECT_FALSE(mock_client->show_validation_message_was_called);
diff --git a/third_party/WebKit/Source/core/dom/Element.idl b/third_party/WebKit/Source/core/dom/Element.idl index 227b074..fa0e969 100644 --- a/third_party/WebKit/Source/core/dom/Element.idl +++ b/third_party/WebKit/Source/core/dom/Element.idl
@@ -80,7 +80,7 @@ // DOM Parsing and Serialization // https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface - [TreatNullAs=NullString, CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute DOMString innerHTML; + [TreatNullAs=NullString, CEReactions, CustomElementCallbacks, RaisesException=Setter, RuntimeCallStatsCounter=ElementInnerHTML] attribute DOMString innerHTML; [TreatNullAs=NullString, CEReactions, CustomElementCallbacks, RaisesException=Setter] attribute DOMString outerHTML; [CEReactions, CustomElementCallbacks, RaisesException] void insertAdjacentHTML(DOMString position, DOMString text);
diff --git a/third_party/WebKit/Source/core/events/EventTarget.idl b/third_party/WebKit/Source/core/events/EventTarget.idl index 1619a0e..9faf117 100644 --- a/third_party/WebKit/Source/core/events/EventTarget.idl +++ b/third_party/WebKit/Source/core/events/EventTarget.idl
@@ -27,5 +27,5 @@ ] interface EventTarget { [Custom=(CallPrologue,CallEpilogue)] void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options); [Custom=(CallPrologue,CallEpilogue)] void removeEventListener(DOMString type, EventListener? listener, optional (EventListenerOptions or boolean) options); - [ImplementedAs=dispatchEventForBindings, RaisesException] boolean dispatchEvent(Event event); + [ImplementedAs=dispatchEventForBindings, RaisesException, RuntimeCallStatsCounter=EventTargetDispatchEvent] boolean dispatchEvent(Event event); };
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp index 7f2a73a6..c67e00c 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -1140,9 +1140,8 @@ TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout"); - RuntimeCallTimerScope scope( - RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()), - RuntimeCallStats::CounterId::kUpdateLayout); + RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(), + RuntimeCallStats::CounterId::kUpdateLayout); if (auto_size_info_) auto_size_info_->AutoSizeIfNeeded(); @@ -3389,9 +3388,9 @@ SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Blink.Compositing.UpdateTime"); - paint_artifact_compositor_->Update( - paint_controller_->GetPaintArtifact(), - is_storing_composited_layer_debug_info_, composited_element_ids); + paint_artifact_compositor_->Update(paint_controller_->GetPaintArtifact(), + is_storing_composited_layer_debug_info_, + composited_element_ids); } std::unique_ptr<JSONObject> LocalFrameView::CompositedLayersAsJSON(
diff --git a/third_party/WebKit/Source/core/frame/WindowTimers.idl b/third_party/WebKit/Source/core/frame/WindowTimers.idl index d433fbb..9f8fc07 100644 --- a/third_party/WebKit/Source/core/frame/WindowTimers.idl +++ b/third_party/WebKit/Source/core/frame/WindowTimers.idl
@@ -36,7 +36,7 @@ // FIXME: would be clearer as a union type, like: // typedef (Function or DOMString) Handler // Needs spec update and better union support: http://crbug.com/240176 - [CallWith=ScriptState] long setTimeout(Function handler, optional long timeout = 0, any... arguments); + [CallWith=ScriptState, RuntimeCallStatsCounter=WindowSetTimeout] long setTimeout(Function handler, optional long timeout = 0, any... arguments); [CallWith=ScriptState] long setTimeout(DOMString handler, optional long timeout = 0, any... arguments); void clearTimeout(optional long handle = 0); [CallWith=ScriptState] long setInterval(Function handler, optional long timeout = 0, any... arguments);
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.idl b/third_party/WebKit/Source/core/html/HTMLElement.idl index ad8390f7..7338183 100644 --- a/third_party/WebKit/Source/core/html/HTMLElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLElement.idl
@@ -30,7 +30,7 @@ // user interaction [CEReactions, Reflect] attribute boolean hidden; - void click(); + [RuntimeCallStatsCounter=HTMLElementClick] void click(); [CEReactions, CustomElementCallbacks] attribute long tabIndex; [CEReactions, RuntimeEnabled=InertAttribute, Reflect] attribute boolean inert; void focus();
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp index 470da5e..3a3ffcf6 100644 --- a/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp +++ b/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp
@@ -41,7 +41,6 @@ return anchor_ == &anchor; } - void WillUnloadDocument(const Document&) override {} void DocumentDetached(const Document&) override {} void WillBeDestroyed() override {} DEFINE_INLINE_VIRTUAL_TRACE() {
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index ca12153..db3aa784 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -741,19 +741,28 @@ } float FrameFetchContext::ClientHintsDeviceRAM(int64_t physical_memory_mb) { - // TODO(fmeawad): The calculations in this method are still evolving as the - // spec gets updated: https://github.com/WICG/device-ram. The reported - // device-ram is rounded down to next power of 2 in GB. Ex. 3072MB will return - // 2, and 768MB will return 0.5. + // The calculations in this method are described in the specifcations: + // https://github.com/WICG/device-ram. DCHECK_GT(physical_memory_mb, 0); + int lower_bound = physical_memory_mb; int power = 0; - // Extract the MSB location. - while (physical_memory_mb > 1) { - physical_memory_mb >>= 1; + + // Extract the most significant 2-bits and their location. + while (lower_bound >= 4) { + lower_bound >>= 1; power++; } - // Restore to the power of 2, and convert to GB. - return static_cast<float>(1 << power) / 1024.0; + // The lower_bound value is either 0b10 or 0b11. + DCHECK(lower_bound & 2); + + int64_t upper_bound = lower_bound + 1; + lower_bound = lower_bound << power; + upper_bound = upper_bound << power; + + // Find the closest bound, and convert it to GB. + if (physical_memory_mb - lower_bound <= upper_bound - physical_memory_mb) + return static_cast<float>(lower_bound) / 1024.0; + return static_cast<float>(upper_bound) / 1024.0; } void FrameFetchContext::AddClientHintsIfNecessary(
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp index 7cb7363..eaec6655 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -548,9 +548,9 @@ MemoryCoordinator::SetPhysicalMemoryMBForTesting(2048); ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "2"); MemoryCoordinator::SetPhysicalMemoryMBForTesting(64385); - ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "32"); + ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "64"); MemoryCoordinator::SetPhysicalMemoryMBForTesting(768); - ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "0.5"); + ExpectHeader("http://www.example.com/1.gif", "device-ram", true, "0.75"); ExpectHeader("http://www.example.com/1.gif", "DPR", false, ""); ExpectHeader("http://www.example.com/1.gif", "Width", false, ""); ExpectHeader("http://www.example.com/1.gif", "Viewport-Width", false, ""); @@ -617,20 +617,21 @@ TEST_F(FrameFetchContextHintsTest, ClientHintsDeviceRAM) { EXPECT_EQ(0.125, FrameFetchContext::ClientHintsDeviceRAM(128)); // 128MB EXPECT_EQ(0.25, FrameFetchContext::ClientHintsDeviceRAM(256)); // 256MB - EXPECT_EQ(0.25, FrameFetchContext::ClientHintsDeviceRAM(510)); // <512MB + EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(510)); // <512MB EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(512)); // 512MB EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(640)); // 512+128MB - EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(768)); // 512+256MB - EXPECT_EQ(0.5, FrameFetchContext::ClientHintsDeviceRAM(1000)); // <1GB + EXPECT_EQ(0.75, FrameFetchContext::ClientHintsDeviceRAM(768)); // 512+256MB + EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(1000)); // <1GB EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(1024)); // 1GB - EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(1536)); // 1.5GB - EXPECT_EQ(1, FrameFetchContext::ClientHintsDeviceRAM(2000)); // <2GB + EXPECT_EQ(1.5, FrameFetchContext::ClientHintsDeviceRAM(1536)); // 1.5GB + EXPECT_EQ(2, FrameFetchContext::ClientHintsDeviceRAM(2000)); // <2GB EXPECT_EQ(2, FrameFetchContext::ClientHintsDeviceRAM(2048)); // 2GB + EXPECT_EQ(3, FrameFetchContext::ClientHintsDeviceRAM(3000)); // <3GB EXPECT_EQ(4, FrameFetchContext::ClientHintsDeviceRAM(5120)); // 5GB EXPECT_EQ(8, FrameFetchContext::ClientHintsDeviceRAM(8192)); // 8GB EXPECT_EQ(16, FrameFetchContext::ClientHintsDeviceRAM(16384)); // 16GB EXPECT_EQ(32, FrameFetchContext::ClientHintsDeviceRAM(32768)); // 32GB - EXPECT_EQ(32, FrameFetchContext::ClientHintsDeviceRAM(64385)); // <64GB + EXPECT_EQ(64, FrameFetchContext::ClientHintsDeviceRAM(64385)); // <64GB } TEST_F(FrameFetchContextTest, MainResourceCachePolicy) {
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp index 4a08302..825901d2 100644 --- a/third_party/WebKit/Source/core/page/Page.cpp +++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -253,11 +253,6 @@ main_frame_ = main_frame; } -void Page::WillUnloadDocument(const Document& document) { - if (validation_message_client_) - validation_message_client_->WillUnloadDocument(document); -} - void Page::DocumentDetached(Document* document) { pointer_lock_controller_->DocumentDetached(document); context_menu_controller_->DocumentDetached(document);
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h index ccaea49b..6af63ad9 100644 --- a/third_party/WebKit/Source/core/page/Page.h +++ b/third_party/WebKit/Source/core/page/Page.h
@@ -152,7 +152,6 @@ return ToLocalFrame(main_frame_); } - void WillUnloadDocument(const Document&); void DocumentDetached(Document*); bool OpenedByDOM() const;
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClient.h b/third_party/WebKit/Source/core/page/ValidationMessageClient.h index 396f4b5..fe2285f 100644 --- a/third_party/WebKit/Source/core/page/ValidationMessageClient.h +++ b/third_party/WebKit/Source/core/page/ValidationMessageClient.h
@@ -56,7 +56,6 @@ // is visible. virtual bool IsValidationMessageVisible(const Element& anchor) = 0; - virtual void WillUnloadDocument(const Document&) = 0; virtual void DocumentDetached(const Document&) = 0; virtual void WillBeDestroyed() = 0;
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp index f2e3c3b..7eb5f345 100644 --- a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp +++ b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp
@@ -115,16 +115,11 @@ return current_anchor_ == &anchor; } -void ValidationMessageClientImpl::WillUnloadDocument(const Document& document) { +void ValidationMessageClientImpl::DocumentDetached(const Document& document) { if (current_anchor_ && current_anchor_->GetDocument() == document) HideValidationMessage(*current_anchor_); } -void ValidationMessageClientImpl::DocumentDetached(const Document& document) { - DCHECK(!current_anchor_ || current_anchor_->GetDocument() != document) - << "willUnloadDocument() should be called beforehand."; -} - void ValidationMessageClientImpl::CheckAnchorStatus(TimerBase*) { DCHECK(current_anchor_); if (MonotonicallyIncreasingTime() >= finish_time_ || !CurrentView()) {
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h index 0816472..e261d96 100644 --- a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h +++ b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h
@@ -63,7 +63,6 @@ TextDirection sub_message_dir) override; void HideValidationMessage(const Element& anchor) override; bool IsValidationMessageVisible(const Element& anchor) override; - void WillUnloadDocument(const Document&) override; void DocumentDetached(const Document&) override; void WillBeDestroyed() override;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp index 4f7f591..f75ee2e 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -288,8 +288,8 @@ void PaintLayer::UpdateLayerPositionsAfterLayout() { TRACE_EVENT0("blink,benchmark", "PaintLayer::updateLayerPositionsAfterLayout"); - RuntimeCallTimerScope runtime_timer_scope( - RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()), + RUNTIME_CALL_TIMER_SCOPE( + V8PerIsolateData::MainThreadIsolate(), RuntimeCallStats::CounterId::kUpdateLayerPositionsAfterLayout); ClearClipRects();
diff --git a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp index 64c5e0b6a..7a57419 100644 --- a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp +++ b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp
@@ -113,6 +113,9 @@ RawResource::FetchSynchronously(params, g_global_resource_fetcher); if (!resource || !g_global_processor) return nullptr; + RefPtr<const SharedBuffer> data = resource->ResourceBuffer(); + if (!data) + return nullptr; FrameConsole* console = nullptr; LocalFrame* frame = @@ -122,13 +125,25 @@ xmlSetStructuredErrorFunc(console, XSLTProcessor::ParseErrorFunc); xmlSetGenericErrorFunc(console, XSLTProcessor::GenericErrorFunc); + xmlDocPtr doc = nullptr; + // We don't specify an encoding here. Neither Gecko nor WinIE respects // the encoding specified in the HTTP headers. - RefPtr<const SharedBuffer> data = resource->ResourceBuffer(); - xmlDocPtr doc = data ? xmlReadMemory(data->Data(), data->size(), - (const char*)uri, 0, options) - : nullptr; + xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt( + nullptr, nullptr, nullptr, 0, reinterpret_cast<const char*>(uri)); + if (ctx && !xmlCtxtUseOptions(ctx, options)) { + data->ForEachSegment([&data, &ctx](const char* segment, + size_t segment_size, + size_t segment_offset) -> bool { + bool final_chunk = segment_offset + segment_size == data->size(); + return !xmlParseChunk(ctx, segment, segment_size, final_chunk); + }); + if (ctx->wellFormed) + doc = ctx->myDoc; + } + + xmlFreeParserCtxt(ctx); xmlSetStructuredErrorFunc(0, 0); xmlSetGenericErrorFunc(0, 0);
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp index e15549c..eafe405 100644 --- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp +++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -182,8 +182,14 @@ // already held, simply delay rendering until the next quantum. CrossThreadPersistentRegion::LockScope gc_lock( ProcessHeap::GetCrossThreadPersistentRegion(), true); - if (!gc_lock.HasLock()) + if (!gc_lock.HasLock()) { + // To ensure that the rendering step eventually happens, repost. + render_thread_->GetWebTaskRunner()->PostTask( + BLINK_FROM_HERE, + Bind(&OfflineAudioDestinationHandler::DoOfflineRendering, + WrapPassRefPtr(this))); return; + } number_of_channels = render_target_->numberOfChannels(); destinations.ReserveInitialCapacity(number_of_channels);
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 index 10c8769..fecc6263 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -112,6 +112,9 @@ status: "stable", }, { + name: "BlinkRuntimeCallStats", + }, + { name: "BlockCredentialedSubresources", status: "stable", },
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp index 513797f..5f35638 100644 --- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp +++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
@@ -55,16 +55,6 @@ return V8PerIsolateData::From(isolate)->GetRuntimeCallStats(); } -void RuntimeCallStats::Enter(RuntimeCallTimer* timer, CounterId id) { - timer->Start(GetCounter(id), current_timer_); - current_timer_ = timer; -} - -void RuntimeCallStats::Leave(RuntimeCallTimer* timer) { - DCHECK_EQ(timer, current_timer_); - current_timer_ = timer->Stop(); -} - void RuntimeCallStats::Reset() { for (int i = 0; i < number_of_counters_; i++) { counters_[i].Reset(); @@ -88,7 +78,7 @@ // static void RuntimeCallStats::SetRuntimeCallStatsForTesting() { - DEFINE_STATIC_LOCAL(RuntimeCallStatsForTesting, s_rcs_for_testing, ()); + DEFINE_STATIC_LOCAL(RuntimeCallStats, s_rcs_for_testing, ()); g_runtime_call_stats_for_testing = static_cast<RuntimeCallStats*>(&s_rcs_for_testing); }
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h index e596b9a..07eaeff 100644 --- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h +++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
@@ -9,7 +9,9 @@ #define RuntimeCallStats_h #include "platform/PlatformExport.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/wtf/Allocator.h" +#include "platform/wtf/Optional.h" #include "platform/wtf/Time.h" #include "platform/wtf/text/WTFString.h" #include "v8/include/v8.h" @@ -48,7 +50,7 @@ // Used to track elapsed time for a counter. // NOTE: Do not use this class directly to track execution times, instead use it -// with RuntimeCallStats::Enter/Leave. +// with the macros below. class PLATFORM_EXPORT RuntimeCallTimer { public: RuntimeCallTimer() = default; @@ -88,6 +90,51 @@ TimeDelta elapsed_time_; }; +// Macros that take RuntimeCallStats as a parameter; used only in +// RuntimeCallStatsTest. +#define RUNTIME_CALL_STATS_ENTER_WITH_RCS(runtime_call_stats, timer, \ + counterId) \ + if (UNLIKELY(RuntimeEnabledFeatures::BlinkRuntimeCallStatsEnabled())) { \ + (runtime_call_stats)->Enter(timer, counterId); \ + } + +#define RUNTIME_CALL_STATS_LEAVE_WITH_RCS(runtime_call_stats, timer) \ + if (UNLIKELY(RuntimeEnabledFeatures::BlinkRuntimeCallStatsEnabled())) { \ + (runtime_call_stats)->Leave(timer); \ + } + +#define RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(runtime_call_stats, counterId) \ + Optional<RuntimeCallTimerScope> rcs_scope; \ + if (UNLIKELY(RuntimeEnabledFeatures::BlinkRuntimeCallStatsEnabled())) { \ + rcs_scope.emplace(runtime_call_stats, counterId); \ + } + +#define RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS( \ + optional_scope_name, runtime_call_stats, counterId) \ + if (UNLIKELY(RuntimeEnabledFeatures::BlinkRuntimeCallStatsEnabled())) { \ + optional_scope_name.emplace(runtime_call_stats, counterId); \ + } + +// Use the macros below instead of directly using RuntimeCallStats::Enter, +// RuntimeCallStats::Leave and RuntimeCallTimerScope. They force an early +// exit if Runtime Call Stats is disabled. +#define RUNTIME_CALL_STATS_ENTER(isolate, timer, counterId) \ + RUNTIME_CALL_STATS_ENTER_WITH_RCS(RuntimeCallStats::From(isolate), timer, \ + counterId) + +#define RUNTIME_CALL_STATS_LEAVE(isolate, timer) \ + RUNTIME_CALL_STATS_LEAVE_WITH_RCS(RuntimeCallStats::From(isolate), timer) + +#define RUNTIME_CALL_TIMER_SCOPE(isolate, counterId) \ + RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(RuntimeCallStats::From(isolate), counterId) + +#define RUNTIME_CALL_TIMER_SCOPE_IF_ISOLATE_EXISTS(isolate, counterId) \ + Optional<RuntimeCallTimerScope> rcs_scope; \ + if (isolate) { \ + RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS( \ + rcs_scope, RuntimeCallStats::From(isolate), counterId) \ + } + // Maintains a stack of timers and provides functions to manage recording scopes // by pausing and resuming timers in the chain when entering and leaving a // scope. @@ -122,13 +169,23 @@ // Counters #define FOR_EACH_COUNTER(V) \ - V(UpdateStyle) \ - V(UpdateLayout) \ + V(AssociateObjectWithWrapper) \ V(CollectGarbage) \ - V(PerformIdleLazySweep) \ - V(UpdateLayerPositionsAfterLayout) \ + V(CreateWrapper) \ V(PaintContents) \ + V(PerformIdleLazySweep) \ V(ProcessStyleSheet) \ + V(ToExecutionContext) \ + V(ToV8DOMWindow) \ + V(UpdateLayerPositionsAfterLayout) \ + V(UpdateLayout) \ + V(UpdateStyle) \ + V(SetReturnValueFromStringSlow) \ + V(V8ExternalStringSlow) \ + BINDINGS_METHOD(V, EventTargetDispatchEvent) \ + BINDINGS_METHOD(V, HTMLElementClick) \ + BINDINGS_METHOD(V, WindowSetTimeout) \ + BINDINGS_ATTRIBUTE(V, ElementInnerHTML) \ V(TestCounter1) \ V(TestCounter2) \ BINDINGS_METHOD(V, BindingsMethodTestCounter) \ @@ -144,12 +201,20 @@ // Enters a new recording scope by pausing the currently running timer that // was started by the current instance, and starting <timer>. - virtual void Enter(RuntimeCallTimer*, CounterId); + // NOTE: Do not use this function directly, use RUNTIME_CALL_STATS_ENTER. + void Enter(RuntimeCallTimer* timer, CounterId id) { + timer->Start(GetCounter(id), current_timer_); + current_timer_ = timer; + } // Exits the current recording scope, by stopping <timer> (and updating the // counter associated with <timer>) and resuming the timer that was paused // before entering the current scope. - virtual void Leave(RuntimeCallTimer*); + // NOTE: Do not use this function directly, use RUNTIME_CALL_STATS_LEAVE. + void Leave(RuntimeCallTimer* timer) { + DCHECK_EQ(timer, current_timer_); + current_timer_ = timer->Stop(); + } // Reset all the counters. void Reset(); @@ -160,7 +225,6 @@ String ToString() const; - // Use these two functions to stub out RuntimeCallStats in tests. static void SetRuntimeCallStatsForTesting(); static void ClearRuntimeCallStatsForTesting(); @@ -173,6 +237,7 @@ // A utility class that creates a RuntimeCallTimer and uses it with // RuntimeCallStats to measure execution time of a C++ scope. +// Do not use this class directly, use RUNTIME_CALL_TIMER_SCOPE instead. class PLATFORM_EXPORT RuntimeCallTimerScope { public: RuntimeCallTimerScope(RuntimeCallStats* stats, @@ -187,12 +252,6 @@ RuntimeCallTimer timer_; }; -// Used to stub out RuntimeCallStats for testing. -class RuntimeCallStatsForTesting : public RuntimeCallStats { - void Enter(RuntimeCallTimer*, RuntimeCallStats::CounterId) override {} - void Leave(RuntimeCallTimer*) override {} -}; - } // namespace blink #endif // RuntimeCallStats_h
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp index 9ccece9..b5833229 100644 --- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp +++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStatsTest.cpp
@@ -4,6 +4,7 @@ #include "platform/bindings/RuntimeCallStats.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/wtf/CurrentTime.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,10 +37,12 @@ void TearDown() override { SetTimeFunctionsForTesting(original_time_function_); + features_backup_.Restore(); } private: TimeFunction original_time_function_; + RuntimeEnabledFeatures::Backup features_backup_; }; TEST_F(RuntimeCallStatsTest, InitialCountShouldBeZero) { @@ -233,4 +236,92 @@ EXPECT_EQ(0ul, counter2->GetCount()); } +TEST_F(RuntimeCallStatsTest, TestEnterAndLeaveMacrosWithCallStatsDisabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(false); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + RuntimeCallTimer timer; + + RUNTIME_CALL_STATS_ENTER_WITH_RCS(&stats, &timer, test_counter_1_id); + AdvanceClock(25); + RUNTIME_CALL_STATS_LEAVE_WITH_RCS(&stats, &timer); + + EXPECT_EQ(0ul, counter->GetCount()); + EXPECT_EQ(0, counter->GetTime().InMilliseconds()); +} + +TEST_F(RuntimeCallStatsTest, TestEnterAndLeaveMacrosWithCallStatsEnabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(true); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + RuntimeCallTimer timer; + + RUNTIME_CALL_STATS_ENTER_WITH_RCS(&stats, &timer, test_counter_1_id); + AdvanceClock(25); + RUNTIME_CALL_STATS_LEAVE_WITH_RCS(&stats, &timer); + + EXPECT_EQ(1ul, counter->GetCount()); + EXPECT_EQ(25, counter->GetTime().InMilliseconds()); +} + +TEST_F(RuntimeCallStatsTest, TestScopeMacroWithCallStatsDisabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(false); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + + { + RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(&stats, test_counter_1_id); + AdvanceClock(25); + } + + EXPECT_EQ(0ul, counter->GetCount()); + EXPECT_EQ(0, counter->GetTime().InMilliseconds()); +} + +TEST_F(RuntimeCallStatsTest, TestScopeMacroWithCallStatsEnabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(true); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + + { + RUNTIME_CALL_TIMER_SCOPE_WITH_RCS(&stats, test_counter_1_id); + AdvanceClock(25); + } + + EXPECT_EQ(1ul, counter->GetCount()); + EXPECT_EQ(25, counter->GetTime().InMilliseconds()); +} + +TEST_F(RuntimeCallStatsTest, TestScopeWithOptionalMacroWithCallStatsDisabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(false); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + + { + Optional<RuntimeCallTimerScope> scope; + RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS(scope, &stats, + test_counter_1_id); + AdvanceClock(25); + } + + EXPECT_EQ(0ul, counter->GetCount()); + EXPECT_EQ(0, counter->GetTime().InMilliseconds()); +} + +TEST_F(RuntimeCallStatsTest, TestScopeWithOptionalMacroWithCallStatsEnabled) { + RuntimeEnabledFeatures::SetBlinkRuntimeCallStatsEnabled(true); + RuntimeCallStats stats; + RuntimeCallCounter* counter = stats.GetCounter(test_counter_1_id); + + { + Optional<RuntimeCallTimerScope> scope; + RUNTIME_CALL_TIMER_SCOPE_WITH_OPTIONAL_RCS(scope, &stats, + test_counter_1_id); + AdvanceClock(25); + } + + EXPECT_EQ(1ul, counter->GetCount()); + EXPECT_EQ(25, counter->GetTime().InMilliseconds()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.cpp b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.cpp index ac6da70..4febb73 100644 --- a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.cpp +++ b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.cpp
@@ -41,6 +41,9 @@ v8::Isolate* isolate, v8::Local<v8::Object> creation_context, const WrapperTypeInfo* type) { + RUNTIME_CALL_TIMER_SCOPE(isolate, + RuntimeCallStats::CounterId::kCreateWrapper); + // TODO(adithyas): We should abort wrapper creation if the context access // check fails and throws an exception. V8WrapperInstantiationScope scope(creation_context, isolate, type);
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h index b91592b..89a2d266 100644 --- a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h +++ b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
@@ -33,6 +33,7 @@ #include "platform/PlatformExport.h" #include "platform/bindings/DOMDataStore.h" +#include "platform/bindings/RuntimeCallStats.h" #include "platform/bindings/ScriptWrappable.h" #include "platform/bindings/V8Binding.h" #include "platform/bindings/WrapperCreationSecurityCheck.h" @@ -114,6 +115,8 @@ ScriptWrappable* impl, const WrapperTypeInfo* wrapper_type_info, v8::Local<v8::Object> wrapper) { + RUNTIME_CALL_TIMER_SCOPE( + isolate, RuntimeCallStats::CounterId::kAssociateObjectWithWrapper); if (DOMDataStore::SetWrapper(isolate, impl, wrapper_type_info, wrapper)) { WrapperTypeInfo::WrapperCreated(); SetNativeInfo(isolate, wrapper, wrapper_type_info, impl);
diff --git a/third_party/WebKit/Source/platform/bindings/V8ValueCache.cpp b/third_party/WebKit/Source/platform/bindings/V8ValueCache.cpp index ba755bb2..8878875 100644 --- a/third_party/WebKit/Source/platform/bindings/V8ValueCache.cpp +++ b/third_party/WebKit/Source/platform/bindings/V8ValueCache.cpp
@@ -26,6 +26,7 @@ #include "platform/bindings/V8ValueCache.h" #include <utility> +#include "platform/bindings/RuntimeCallStats.h" #include "platform/bindings/V8Binding.h" #include "platform/wtf/text/StringHash.h" @@ -93,6 +94,8 @@ v8::Local<v8::String> StringCache::V8ExternalStringSlow( v8::Isolate* isolate, StringImpl* string_impl) { + RUNTIME_CALL_TIMER_SCOPE(isolate, + RuntimeCallStats::CounterId::kV8ExternalStringSlow); if (!string_impl->length()) return v8::String::Empty(isolate); @@ -110,6 +113,9 @@ void StringCache::SetReturnValueFromStringSlow( v8::ReturnValue<v8::Value> return_value, StringImpl* string_impl) { + RUNTIME_CALL_TIMER_SCOPE( + return_value.GetIsolate(), + RuntimeCallStats::CounterId::kSetReturnValueFromStringSlow); if (!string_impl->length()) { return_value.SetEmptyString(); return;
diff --git a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp index 684ec562..3f9aa70 100644 --- a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp +++ b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
@@ -57,9 +57,8 @@ WebDisplayItemList* web_display_item_list, WebContentLayerClient::PaintingControlSetting painting_control) { TRACE_EVENT0("blink,benchmark", "ContentLayerDelegate::paintContents"); - RuntimeCallTimerScope runtime_timer_scope( - RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()), - RuntimeCallStats::CounterId::kPaintContents); + RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(), + RuntimeCallStats::CounterId::kPaintContents); PaintController& paint_controller = graphics_layer_->GetPaintController(); paint_controller.SetDisplayItemConstructionIsDisabled(
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp index a8716456..9d2fd134 100644 --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -618,11 +618,8 @@ if (SweepForbidden()) return; - Optional<RuntimeCallTimerScope> timer_scope; - if (v8::Isolate* isolate = GetIsolate()) { - timer_scope.emplace(RuntimeCallStats::From(isolate), - RuntimeCallStats::CounterId::kPerformIdleLazySweep); - } + RUNTIME_CALL_TIMER_SCOPE_IF_ISOLATE_EXISTS( + GetIsolate(), RuntimeCallStats::CounterId::kPerformIdleLazySweep); TRACE_EVENT1("blink_gc,devtools.timeline", "ThreadState::performIdleLazySweep", "idleDeltaInSeconds", @@ -1444,11 +1441,8 @@ CHECK(!IsGCForbidden()); CompleteSweep(); - Optional<RuntimeCallTimerScope> timer_scope; - if (v8::Isolate* isolate = GetIsolate()) { - timer_scope.emplace(RuntimeCallStats::From(isolate), - RuntimeCallStats::CounterId::kCollectGarbage); - } + RUNTIME_CALL_TIMER_SCOPE_IF_ISOLATE_EXISTS( + GetIsolate(), RuntimeCallStats::CounterId::kCollectGarbage); GCForbiddenScope gc_forbidden_scope(this);
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 55bb137..6c28e04 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -127,7 +127,6 @@ return 'smoothness.tough_webgl_cases' -@benchmark.Disabled('win') # http://crbug.com/692663 @benchmark.Disabled('android-webview') # http://crbug.com/653933 @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org']) class SmoothnessMaps(perf_benchmark.PerfBenchmark):
diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py index 3d88127..2e22a03 100644 --- a/tools/perf/measurements/smoothness_unittest.py +++ b/tools/perf/measurements/smoothness_unittest.py
@@ -55,7 +55,7 @@ class CustomResultsWrapperUnitTest(unittest.TestCase): def testOnlyOneInteractionRecordPerPage(self): - test_page = page.Page('http://dummy', None) + test_page = page.Page('http://dummy', None, name='http://dummy') # pylint: disable=protected-access results_wrapper = smoothness._CustomResultsWrapper() @@ -82,7 +82,7 @@ self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF def testSyntheticDelayConfiguration(self): - test_page = page.Page('http://dummy', None) + test_page = page.Page('http://dummy', None, name='http://dummy') test_page.synthetic_delays = { 'cc.BeginMainFrame': {'target_duration': 0.012}, 'cc.DrawAndSwap': {'target_duration': 0.012, 'mode': 'alternating'},
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java index c82004f..508eebc8 100644 --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -282,6 +282,7 @@ */ @VisibleForTesting public static List<String> convertToImageMimeTypes(List<String> fileTypes) { + if (fileTypes.size() == 0) return null; List<String> mimeTypes = new ArrayList<>(); for (String type : fileTypes) { String mimeType = ensureMimeType(type);
diff --git a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java index fac9e83..10c6623 100644 --- a/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java +++ b/ui/android/junit/src/org/chromium/ui/base/SelectFileDialogTest.java
@@ -106,6 +106,7 @@ // Unknown extension, expect default response: assertEquals("application/octet-stream", SelectFileDialog.ensureMimeType(".flv")); + assertEquals(null, SelectFileDialog.convertToImageMimeTypes(new ArrayList<>())); assertEquals(null, SelectFileDialog.convertToImageMimeTypes(Arrays.asList(""))); assertEquals(null, SelectFileDialog.convertToImageMimeTypes(Arrays.asList("foo/bar"))); assertEquals(Arrays.asList("image/jpeg"),
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn index 8dd18cd..27b8fb68 100644 --- a/ui/app_list/BUILD.gn +++ b/ui/app_list/BUILD.gn
@@ -4,18 +4,6 @@ import("//build/config/ui.gni") import("//testing/test.gni") -import("//ui/vector_icons/vector_icons.gni") - -aggregate_vector_icons("app_list_vector_icons") { - icon_directory = "vector_icons" - - icons = [ - "ic_google_black.1x.icon", - "ic_google_black.icon", - "ic_mic_black.1x.icon", - "ic_mic_black.icon", - ] -} component("app_list") { sources = [ @@ -80,12 +68,9 @@ "speech_ui_model_observer.h", ] - sources += get_target_outputs(":app_list_vector_icons") - defines = [ "APP_LIST_IMPLEMENTATION" ] deps = [ - ":app_list_vector_icons", "//base", "//base:i18n", "//base/third_party/dynamic_annotations", @@ -95,6 +80,7 @@ "//third_party/icu", "//ui/accessibility", "//ui/app_list/resources", + "//ui/app_list/vector_icons", "//ui/base", "//ui/base/ime", "//ui/compositor",
diff --git a/ui/app_list/presenter/app_list_presenter_impl.cc b/ui/app_list/presenter/app_list_presenter_impl.cc index c4ef3092..dd1c55a 100644 --- a/ui/app_list/presenter/app_list_presenter_impl.cc +++ b/ui/app_list/presenter/app_list_presenter_impl.cc
@@ -6,6 +6,7 @@ #include "base/metrics/user_metrics.h" #include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_features.h" #include "ui/app_list/app_list_switches.h" #include "ui/app_list/pagination_model.h" #include "ui/app_list/presenter/app_list_presenter_delegate_factory.h" @@ -34,7 +35,8 @@ AppListPresenterImpl::AppListPresenterImpl( std::unique_ptr<AppListPresenterDelegateFactory> factory) - : factory_(std::move(factory)) { + : factory_(std::move(factory)), + is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) { DCHECK(factory_); } @@ -268,10 +270,16 @@ if (!view_) return; + // Disable overscroll animation when the fullscreen app list feature is + // enabled. + if (is_fullscreen_app_list_enabled_) + return; + PaginationModel* pagination_model = view_->GetAppsPaginationModel(); const PaginationModel::Transition& transition = pagination_model->transition(); + if (pagination_model->is_valid_page(transition.target_page)) return;
diff --git a/ui/app_list/presenter/app_list_presenter_impl.h b/ui/app_list/presenter/app_list_presenter_impl.h index 4f1ee1b..eb0d7e7 100644 --- a/ui/app_list/presenter/app_list_presenter_impl.h +++ b/ui/app_list/presenter/app_list_presenter_impl.h
@@ -134,6 +134,9 @@ // Whether should schedule snap back animation. bool should_snap_back_ = false; + // Whether the fullscreen app list feature is enabled; + const bool is_fullscreen_app_list_enabled_; + // The app list interface pointer; used for reporting visibility changes. mojom::AppListPtr app_list_;
diff --git a/ui/app_list/vector_icons/BUILD.gn b/ui/app_list/vector_icons/BUILD.gn new file mode 100644 index 0000000..3c49259 --- /dev/null +++ b/ui/app_list/vector_icons/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2017 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. + +import("//ui/vector_icons/vector_icons.gni") + +aggregate_vector_icons("app_list_vector_icons") { + icon_directory = "." + + icons = [ + "ic_badge_instant.1x.icon", + "ic_badge_instant.icon", + "ic_badge_play.1x.icon", + "ic_badge_play.icon", + "ic_google_black.1x.icon", + "ic_google_black.icon", + "ic_mic_black.1x.icon", + "ic_mic_black.icon", + ] +} + +source_set("vector_icons") { + sources = get_target_outputs(":app_list_vector_icons") + + deps = [ + ":app_list_vector_icons", + "//skia", + ] +}
diff --git a/ui/app_list/vector_icons/ic_badge_instant.1x.icon b/ui/app_list/vector_icons/ic_badge_instant.1x.icon new file mode 100644 index 0000000..77d71b1 --- /dev/null +++ b/ui/app_list/vector_icons/ic_badge_instant.1x.icon
@@ -0,0 +1,22 @@ +// Copyright 2017 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. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 5.36f, 11, +LINE_TO, 4.73f, 11, +LINE_TO, 5.27f, 7, +LINE_TO, 3.34f, 7, +LINE_TO, 3.31f, 7, +CUBIC_TO, 3.14f, 7, 3, 6.86f, 3, 6.69f, +CUBIC_TO, 3, 6.62f, 3.07f, 6.49f, 3.07f, 6.49f, +LINE_TO, 6.62f, 1, +LINE_TO, 7.26f, 1, +LINE_TO, 6.72f, 5, +LINE_TO, 8.65f, 5, +LINE_TO, 8.69f, 5, +CUBIC_TO, 8.86f, 5, 9, 5.14f, 9, 5.31f, +CUBIC_TO, 9, 5.38f, 8.98f, 5.44f, 8.94f, 5.49f, +LINE_TO, 5.36f, 11, +CLOSE, +END
diff --git a/ui/app_list/vector_icons/ic_badge_instant.icon b/ui/app_list/vector_icons/ic_badge_instant.icon new file mode 100644 index 0000000..f88d166 --- /dev/null +++ b/ui/app_list/vector_icons/ic_badge_instant.icon
@@ -0,0 +1,22 @@ +// Copyright 2017 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 10.73f, 22, +LINE_TO, 9.47f, 22, +LINE_TO, 10.53f, 14, +LINE_TO, 6.68f, 14.01f, +LINE_TO, 6.63f, 14.01f, +CUBIC_TO, 6.28f, 14.01f, 6, 13.73f, 6, 13.39f, +CUBIC_TO, 6, 13.24f, 6.14f, 12.98f, 6.14f, 12.98f, +LINE_TO, 13.24f, 2, +LINE_TO, 14.51f, 2.01f, +LINE_TO, 13.44f, 10, +LINE_TO, 17.31f, 9.99f, +LINE_TO, 17.37f, 9.99f, +CUBIC_TO, 17.72f, 9.99f, 18, 10.27f, 18, 10.61f, +CUBIC_TO, 18.01f, 10.76f, 17.95f, 10.88f, 17.88f, 10.99f, +LINE_TO, 10.73f, 22, +CLOSE, +END
diff --git a/ui/app_list/vector_icons/ic_badge_play.1x.icon b/ui/app_list/vector_icons/ic_badge_play.1x.icon new file mode 100644 index 0000000..9fd281b --- /dev/null +++ b/ui/app_list/vector_icons/ic_badge_play.1x.icon
@@ -0,0 +1,37 @@ +// Copyright 2017 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. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 8.06f, 4.5f, +LINE_TO, 6.63f, 5.93f, +LINE_TO, 8.06f, 7.36f, +LINE_TO, 9.09f, 6.49f, +CUBIC_TO, 9.37f, 6.34f, 9.5f, 6.14f, 9.5f, 5.93f, +CUBIC_TO, 9.5f, 5.73f, 9.37f, 5.53f, 9.09f, 5.37f, +LINE_TO, 8.06f, 4.5f, +CLOSE, +MOVE_TO, 6.07f, 5.37f, +LINE_TO, 7.34f, 4.09f, +LINE_TO, 1.99f, 1.06f, +CUBIC_TO, 1.96f, 1.04f, 1.92f, 1.03f, 1.89f, 1.01f, +CUBIC_TO, 1.8f, 0.98f, 1.74f, 1.04f, 1.81f, 1.12f, +CUBIC_TO, 1.83f, 1.13f, 1.84f, 1.14f, 1.86f, 1.16f, +LINE_TO, 6.07f, 5.37f, +CLOSE, +MOVE_TO, 1.82f, 10.75f, +CUBIC_TO, 1.74f, 10.82f, 1.81f, 10.89f, 1.89f, 10.85f, +CUBIC_TO, 1.93f, 10.84f, 1.96f, 10.82f, 2, 10.8f, +LINE_TO, 7.34f, 7.77f, +LINE_TO, 6.07f, 6.5f, +CUBIC_TO, 6.07f, 6.5f, 2.47f, 10.1f, 1.86f, 10.71f, +LINE_TO, 1.82f, 10.75f, +CLOSE, +MOVE_TO, 5.5f, 5.93f, +LINE_TO, 1.19f, 1.62f, +CUBIC_TO, 1.1f, 1.53f, 1, 1.59f, 1, 1.72f, +LINE_TO, 1, 10.15f, +CUBIC_TO, 1, 10.28f, 1.1f, 10.34f, 1.19f, 10.24f, +LINE_TO, 5.5f, 5.93f, +CLOSE, +END
diff --git a/ui/app_list/vector_icons/ic_badge_play.icon b/ui/app_list/vector_icons/ic_badge_play.icon new file mode 100644 index 0000000..77e62cd41 --- /dev/null +++ b/ui/app_list/vector_icons/ic_badge_play.icon
@@ -0,0 +1,40 @@ +// Copyright 2017 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 20.18f, 10.88f, +LINE_TO, 17.12f, 9.14f, +LINE_TO, 14.26f, 12, +LINE_TO, 17.12f, 14.86f, +LINE_TO, 20.18f, 13.12f, +CUBIC_TO, 20.73f, 12.81f, 21, 12.41f, 21, 12, +CUBIC_TO, 21, 11.59f, 20.73f, 11.19f, 20.18f, 10.88f, +LINE_TO, 20.18f, 10.88f, +CLOSE, +MOVE_TO, 4.71f, 2.45f, +LINE_TO, 13.13f, 10.87f, +LINE_TO, 15.68f, 8.32f, +LINE_TO, 4.98f, 2.26f, +CUBIC_TO, 4.91f, 2.22f, 4.84f, 2.19f, 4.77f, 2.16f, +CUBIC_TO, 4.6f, 2.09f, 4.47f, 2.21f, 4.62f, 2.37f, +CUBIC_TO, 4.65f, 2.39f, 4.68f, 2.42f, 4.71f, 2.45f, +LINE_TO, 4.71f, 2.45f, +CLOSE, +MOVE_TO, 4.71f, 21.55f, +LINE_TO, 4.63f, 21.63f, +CUBIC_TO, 4.48f, 21.78f, 4.61f, 21.91f, 4.78f, 21.84f, +CUBIC_TO, 4.85f, 21.81f, 4.92f, 21.78f, 4.99f, 21.74f, +LINE_TO, 15.68f, 15.68f, +LINE_TO, 13.13f, 13.13f, +CUBIC_TO, 13.13f, 13.13f, 5.93f, 20.34f, 4.71f, 21.55f, +LINE_TO, 4.71f, 21.55f, +CLOSE, +MOVE_TO, 12, 12, +LINE_TO, 3.38f, 3.38f, +CUBIC_TO, 3.19f, 3.19f, 3, 3.31f, 3, 3.57f, +LINE_TO, 3, 20.43f, +CUBIC_TO, 3, 20.69f, 3.19f, 20.81f, 3.38f, 20.62f, +LINE_TO, 12, 12, +CLOSE, +END
diff --git a/ui/app_list/vector_icons/vector_icons.cc.template b/ui/app_list/vector_icons/vector_icons.cc.template index 7af5d5b4..9a44601 100644 --- a/ui/app_list/vector_icons/vector_icons.cc.template +++ b/ui/app_list/vector_icons/vector_icons.cc.template
@@ -5,7 +5,7 @@ // vector_icons.cc.template is used to generate vector_icons.cc. Edit the former // rather than the latter. -#include "ui/app_list/vector_icons.h" +#include "ui/app_list/vector_icons/vector_icons.h" #include "base/logging.h" #include "ui/gfx/vector_icon_types.h"
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc index 128b018..79fa7426 100644 --- a/ui/app_list/views/app_list_view.cc +++ b/ui/app_list/views/app_list_view.cc
@@ -521,7 +521,7 @@ // fling. int const new_y_position = location.y() - initial_drag_point_.y() + fullscreen_widget_->GetWindowBoundsInScreen().y(); - if (std::abs(last_fling_velocity_) > kAppListDragVelocityThreshold) { + if (std::abs(last_fling_velocity_) >= kAppListDragVelocityThreshold) { // If the user releases drag with velocity over the threshold, snap to // the next state, ignoring the drag release position. @@ -724,12 +724,13 @@ return; switch (event->type()) { + case ui::ET_SCROLL_FLING_START: case ui::ET_GESTURE_SCROLL_BEGIN: StartDrag(event->location()); event->SetHandled(); break; case ui::ET_GESTURE_SCROLL_UPDATE: - last_fling_velocity_ = event->details().velocity_y(); + last_fling_velocity_ = event->details().scroll_y(); UpdateDrag(event->location()); event->SetHandled(); break;
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc index 7841388b..bd0141c 100644 --- a/ui/app_list/views/search_box_view.cc +++ b/ui/app_list/views/search_box_view.cc
@@ -17,7 +17,7 @@ #include "ui/app_list/resources/grit/app_list_resources.h" #include "ui/app_list/search_box_model.h" #include "ui/app_list/speech_ui_model.h" -#include "ui/app_list/vector_icons.h" +#include "ui/app_list/vector_icons/vector_icons.h" #include "ui/app_list/views/app_list_view.h" #include "ui/app_list/views/contents_view.h" #include "ui/app_list/views/search_box_view_delegate.h"
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc index 70c8e26..61f27dc 100644 --- a/ui/app_list/views/search_result_tile_item_view.cc +++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -111,6 +111,10 @@ if (!old_item || !item->icon().BackedBySameObjectAs(old_item->icon())) { OnIconChanged(); } + if (!old_item || + !item->badge_icon().BackedBySameObjectAs(old_item->badge_icon())) { + OnBadgeIconChanged(); + } } void SearchResultTileItemView::SetRating(float rating) { @@ -155,10 +159,12 @@ void SearchResultTileItemView::OnIconChanged() { SetIcon(item_->icon()); + Layout(); } void SearchResultTileItemView::OnBadgeIconChanged() { SetBadgeIcon(item_->badge_icon()); + Layout(); } void SearchResultTileItemView::OnRatingChanged() {
diff --git a/ui/aura/test/mus/test_window_manager_client.cc b/ui/aura/test/mus/test_window_manager_client.cc index 9e500d73..5ca10a2a 100644 --- a/ui/aura/test/mus/test_window_manager_client.cc +++ b/ui/aura/test/mus/test_window_manager_client.cc
@@ -48,7 +48,9 @@ const std::vector<display::Display>& displays, std::vector<::ui::mojom::WmViewportMetricsPtr> viewport_metrics, int64_t primary_display_id, - const SetDisplayConfigurationCallback& callback) {} + const SetDisplayConfigurationCallback& callback) { + changes_.push_back(WindowManagerClientChangeType::SET_DISPLAY_CONFIGURATION); +} void TestWindowManagerClient::WmResponse(uint32_t change_id, bool response) {}
diff --git a/ui/aura/test/mus/test_window_manager_client.h b/ui/aura/test/mus/test_window_manager_client.h index 68d94332..31ac57fc 100644 --- a/ui/aura/test/mus/test_window_manager_client.h +++ b/ui/aura/test/mus/test_window_manager_client.h
@@ -17,6 +17,7 @@ enum class WindowManagerClientChangeType { ADD_ACTIVATION_PARENT, + SET_DISPLAY_CONFIGURATION, }; // WindowManagerClient implementation for tests.
diff --git a/ui/display/manager/display_manager.cc b/ui/display/manager/display_manager.cc index 7390e32..f8be65d0 100644 --- a/ui/display/manager/display_manager.cc +++ b/ui/display/manager/display_manager.cc
@@ -126,6 +126,15 @@ return *iter; } +bool ContainsDisplayWithId(const std::vector<Display>& displays, + int64_t display_id) { + for (auto& display : displays) { + if (display.id() == display_id) + return true; + } + return false; +} + } // namespace using std::string; @@ -906,10 +915,7 @@ } bool DisplayManager::IsActiveDisplayId(int64_t display_id) const { - return std::find_if(active_display_list_.begin(), active_display_list_.end(), - [display_id](const Display& display) { - return display.id() == display_id; - }) != active_display_list_.end(); + return ContainsDisplayWithId(active_display_list_, display_id); } bool DisplayManager::IsInMirrorMode() const { @@ -1110,7 +1116,19 @@ // Don't notify observers if the mirrored window has changed. if (software_mirroring_enabled() && mirroring_display_id_ == display_id) return false; + + // In unified mode then |active_display_list_| won't have a display for + // |display_id| but |software_mirroring_display_list_| should. Reconfigure + // the displays so the unified display size is recomputed. + if (IsInUnifiedMode() && + ContainsDisplayWithId(software_mirroring_display_list_, display_id)) { + DCHECK(!IsActiveDisplayId(display_id)); + ReconfigureDisplays(); + return true; + } + Display* display = FindDisplayForId(display_id); + DCHECK(display); display->SetSize(display_info_[display_id].size_in_pixel()); NotifyMetricsChanged(*display, DisplayObserver::DISPLAY_METRIC_BOUNDS); return true; @@ -1329,7 +1347,7 @@ // TODO(oshima): This happens when windows in unified desktop have // been moved to a normal window. Fix this. if (id != kUnifiedDisplayId) - DLOG(WARNING) << "Could not find display:" << id; + DLOG(ERROR) << "Could not find display:" << id; return nullptr; }
diff --git a/ui/display/mojo/display.mojom b/ui/display/mojo/display.mojom index 6b2cce08..708f2be 100644 --- a/ui/display/mojo/display.mojom +++ b/ui/display/mojo/display.mojom
@@ -21,6 +21,13 @@ UNAVAILABLE, }; +// Corresponds to display::Display::AccelerometerSupport. +enum AccelerometerSupport { + UNKNOWN, + AVAILABLE, + UNAVAILABLE, +}; + // Corresponds to display::Display. struct Display { int64 id; @@ -30,6 +37,7 @@ float device_scale_factor; Rotation rotation; TouchSupport touch_support; + AccelerometerSupport accelerometer_support; gfx.mojom.Size maximum_cursor_size; int32 color_depth; int32 depth_per_component;
diff --git a/ui/display/mojo/display.typemap b/ui/display/mojo/display.typemap index 69a12e7..35d8b1d 100644 --- a/ui/display/mojo/display.typemap +++ b/ui/display/mojo/display.typemap
@@ -19,4 +19,5 @@ "display.mojom.Display=display::Display", "display.mojom.DisplayRotation=display::Display::Rotation", "display.mojom.TouchSupport=display::Display::TouchSupport", + "display.mojom.AccelerometerSupport=display::Display::AccelerometerSupport", ]
diff --git a/ui/display/mojo/display_struct_traits.cc b/ui/display/mojo/display_struct_traits.cc index d7d11b8..4b61b0a 100644 --- a/ui/display/mojo/display_struct_traits.cc +++ b/ui/display/mojo/display_struct_traits.cc
@@ -77,6 +77,41 @@ return false; } +display::mojom::AccelerometerSupport +EnumTraits<display::mojom::AccelerometerSupport, + display::Display::AccelerometerSupport>:: + ToMojom(display::Display::AccelerometerSupport accelerometer_support) { + switch (accelerometer_support) { + case display::Display::ACCELEROMETER_SUPPORT_UNKNOWN: + return display::mojom::AccelerometerSupport::UNKNOWN; + case display::Display::ACCELEROMETER_SUPPORT_AVAILABLE: + return display::mojom::AccelerometerSupport::AVAILABLE; + case display::Display::ACCELEROMETER_SUPPORT_UNAVAILABLE: + return display::mojom::AccelerometerSupport::UNAVAILABLE; + } + NOTREACHED(); + return display::mojom::AccelerometerSupport::UNKNOWN; +} + +bool EnumTraits<display::mojom::AccelerometerSupport, + display::Display::AccelerometerSupport>:: + FromMojom(display::mojom::AccelerometerSupport accelerometer_support, + display::Display::AccelerometerSupport* out) { + switch (accelerometer_support) { + case display::mojom::AccelerometerSupport::UNKNOWN: + *out = display::Display::ACCELEROMETER_SUPPORT_UNKNOWN; + return true; + case display::mojom::AccelerometerSupport::AVAILABLE: + *out = display::Display::ACCELEROMETER_SUPPORT_AVAILABLE; + return true; + case display::mojom::AccelerometerSupport::UNAVAILABLE: + *out = display::Display::ACCELEROMETER_SUPPORT_UNAVAILABLE; + return true; + } + NOTREACHED(); + return false; +} + bool StructTraits<display::mojom::DisplayDataView, display::Display>::Read( display::mojom::DisplayDataView data, display::Display* out) { @@ -99,6 +134,9 @@ if (!data.ReadTouchSupport(&out->touch_support_)) return false; + if (!data.ReadAccelerometerSupport(&out->accelerometer_support_)) + return false; + if (!data.ReadMaximumCursorSize(&out->maximum_cursor_size_)) return false;
diff --git a/ui/display/mojo/display_struct_traits.h b/ui/display/mojo/display_struct_traits.h index 00009ed..3e951e9c 100644 --- a/ui/display/mojo/display_struct_traits.h +++ b/ui/display/mojo/display_struct_traits.h
@@ -28,6 +28,15 @@ }; template <> +struct EnumTraits<display::mojom::AccelerometerSupport, + display::Display::AccelerometerSupport> { + static display::mojom::AccelerometerSupport ToMojom( + display::Display::AccelerometerSupport type); + static bool FromMojom(display::mojom::AccelerometerSupport type, + display::Display::AccelerometerSupport* output); +}; + +template <> struct StructTraits<display::mojom::DisplayDataView, display::Display> { static int64_t id(const display::Display& display) { return display.id(); } @@ -56,6 +65,11 @@ return display.touch_support(); } + static display::Display::AccelerometerSupport accelerometer_support( + const display::Display& display) { + return display.accelerometer_support(); + } + static const gfx::Size& maximum_cursor_size(const display::Display& display) { return display.maximum_cursor_size(); }
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc index 9e2ed40..42ae8278 100644 --- a/ui/display/mojo/display_struct_traits_unittest.cc +++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -3,6 +3,9 @@ // found in the LICENSE file. #include <memory> +#include <string> +#include <utility> +#include <vector> #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,6 +39,7 @@ EXPECT_EQ(input.device_scale_factor(), output.device_scale_factor()); EXPECT_EQ(input.rotation(), output.rotation()); EXPECT_EQ(input.touch_support(), output.touch_support()); + EXPECT_EQ(input.accelerometer_support(), output.accelerometer_support()); EXPECT_EQ(input.maximum_cursor_size(), output.maximum_cursor_size()); EXPECT_EQ(input.color_depth(), output.color_depth()); EXPECT_EQ(input.depth_per_component(), output.depth_per_component()); @@ -51,10 +55,17 @@ EXPECT_EQ(input.primary_id, output.primary_id); } -bool CompareModes(const DisplayMode& lhs, const DisplayMode& rhs) { - return lhs.size() == rhs.size() && - lhs.is_interlaced() == rhs.is_interlaced() && - lhs.refresh_rate() == rhs.refresh_rate(); +void CheckDisplayModesEqual(const DisplayMode* input, + const DisplayMode* output) { + // DisplaySnapshot can have null DisplayModes, so if |input| is null then + // |output| should be null too. + if (input == nullptr && output == nullptr) + return; + + EXPECT_NE(input, output); // Make sure they aren't the same object. + EXPECT_EQ(input->size(), output->size()); + EXPECT_EQ(input->is_interlaced(), output->is_interlaced()); + EXPECT_EQ(input->refresh_rate(), output->refresh_rate()); } void CheckDisplaySnapShotMojoEqual(const DisplaySnapshotMojo& input, @@ -77,19 +88,12 @@ EXPECT_EQ(input.modes().size(), output.modes().size()); for (size_t i = 0; i < input.modes().size(); i++) - EXPECT_TRUE(CompareModes(*input.modes()[i], *output.modes()[i])); + CheckDisplayModesEqual(input.modes()[i].get(), output.modes()[i].get()); EXPECT_EQ(input.edid(), output.edid()); - if (!input.current_mode()) - EXPECT_EQ(nullptr, output.current_mode()); - else - EXPECT_TRUE(CompareModes(*input.current_mode(), *output.current_mode())); - - if (!input.native_mode()) - EXPECT_EQ(nullptr, output.native_mode()); - else - EXPECT_TRUE(CompareModes(*input.native_mode(), *output.native_mode())); + CheckDisplayModesEqual(input.current_mode(), output.current_mode()); + CheckDisplayModesEqual(input.native_mode(), output.native_mode()); EXPECT_EQ(input.maximum_cursor_size(), output.maximum_cursor_size()); } @@ -128,6 +132,7 @@ input.set_device_scale_factor(2.0f); input.set_rotation(Display::ROTATE_270); input.set_touch_support(Display::TOUCH_SUPPORT_AVAILABLE); + input.set_accelerometer_support(Display::ACCELEROMETER_SUPPORT_UNAVAILABLE); input.set_maximum_cursor_size(maximum_cursor_size); input.set_color_depth(input.color_depth() + 1); input.set_depth_per_component(input.depth_per_component() + 1); @@ -146,11 +151,7 @@ std::unique_ptr<DisplayMode> output; SerializeAndDeserialize<mojom::DisplayMode>(input->Clone(), &output); - // We want to test each component individually to make sure each data member - // was correctly serialized and deserialized. - EXPECT_EQ(input->size(), output->size()); - EXPECT_EQ(input->is_interlaced(), output->is_interlaced()); - EXPECT_EQ(input->refresh_rate(), output->refresh_rate()); + CheckDisplayModesEqual(input.get(), output.get()); } TEST(DisplayStructTraitsTest, DisplayPlacementFlushAtTop) { @@ -267,8 +268,7 @@ const gfx::Point origin(1, 2); const gfx::Size physical_size(5, 9); const gfx::Size maximum_cursor_size(3, 5); - const DisplayConnectionType type = - display::DISPLAY_CONNECTION_TYPE_DISPLAYPORT; + const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_DISPLAYPORT; const bool is_aspect_preserving_scaling = true; const bool has_overscan = true; const bool has_color_correction_matrix = true; @@ -278,7 +278,7 @@ const DisplayMode display_mode(gfx::Size(13, 11), true, 40.0f); - display::DisplaySnapshot::DisplayModeList modes; + DisplaySnapshot::DisplayModeList modes; modes.push_back(display_mode.Clone()); const DisplayMode* current_mode = nullptr; @@ -306,7 +306,7 @@ const gfx::Point origin(11, 32); const gfx::Size physical_size(55, 49); const gfx::Size maximum_cursor_size(13, 95); - const DisplayConnectionType type = display::DISPLAY_CONNECTION_TYPE_VGA; + const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_VGA; const bool is_aspect_preserving_scaling = true; const bool has_overscan = true; const bool has_color_correction_matrix = true; @@ -316,7 +316,7 @@ const DisplayMode display_mode(gfx::Size(13, 11), true, 50.0f); - display::DisplaySnapshot::DisplayModeList modes; + DisplaySnapshot::DisplayModeList modes; modes.push_back(display_mode.Clone()); const DisplayMode* current_mode = nullptr; @@ -344,7 +344,7 @@ const gfx::Point origin(0, 1760); const gfx::Size physical_size(520, 320); const gfx::Size maximum_cursor_size(4, 5); - const DisplayConnectionType type = display::DISPLAY_CONNECTION_TYPE_HDMI; + const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_HDMI; const bool is_aspect_preserving_scaling = false; const bool has_overscan = false; const bool has_color_correction_matrix = false; @@ -356,7 +356,7 @@ const DisplayMode display_current_mode(gfx::Size(1440, 900), false, 59.89f); const DisplayMode display_native_mode(gfx::Size(1920, 1200), false, 59.89f); - display::DisplaySnapshot::DisplayModeList modes; + DisplaySnapshot::DisplayModeList modes; modes.push_back(display_mode.Clone()); modes.push_back(display_current_mode.Clone()); modes.push_back(display_native_mode.Clone()); @@ -385,7 +385,7 @@ const gfx::Point origin(0, 0); const gfx::Size physical_size(270, 180); const gfx::Size maximum_cursor_size(64, 64); - const DisplayConnectionType type = display::DISPLAY_CONNECTION_TYPE_INTERNAL; + const DisplayConnectionType type = DISPLAY_CONNECTION_TYPE_INTERNAL; const bool is_aspect_preserving_scaling = true; const bool has_overscan = false; const bool has_color_correction_matrix = false; @@ -395,7 +395,7 @@ const DisplayMode display_mode(gfx::Size(2560, 1700), false, 95.96f); - display::DisplaySnapshot::DisplayModeList modes; + DisplaySnapshot::DisplayModeList modes; modes.push_back(display_mode.Clone()); const DisplayMode* current_mode = modes[0].get();
diff --git a/ui/events/blink/blink_event_util.cc b/ui/events/blink/blink_event_util.cc index ad6e31ae7..2225d933 100644 --- a/ui/events/blink/blink_event_util.cc +++ b/ui/events/blink/blink_event_util.cc
@@ -283,6 +283,7 @@ float old_wheelTicksY = event->wheel_ticks_y; float old_movementX = event->movement_x; float old_movementY = event->movement_y; + WebInputEvent::DispatchType old_dispatch_type = event->dispatch_type; *event = event_to_coalesce; event->delta_x += old_deltaX; event->delta_y += old_deltaY; @@ -294,6 +295,8 @@ GetAccelerationRatio(event->delta_x, unaccelerated_x); event->acceleration_ratio_y = GetAccelerationRatio(event->delta_y, unaccelerated_y); + event->dispatch_type = + MergeDispatchTypes(old_dispatch_type, event_to_coalesce.dispatch_type); } bool CanCoalesce(const WebTouchEvent& event_to_coalesce,
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index 0f26dd9..f1ce986 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -678,6 +678,24 @@ CancelCurrentFling(); InputHandlerProxy::EventDisposition result = DROP_EVENT; + + if (wheel_event.dispatch_type == WebInputEvent::kEventNonBlocking) { + // The first wheel event in the sequence should be cancellable. + DCHECK(wheel_event.phase != WebMouseWheelEvent::kPhaseBegan); + + DCHECK(mouse_wheel_result_ != kEventDispositionUndefined); + result = static_cast<EventDisposition>(mouse_wheel_result_); + + if (wheel_event.phase == WebMouseWheelEvent::kPhaseEnded || + wheel_event.phase == WebMouseWheelEvent::kPhaseCancelled || + wheel_event.momentum_phase == WebMouseWheelEvent::kPhaseEnded || + wheel_event.momentum_phase == WebMouseWheelEvent::kPhaseCancelled) { + mouse_wheel_result_ = kEventDispositionUndefined; + } + if (mouse_wheel_result_ != kEventDispositionUndefined) + return result; + } + cc::EventListenerProperties properties = input_handler_->GetEventListenerProperties( cc::EventListenerClass::kMouseWheel);
diff --git a/ui/shell_dialogs/DEPS b/ui/shell_dialogs/DEPS index 629645a..41751b8 100644 --- a/ui/shell_dialogs/DEPS +++ b/ui/shell_dialogs/DEPS
@@ -5,5 +5,4 @@ "+ui/base", "+ui/gfx", "+ui/strings/grit/ui_strings.h", - "+win8/viewer", ]
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp index 3579eca..1f97fedd 100644 --- a/ui/webui/resources/polymer_resources.grdp +++ b/ui/webui/resources/polymer_resources.grdp
@@ -278,21 +278,6 @@ <structure name="IDR_POLYMER_1_0_IRON_SELECTOR_IRON_SELECTOR_HTML" file="../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-selector.html" type="chrome_html" /> - <structure name="IDR_POLYMER_1_0_IRON_TEST_HELPERS_IRON_TEST_HELPERS_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/iron-test-helpers/iron-test-helpers.html" - type="chrome_html" /> - <structure name="IDR_POLYMER_1_0_IRON_TEST_HELPERS_MOCK_INTERACTIONS_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.html" - type="chrome_html" /> - <structure name="IDR_POLYMER_1_0_IRON_TEST_HELPERS_MOCK_INTERACTIONS_JS" - file="../../../third_party/polymer/v1_0/components-chromium/iron-test-helpers/mock-interactions.js" - type="chrome_html" /> - <structure name="IDR_POLYMER_1_0_IRON_TEST_HELPERS_TEST_HELPERS_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.html" - type="chrome_html" /> - <structure name="IDR_POLYMER_1_0_IRON_TEST_HELPERS_TEST_HELPERS_JS" - file="../../../third_party/polymer/v1_0/components-chromium/iron-test-helpers/test-helpers.js" - type="chrome_html" /> <structure name="IDR_POLYMER_1_0_IRON_VALIDATABLE_BEHAVIOR_IRON_VALIDATABLE_BEHAVIOR_EXTRACTED_JS" file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js" type="chrome_html" />